#Requires -RunAsAdministrator [CmdletBinding()] param( [switch]$SkipBloatware, [switch]$SkipSoftware, [switch]$SkipDefaultProfile, [switch]$DryRun ) $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 } # ----------------------------------------------------------------------- # Step 0a - Admin account # ----------------------------------------------------------------------- Invoke-Step -Name "Step 0a - Admin account" -Action { & "$ScriptRoot\scripts\00-admin-account.ps1" -Config $Config -LogFile $LogFile } # ----------------------------------------------------------------------- # Step 0b - Windows activation # ----------------------------------------------------------------------- Invoke-Step -Name "Step 0b - Windows activation" -Action { & "$ScriptRoot\scripts\08-activation.ps1" -Config $Config -LogFile $LogFile } # ----------------------------------------------------------------------- # Step 1 - Bloatware removal # ----------------------------------------------------------------------- if ($SkipBloatware) { Write-Log "Step 1 - Bloatware removal: SKIPPED (-SkipBloatware)" -Level WARN $StepResults.Add(@{ Name = "Step 1 - Bloatware removal"; Status = "SKIPPED" }) } else { Invoke-Step -Name "Step 1 - Bloatware removal" -Action { & "$ScriptRoot\scripts\01-bloatware.ps1" -Config $Config -LogFile $LogFile } } # ----------------------------------------------------------------------- # Step 2 - Software installation # ----------------------------------------------------------------------- if ($SkipSoftware) { Write-Log "Step 2 - Software installation: SKIPPED (-SkipSoftware)" -Level WARN $StepResults.Add(@{ Name = "Step 2 - Software installation"; Status = "SKIPPED" }) } else { Invoke-Step -Name "Step 2 - Software installation" -Action { & "$ScriptRoot\scripts\02-software.ps1" -Config $Config -LogFile $LogFile } } # ----------------------------------------------------------------------- # Step 3 - System registry (HKLM) # ----------------------------------------------------------------------- Invoke-Step -Name "Step 3 - System registry" -Action { & "$ScriptRoot\scripts\03-system-registry.ps1" -Config $Config -LogFile $LogFile } # ----------------------------------------------------------------------- # Step 4 - Default profile (NTUSER.DAT) # ----------------------------------------------------------------------- if ($SkipDefaultProfile) { Write-Log "Step 4 - Default profile: SKIPPED (-SkipDefaultProfile)" -Level WARN $StepResults.Add(@{ Name = "Step 4 - Default profile"; Status = "SKIPPED" }) } else { Invoke-Step -Name "Step 4 - Default profile" -Action { & "$ScriptRoot\scripts\04-default-profile.ps1" -Config $Config -LogFile $LogFile } } # ----------------------------------------------------------------------- # Step 5 - Personalization # ----------------------------------------------------------------------- Invoke-Step -Name "Step 5 - Personalization" -Action { & "$ScriptRoot\scripts\05-personalization.ps1" -Config $Config -LogFile $LogFile } # ----------------------------------------------------------------------- # Step 6 - Scheduled tasks # ----------------------------------------------------------------------- Invoke-Step -Name "Step 6 - Scheduled tasks" -Action { & "$ScriptRoot\scripts\06-scheduled-tasks.ps1" -Config $Config -LogFile $LogFile } # ----------------------------------------------------------------------- # Step 7 - DesktopInfo # ----------------------------------------------------------------------- Invoke-Step -Name "Step 7 - DesktopInfo" -Action { & "$ScriptRoot\scripts\07-desktop-info.ps1" -Config $Config -LogFile $LogFile } # ----------------------------------------------------------------------- # 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 }