Auto-commit: 2025-10-31 08:55:43
This commit is contained in:
123
auto-approval/approval.ps1
Normal file
123
auto-approval/approval.ps1
Normal file
@@ -0,0 +1,123 @@
|
||||
$SyncApprovals = @(
|
||||
# Sync TESTERS -> PILOT
|
||||
@{
|
||||
"Source" = "Pilot" # Source group: TESTERS
|
||||
"Target" = "Global1" # Target group: PILOT
|
||||
"MinDays" = 5 # Minimum number of days before synchronization
|
||||
},
|
||||
|
||||
# Sync PILOT -> PROD
|
||||
@{
|
||||
"Source" = "Global1" # Source group: PILOT
|
||||
"Target" = "Global2" # Target group: PROD
|
||||
"MinDays" = 5 # Minimum number of days before synchronization
|
||||
}
|
||||
)
|
||||
|
||||
$logFolder = "C:\logs"
|
||||
$maxLogs = 60
|
||||
|
||||
# Ensure the log folder exists (create if missing)
|
||||
If (-not (Test-Path $logFolder)) {
|
||||
New-Item -Path $logFolder -ItemType Directory
|
||||
Write-Host "The directory $logFolder has been created."
|
||||
} else {
|
||||
Write-Host "The directory $logFolder already exists."
|
||||
}
|
||||
|
||||
# Limit the number of log files (keep the most recent $maxLogs)
|
||||
$logFiles = Get-ChildItem -Path $logFolder -Filter "WSUS-ManageApprovals*.log" | Sort-Object LastWriteTime -Descending
|
||||
if ($logFiles.Count -gt $maxLogs) {
|
||||
$logFiles | Select-Object -Skip $maxLogs | Remove-Item -Force
|
||||
}
|
||||
|
||||
# Build current log file path
|
||||
$logFile = Join-Path $logFolder ("WSUS-ManageApprovals" + (Get-Date -format "yyyyMMdd-HHmmss") + ".log")
|
||||
|
||||
# Connect to the WSUS server
|
||||
Try {
|
||||
[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | Out-Null
|
||||
$wsusServer = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer()
|
||||
$subscription = $wsusServer.GetSubscription()
|
||||
$wsusServerConfig = $wsusServer.GetConfiguration()
|
||||
$targetGroups = $wsusServer.GetComputerTargetGroups()
|
||||
$updates = $wsusServer.GetUpdates()
|
||||
} Catch {
|
||||
Write-Output "Error connecting to the WSUS server: $_" | Add-Content -Path $logFile
|
||||
Exit
|
||||
}
|
||||
|
||||
# Start a WSUS synchronization (non-blocking)
|
||||
Try {
|
||||
$subscription.StartSynchronization()
|
||||
Write-Output "Synchronization successfully started." | Add-Content -Path $logFile
|
||||
} Catch {
|
||||
Write-Output "Error during WSUS synchronization: $_" | Add-Content -Path $logFile
|
||||
Exit
|
||||
}
|
||||
|
||||
# Filter working updates (exclude declined) and accept EULAs if needed
|
||||
$workingUpdates = $updates | Where-Object { -not $_.IsDeclined }
|
||||
Foreach ($update in $workingUpdates) {
|
||||
# Accept license agreement if required
|
||||
If ($update.RequiresLicenseAgreementAcceptance) {
|
||||
$update.AcceptLicenseAgreement()
|
||||
Write-Output "License accepted for: $($update.Title)" | Add-Content -Path $logFile
|
||||
}
|
||||
}
|
||||
|
||||
# Approve updates to target groups after MinDays since source approval GoLiveTime
|
||||
Write-Output "********** Approve KB **********" | Add-Content -Path $logFile
|
||||
Foreach ($update in $workingUpdates) {
|
||||
$approvals = $update.GetUpdateApprovals()
|
||||
Foreach ($syncApproval in $SyncApprovals) {
|
||||
$sourceGroup = $targetGroups | Where-Object { $_.Name -eq $syncApproval.Source }
|
||||
|
||||
# Ensure source group exists and action is Install
|
||||
If ($sourceGroup) {
|
||||
$sourceApproval = $approvals | Where-Object { $_.ComputerTargetGroupId -eq $sourceGroup.ID }
|
||||
If ($sourceApproval -and $($sourceApproval.Action) -eq "Install") {
|
||||
# Check if enough days have passed since GoLiveTime
|
||||
$LastChangeKB = (New-TimeSpan -Start $sourceApproval.GoLiveTime -End (Get-Date)).Days
|
||||
If ($LastChangeKB -ge $syncApproval.MinDays) {
|
||||
$targetGroup = $targetGroups | Where-Object { $_.Name -eq $syncApproval.Target }
|
||||
$targetApproval = $approvals | Where-Object { $_.ComputerTargetGroupId -eq $targetGroup.ID }
|
||||
|
||||
# Approve the update if it's not already approved for installation
|
||||
If ($($targetApproval.Action) -ne "Install") {
|
||||
Write-Output "Approving: $($syncApproval.Target) => $($update.Title) - $LastChangeKB days" | Add-Content -Path $logFile
|
||||
$update.Approve("Install", $targetGroup) | Out-Null
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Output "Source group $($syncApproval.Source) not found." | Add-Content -Path $logFile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Decline superseded updates if a superseding one is installed for the expected target groups
|
||||
Write-Output "********** Disable Superseded Updates **********" | Add-Content -Path $logFile
|
||||
$workingUpdates = $workingUpdates | Where-Object { $_.IsSuperseded }
|
||||
Foreach ($update in $workingUpdates) {
|
||||
Write-Output "$($update.Title)" | Add-Content -Path $logFile
|
||||
|
||||
# Find updates that supersede the current update
|
||||
Foreach ($Supersede in $update.GetRelatedUpdates([Microsoft.UpdateServices.Administration.UpdateRelationship]::UpdatesThatSupersedeThisUpdate)) {
|
||||
Write-Output "----- Replaced By: $($Supersede.Title)" | Add-Content -Path $logFile
|
||||
$approvals = $Supersede.GetUpdateApprovals()
|
||||
|
||||
# If a superseding update is approved for Install in Global2, decline the superseded one
|
||||
Foreach ($approval in $approvals) {
|
||||
Foreach ($targetGroup in $targetGroups) {
|
||||
If (($targetGroup.Id -eq $approval.ComputerTargetGroupId) -and ($($approval.Action) -eq "Install")) {
|
||||
Write-Output "---------- $($targetGroup.Name)" | Add-Content -Path $logFile
|
||||
if ($($targetGroup.Name) -eq "Global2") { # fixed: target group is Global2
|
||||
Write-Output "---------- Declining: $($update.Title)" | Add-Content -Path $logFile
|
||||
$update.Decline()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user