#Requires -RunAsAdministrator [CmdletBinding()] param( [switch]$SkipBloatware, [switch]$SkipSoftware, [switch]$SkipDefaultProfile, [switch]$DryRun, [ValidateSet("default","admin","user")] [string]$ProfileType = "default" ) $ErrorActionPreference = "Continue" # ----------------------------------------------------------------------- # Paths # ----------------------------------------------------------------------- $ScriptRoot = $PSScriptRoot $LogDir = "C:\Windows\Setup\Scripts" $LogFile = "$LogDir\Deploy.log" $ConfigFile = "$ScriptRoot\config\config.json" # ----------------------------------------------------------------------- # Logging # ----------------------------------------------------------------------- function Write-Log { param( [string]$Message, [ValidateSet("INFO","OK","ERROR","WARN","STEP")] [string]$Level = "INFO" ) $timestamp = Get-Date -Format "HH:mm:ss" $line = "[$timestamp] [$Level] $Message" Add-Content -Path $LogFile -Value $line -Encoding UTF8 switch ($Level) { "OK" { Write-Host $line -ForegroundColor Green } "ERROR" { Write-Host $line -ForegroundColor Red } "WARN" { Write-Host $line -ForegroundColor Yellow } "STEP" { Write-Host $line -ForegroundColor Cyan } default { Write-Host $line } } } # ----------------------------------------------------------------------- # Step runner - catches errors, logs, always continues # ----------------------------------------------------------------------- $StepResults = [System.Collections.Generic.List[hashtable]]::new() function Invoke-Step { param( [string]$Name, [scriptblock]$Action ) Write-Log "---- $Name ----" -Level STEP if ($DryRun) { Write-Log "DryRun - skipping execution" -Level WARN $StepResults.Add(@{ Name = $Name; Status = "DRYRUN" }) return } try { & $Action Write-Log "$Name - OK" -Level OK $StepResults.Add(@{ Name = $Name; Status = "OK" }) } catch { Write-Log "$Name - ERROR: $_" -Level ERROR $StepResults.Add(@{ Name = $Name; Status = "ERROR" }) } } # ----------------------------------------------------------------------- # Init # ----------------------------------------------------------------------- if (-not (Test-Path $LogDir)) { New-Item -ItemType Directory -Path $LogDir -Force | Out-Null } Write-Log "========================================" -Level INFO Write-Log "Deploy-Windows.ps1 started" -Level INFO Write-Log "Computer: $env:COMPUTERNAME" -Level INFO Write-Log "User: $env:USERNAME" -Level INFO Write-Log "Date: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -Level INFO if ($DryRun) { Write-Log "Mode: DRY RUN" -Level WARN } Write-Log "========================================" -Level INFO # ----------------------------------------------------------------------- # Load config # ----------------------------------------------------------------------- $Config = $null Invoke-Step -Name "Load config.json" -Action { if (-not (Test-Path $ConfigFile)) { throw "config.json not found: $ConfigFile" } $script:Config = Get-Content $ConfigFile -Raw -Encoding UTF8 | ConvertFrom-Json Write-Log "Config loaded from $ConfigFile" -Level INFO } # ----------------------------------------------------------------------- # Build step enable/disable map from config + CLI overrides # ----------------------------------------------------------------------- $stepsEnabled = @{ adminAccount = $true bloatware = $true software = $true systemRegistry = $true defaultProfile = $true personalization = $true scheduledTasks = $true backinfo = $true network = $true pcIdentity = $true activation = $true } if ($Config -and $Config.steps) { foreach ($key in @($stepsEnabled.Keys)) { $val = $Config.steps.$key if ($null -ne $val) { $stepsEnabled[$key] = [bool]$val } } } # CLI switches override config.steps if ($SkipBloatware) { $stepsEnabled['bloatware'] = $false } if ($SkipSoftware) { $stepsEnabled['software'] = $false } if ($SkipDefaultProfile) { $stepsEnabled['defaultProfile'] = $false } function Skip-Step { param([string]$Name) Write-Log "$Name - SKIPPED (disabled in config)" -Level WARN $StepResults.Add(@{ Name = $Name; Status = "SKIPPED" }) } # ----------------------------------------------------------------------- # Step 0a - Admin account # ----------------------------------------------------------------------- if ($stepsEnabled['adminAccount']) { Invoke-Step -Name "Step 0a - Admin account" -Action { & "$ScriptRoot\scripts\00-admin-account.ps1" -Config $Config -LogFile $LogFile } } else { Skip-Step "Step 0a - Admin account" } # ----------------------------------------------------------------------- # Step 0b - Windows activation # ----------------------------------------------------------------------- if ($stepsEnabled['activation']) { Invoke-Step -Name "Step 0b - Windows activation" -Action { & "$ScriptRoot\scripts\08-activation.ps1" -Config $Config -LogFile $LogFile } } else { Skip-Step "Step 0b - Windows activation" } # ----------------------------------------------------------------------- # Step 1 - Bloatware removal # ----------------------------------------------------------------------- if ($stepsEnabled['bloatware']) { Invoke-Step -Name "Step 1 - Bloatware removal" -Action { & "$ScriptRoot\scripts\01-bloatware.ps1" -Config $Config -LogFile $LogFile } } else { Skip-Step "Step 1 - Bloatware removal" } # ----------------------------------------------------------------------- # Step 2 - Software installation # ----------------------------------------------------------------------- if ($stepsEnabled['software']) { Invoke-Step -Name "Step 2 - Software installation" -Action { & "$ScriptRoot\scripts\02-software.ps1" -Config $Config -LogFile $LogFile } } else { Skip-Step "Step 2 - Software installation" } # ----------------------------------------------------------------------- # Step 3 - System registry (HKLM) # ----------------------------------------------------------------------- if ($stepsEnabled['systemRegistry']) { Invoke-Step -Name "Step 3 - System registry" -Action { & "$ScriptRoot\scripts\03-system-registry.ps1" -Config $Config -LogFile $LogFile } } else { Skip-Step "Step 3 - System registry" } # ----------------------------------------------------------------------- # Step 4 - Default profile (NTUSER.DAT) # ----------------------------------------------------------------------- if ($stepsEnabled['defaultProfile']) { Invoke-Step -Name "Step 4 - Default profile" -Action { & "$ScriptRoot\scripts\04-default-profile.ps1" -Config $Config -LogFile $LogFile -ProfileType $ProfileType } } else { Skip-Step "Step 4 - Default profile" } # ----------------------------------------------------------------------- # Step 5 - Personalization # ----------------------------------------------------------------------- if ($stepsEnabled['personalization']) { Invoke-Step -Name "Step 5 - Personalization" -Action { & "$ScriptRoot\scripts\05-personalization.ps1" -Config $Config -LogFile $LogFile } } else { Skip-Step "Step 5 - Personalization" } # ----------------------------------------------------------------------- # Step 6 - Scheduled tasks # ----------------------------------------------------------------------- if ($stepsEnabled['scheduledTasks']) { Invoke-Step -Name "Step 6 - Scheduled tasks" -Action { & "$ScriptRoot\scripts\06-scheduled-tasks.ps1" -Config $Config -LogFile $LogFile } } else { Skip-Step "Step 6 - Scheduled tasks" } # ----------------------------------------------------------------------- # Step 7 - BackInfo # ----------------------------------------------------------------------- if ($stepsEnabled['backinfo']) { Invoke-Step -Name "Step 7 - BackInfo" -Action { & "$ScriptRoot\scripts\07-backinfo.ps1" -Config $Config -LogFile $LogFile } } else { Skip-Step "Step 7 - BackInfo" } # ----------------------------------------------------------------------- # Step 9 - Network # ----------------------------------------------------------------------- if ($stepsEnabled['network']) { Invoke-Step -Name "Step 9 - Network" -Action { & "$ScriptRoot\scripts\10-network.ps1" -Config $Config -LogFile $LogFile } } else { Skip-Step "Step 9 - Network" } # ----------------------------------------------------------------------- # Step 10 - PC identity (rename + C:\X9) - runs last, rename needs restart # ----------------------------------------------------------------------- if ($stepsEnabled['pcIdentity']) { Invoke-Step -Name "Step 10 - PC identity" -Action { & "$ScriptRoot\scripts\09-pc-identity.ps1" -Config $Config -LogFile $LogFile } } else { Skip-Step "Step 10 - PC identity" } # ----------------------------------------------------------------------- # Summary # ----------------------------------------------------------------------- Write-Log "========================================" -Level INFO Write-Log "SUMMARY" -Level INFO Write-Log "========================================" -Level INFO $countOK = ($StepResults | Where-Object { $_.Status -eq "OK" }).Count $countError = ($StepResults | Where-Object { $_.Status -eq "ERROR" }).Count $countSkipped = ($StepResults | Where-Object { $_.Status -eq "SKIPPED" }).Count $countDryRun = ($StepResults | Where-Object { $_.Status -eq "DRYRUN" }).Count foreach ($r in $StepResults) { $lvl = switch ($r.Status) { "OK" { "OK" } "ERROR" { "ERROR" } "SKIPPED" { "WARN" } "DRYRUN" { "WARN" } } Write-Log "$($r.Status.PadRight(8)) $($r.Name)" -Level $lvl } Write-Log "----------------------------------------" -Level INFO Write-Log "OK: $countOK ERROR: $countError SKIPPED: $countSkipped DRYRUN: $countDryRun" -Level INFO Write-Log "Log saved to: $LogFile" -Level INFO Write-Log "========================================" -Level INFO if ($countError -gt 0) { Write-Log "Deployment finished with errors. Review log: $LogFile" -Level ERROR exit 1 } else { Write-Log "Deployment finished successfully." -Level OK exit 0 }