245 lines
9.2 KiB
PowerShell
245 lines
9.2 KiB
PowerShell
|
|
#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
|
||
|
|
}
|
||
|
|
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
# Build step enable/disable map from config + CLI overrides
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
$stepsEnabled = @{
|
||
|
|
adminAccount = $true
|
||
|
|
bloatware = $true
|
||
|
|
software = $true
|
||
|
|
systemRegistry = $true
|
||
|
|
defaultProfile = $true
|
||
|
|
personalization = $true
|
||
|
|
scheduledTasks = $true
|
||
|
|
desktopInfo = $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
|
||
|
|
}
|
||
|
|
} 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 - DesktopInfo
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
if ($stepsEnabled['desktopInfo']) {
|
||
|
|
Invoke-Step -Name "Step 7 - DesktopInfo" -Action {
|
||
|
|
& "$ScriptRoot\scripts\07-desktop-info.ps1" -Config $Config -LogFile $LogFile
|
||
|
|
}
|
||
|
|
} else { Skip-Step "Step 7 - DesktopInfo" }
|
||
|
|
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
# 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
|
||
|
|
}
|