106 lines
4.0 KiB
PowerShell
106 lines
4.0 KiB
PowerShell
param(
|
|
[string]$EvidenceDir = "C:\Wooo\Agent99\evidence"
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
New-Item -ItemType Directory -Force -Path $EvidenceDir | Out-Null
|
|
|
|
$stamp = Get-Date -Format "yyyyMMdd-HHmmss"
|
|
$evidencePath = Join-Path $EvidenceDir "agent99-windows-update-policy-$stamp.json"
|
|
$logPath = Join-Path $EvidenceDir "agent99-windows-update-policy-$stamp.log"
|
|
|
|
function Write-PolicyLog {
|
|
param([string]$Message)
|
|
"$(Get-Date -Format o) $Message" | Tee-Object -FilePath $logPath -Append | Out-Null
|
|
}
|
|
|
|
function Get-RegistrySnapshot {
|
|
param([string]$Path)
|
|
if (-not (Test-Path $Path)) {
|
|
return [pscustomobject]@{ path = $Path; exists = $false; values = @{} }
|
|
}
|
|
|
|
$item = Get-ItemProperty -Path $Path
|
|
$values = @{}
|
|
foreach ($prop in $item.PSObject.Properties) {
|
|
if ($prop.Name -notmatch "^PS") {
|
|
$values[$prop.Name] = $prop.Value
|
|
}
|
|
}
|
|
|
|
[pscustomobject]@{ path = $Path; exists = $true; values = $values }
|
|
}
|
|
|
|
$windowsUpdatePolicy = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate"
|
|
$auPolicy = Join-Path $windowsUpdatePolicy "AU"
|
|
$uxSettings = "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings"
|
|
|
|
$before = @(
|
|
Get-RegistrySnapshot $windowsUpdatePolicy
|
|
Get-RegistrySnapshot $auPolicy
|
|
Get-RegistrySnapshot $uxSettings
|
|
)
|
|
|
|
Write-PolicyLog "apply_start windows_update_no_surprise_reboot"
|
|
New-Item -Path $windowsUpdatePolicy -Force | Out-Null
|
|
New-Item -Path $auPolicy -Force | Out-Null
|
|
New-Item -Path $uxSettings -Force | Out-Null
|
|
|
|
# Keep Windows Update enabled, but prevent unattended surprise restarts.
|
|
New-ItemProperty -Path $auPolicy -Name "NoAutoRebootWithLoggedOnUsers" -Value 1 -PropertyType DWord -Force | Out-Null
|
|
New-ItemProperty -Path $auPolicy -Name "AlwaysAutoRebootAtScheduledTime" -Value 0 -PropertyType DWord -Force | Out-Null
|
|
New-ItemProperty -Path $auPolicy -Name "AUOptions" -Value 3 -PropertyType DWord -Force | Out-Null
|
|
New-ItemProperty -Path $auPolicy -Name "ScheduledInstallDay" -Value 0 -PropertyType DWord -Force | Out-Null
|
|
New-ItemProperty -Path $auPolicy -Name "ScheduledInstallTime" -Value 3 -PropertyType DWord -Force | Out-Null
|
|
New-ItemProperty -Path $auPolicy -Name "AUPowerManagement" -Value 0 -PropertyType DWord -Force | Out-Null
|
|
|
|
# Make the interactive active-hours UI reflect an ops-safe window.
|
|
New-ItemProperty -Path $uxSettings -Name "ActiveHoursStart" -Value 0 -PropertyType DWord -Force | Out-Null
|
|
New-ItemProperty -Path $uxSettings -Name "ActiveHoursEnd" -Value 23 -PropertyType DWord -Force | Out-Null
|
|
New-ItemProperty -Path $uxSettings -Name "SmartActiveHoursState" -Value 0 -PropertyType DWord -Force | Out-Null
|
|
|
|
$after = @(
|
|
Get-RegistrySnapshot $windowsUpdatePolicy
|
|
Get-RegistrySnapshot $auPolicy
|
|
Get-RegistrySnapshot $uxSettings
|
|
)
|
|
|
|
$pendingRebootKeys = @(
|
|
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending",
|
|
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired",
|
|
"HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager"
|
|
)
|
|
|
|
$pending = @()
|
|
foreach ($key in $pendingRebootKeys) {
|
|
if ($key -like "*Session Manager") {
|
|
$value = (Get-ItemProperty -Path $key -Name "PendingFileRenameOperations" -ErrorAction SilentlyContinue).PendingFileRenameOperations
|
|
$pending += [pscustomobject]@{ path = $key; signal = "PendingFileRenameOperations"; present = [bool]$value }
|
|
} else {
|
|
$pending += [pscustomobject]@{ path = $key; signal = "key_exists"; present = [bool](Test-Path $key) }
|
|
}
|
|
}
|
|
|
|
try {
|
|
gpupdate.exe /target:computer /force | Out-File -FilePath $logPath -Append -Encoding UTF8
|
|
$gpupdateOk = $true
|
|
} catch {
|
|
$gpupdateOk = $false
|
|
Write-PolicyLog "gpupdate_failed error=$($_.Exception.Message)"
|
|
}
|
|
|
|
$result = [pscustomobject]@{
|
|
timestamp = (Get-Date -Format o)
|
|
applied = $true
|
|
policy = "windows_update_no_surprise_reboot"
|
|
gpupdateOk = $gpupdateOk
|
|
before = $before
|
|
after = $after
|
|
pendingRebootSignals = $pending
|
|
evidenceLog = $logPath
|
|
}
|
|
|
|
$result | ConvertTo-Json -Depth 8 | Set-Content -Encoding UTF8 $evidencePath
|
|
Write-PolicyLog "apply_complete evidence=$evidencePath"
|
|
Write-Host $evidencePath
|