- config-editor.hta: lightweight WYSIWYG HTA editor for config.json - Step on/off toggles with info tooltips - Editable software list (winget packages) - Settings: timezone, admin account, desktopInfo, PDF default - Run.cmd: USB launcher with UAC auto-elevation and deployment menu - flash/: minimal USB-ready subset (Deploy, scripts, config, GUI, launcher) - config.json: add steps section for per-step enable/disable - Deploy-Windows.ps1: read steps from config, CLI switches override - 03-system-registry.ps1: add SearchOnTaskbarMode HKLM policy (Win11 search fix) - 04-default-profile.ps1: fix systray - clear TrayNotify cache + proper Explorer restart - 06-scheduled-tasks.ps1: fix Register-Task trigger array, ShowAllTrayIcons Win11 fix, PDF-DefaultApp runs as SYSTEM via HKCR (bypasses UserChoice Hash validation) - 02-software.ps1: remove unreliable UserChoice ProgId write without Hash Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
194 lines
8.5 KiB
PowerShell
194 lines
8.5 KiB
PowerShell
param(
|
|
[object]$Config,
|
|
[string]$LogFile
|
|
)
|
|
|
|
$ErrorActionPreference = "Continue"
|
|
|
|
function Write-Log {
|
|
param([string]$Message, [string]$Level = "INFO")
|
|
$line = "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message"
|
|
Add-Content -Path $LogFile -Value $line -Encoding UTF8
|
|
}
|
|
|
|
$ScriptDir = "C:\Windows\Setup\Scripts"
|
|
if (-not (Test-Path $ScriptDir)) {
|
|
New-Item -ItemType Directory -Path $ScriptDir -Force | Out-Null
|
|
}
|
|
|
|
function Register-Task {
|
|
param(
|
|
[string]$TaskName,
|
|
[string]$Description,
|
|
[object]$Action,
|
|
[object[]]$Triggers,
|
|
[string]$RunLevel = "Highest"
|
|
)
|
|
try {
|
|
# Remove existing task with same name
|
|
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue
|
|
|
|
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Minutes 5) `
|
|
-MultipleInstances IgnoreNew `
|
|
-StartWhenAvailable
|
|
|
|
$principal = New-ScheduledTaskPrincipal -GroupId "Users" `
|
|
-RunLevel $RunLevel
|
|
|
|
$task = New-ScheduledTask -Action $Action `
|
|
-Trigger $Triggers `
|
|
-Settings $settings `
|
|
-Principal $principal `
|
|
-Description $Description
|
|
|
|
Register-ScheduledTask -TaskName $TaskName -InputObject $task -Force | Out-Null
|
|
Write-Log " Registered task: $TaskName" -Level OK
|
|
}
|
|
catch {
|
|
Write-Log " Failed to register task $TaskName - $_" -Level ERROR
|
|
}
|
|
}
|
|
|
|
# -----------------------------------------------------------------------
|
|
# Task: ShowAllTrayIcons
|
|
# Runs on logon: clears TrayNotify icon cache and restarts Explorer so all
|
|
# tray icons are visible on first login (Win10: EnableAutoTray=0, Win11: cache clear)
|
|
# -----------------------------------------------------------------------
|
|
Write-Log "Registering task: ShowAllTrayIcons" -Level STEP
|
|
|
|
$showTrayScript = "$ScriptDir\ShowAllTrayIcons.ps1"
|
|
@'
|
|
# Win10: disable auto-hiding of tray icons
|
|
$regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer"
|
|
Set-ItemProperty -Path $regPath -Name "EnableAutoTray" -Value 0 -Force -ErrorAction SilentlyContinue
|
|
|
|
# Win11: clear icon stream cache so all icons become visible after Explorer restart
|
|
$trayPath = "HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
|
|
if (Test-Path $trayPath) {
|
|
Remove-ItemProperty -Path $trayPath -Name "IconStreams" -Force -ErrorAction SilentlyContinue
|
|
Remove-ItemProperty -Path $trayPath -Name "PastIconsStream" -Force -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
# Restart Explorer to apply changes
|
|
Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue
|
|
Start-Sleep -Milliseconds 1500
|
|
if (-not (Get-Process explorer -ErrorAction SilentlyContinue)) {
|
|
Start-Process explorer
|
|
}
|
|
'@ | Set-Content -Path $showTrayScript -Encoding UTF8 -Force
|
|
|
|
$showTrayAction = New-ScheduledTaskAction -Execute "powershell.exe" `
|
|
-Argument "-NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$showTrayScript`""
|
|
$showTrayTrigger = New-ScheduledTaskTrigger -AtLogOn
|
|
|
|
Register-Task -TaskName "ShowAllTrayIcons" `
|
|
-Description "Show all system tray icons for current user" `
|
|
-Action $showTrayAction `
|
|
-Triggers $showTrayTrigger
|
|
|
|
# -----------------------------------------------------------------------
|
|
# Task: PDF-DefaultApp
|
|
# Runs on every logon, restores .pdf -> Adobe Reader association
|
|
# Guards against Edge overwriting it
|
|
# -----------------------------------------------------------------------
|
|
Write-Log "Registering task: PDF-DefaultApp" -Level STEP
|
|
|
|
$pdfScript = "$ScriptDir\PDF-DefaultApp.ps1"
|
|
@'
|
|
# Restore .pdf -> Adobe Reader HKCR association (system-wide).
|
|
# Runs as SYSTEM so it can write to HKCR regardless of Edge updates.
|
|
# Note: HKCU UserChoice requires Windows Hash validation and cannot be
|
|
# set reliably via registry; HKCR provides the system-wide fallback.
|
|
$acroPaths = @(
|
|
"$env:ProgramFiles\Adobe\Acrobat DC\Acrobat\Acrobat.exe"
|
|
"${env:ProgramFiles(x86)}\Adobe\Acrobat DC\Acrobat\Acrobat.exe"
|
|
"${env:ProgramFiles(x86)}\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe"
|
|
"$env:ProgramFiles\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe"
|
|
"${env:ProgramFiles(x86)}\Adobe\Reader\Reader\AcroRd32.exe"
|
|
)
|
|
$acroExe = $acroPaths | Where-Object { Test-Path $_ } | Select-Object -First 1
|
|
if (-not $acroExe) { exit 0 }
|
|
|
|
$progId = "AcroExch.Document.DC"
|
|
$openCmd = "`"$acroExe`" `"%1`""
|
|
|
|
# HKCR\.pdf
|
|
if (-not (Test-Path "HKCR:\.pdf")) { New-Item -Path "HKCR:\.pdf" -Force | Out-Null }
|
|
$current = (Get-ItemProperty -Path "HKCR:\.pdf" -Name "(Default)" -ErrorAction SilentlyContinue)."(Default)"
|
|
if ($current -ne $progId) {
|
|
Set-ItemProperty -Path "HKCR:\.pdf" -Name "(Default)" -Value $progId -Force
|
|
}
|
|
|
|
# HKCR\AcroExch.Document.DC\shell\open\command
|
|
$cmdPath = "HKCR:\$progId\shell\open\command"
|
|
if (-not (Test-Path $cmdPath)) { New-Item -Path $cmdPath -Force | Out-Null }
|
|
Set-ItemProperty -Path $cmdPath -Name "(Default)" -Value $openCmd -Force
|
|
'@ | Set-Content -Path $pdfScript -Encoding UTF8 -Force
|
|
|
|
$pdfAction = New-ScheduledTaskAction -Execute "powershell.exe" `
|
|
-Argument "-NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$pdfScript`""
|
|
$pdfTrigger = New-ScheduledTaskTrigger -AtLogOn
|
|
|
|
# Runs as SYSTEM to allow HKCR writes (system-wide file association)
|
|
$pdfPrincipal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
|
|
$pdfSettings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Minutes 2) `
|
|
-MultipleInstances IgnoreNew `
|
|
-StartWhenAvailable
|
|
$pdfTask = New-ScheduledTask -Action $pdfAction `
|
|
-Trigger $pdfTrigger `
|
|
-Settings $pdfSettings `
|
|
-Principal $pdfPrincipal `
|
|
-Description "Restore Adobe Reader as default PDF app on logon"
|
|
try {
|
|
Unregister-ScheduledTask -TaskName "PDF-DefaultApp" -Confirm:$false -ErrorAction SilentlyContinue
|
|
Register-ScheduledTask -TaskName "PDF-DefaultApp" -InputObject $pdfTask -Force | Out-Null
|
|
Write-Log " Registered task: PDF-DefaultApp" -Level OK
|
|
}
|
|
catch {
|
|
Write-Log " Failed to register task PDF-DefaultApp - $_" -Level ERROR
|
|
}
|
|
|
|
# -----------------------------------------------------------------------
|
|
# Task: UnlockStartLayout
|
|
# Runs once after deployment to unlock the Start menu layout
|
|
# so users can still customize it later
|
|
# -----------------------------------------------------------------------
|
|
Write-Log "Registering task: UnlockStartLayout" -Level STEP
|
|
|
|
$unlockScript = "$ScriptDir\UnlockStartLayout.ps1"
|
|
@'
|
|
# Remove Start layout lock so users can modify it
|
|
$layoutXml = "C:\Users\Default\AppData\Local\Microsoft\Windows\Shell\LayoutModification.xml"
|
|
if (Test-Path $layoutXml) {
|
|
Remove-Item $layoutXml -Force -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
# Unregister self after running once
|
|
Unregister-ScheduledTask -TaskName "UnlockStartLayout" -Confirm:$false -ErrorAction SilentlyContinue
|
|
'@ | Set-Content -Path $unlockScript -Encoding UTF8 -Force
|
|
|
|
$unlockAction = New-ScheduledTaskAction -Execute "powershell.exe" `
|
|
-Argument "-NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$unlockScript`""
|
|
# Trigger: 5 minutes after system startup, once
|
|
$unlockTrigger = New-ScheduledTaskTrigger -AtStartup
|
|
$unlockTrigger.Delay = "PT5M"
|
|
|
|
$unlockPrincipal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
|
|
$unlockSettings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Minutes 10) `
|
|
-StartWhenAvailable
|
|
$unlockTask = New-ScheduledTask -Action $unlockAction `
|
|
-Trigger $unlockTrigger `
|
|
-Settings $unlockSettings `
|
|
-Principal $unlockPrincipal `
|
|
-Description "Unlock Start menu layout 5 min after first boot"
|
|
|
|
try {
|
|
Unregister-ScheduledTask -TaskName "UnlockStartLayout" -Confirm:$false -ErrorAction SilentlyContinue
|
|
Register-ScheduledTask -TaskName "UnlockStartLayout" -InputObject $unlockTask -Force | Out-Null
|
|
Write-Log " Registered task: UnlockStartLayout" -Level OK
|
|
}
|
|
catch {
|
|
Write-Log " Failed to register task UnlockStartLayout - $_" -Level ERROR
|
|
}
|
|
|
|
Write-Log "Step 6 complete" -Level OK
|