Scripts/Optimize-WsusContents.ps1
#Requires -Version 5.0 <# .Synopsis Cleanup wsus contents .Description The task schedule automatically deletes the old version. .Parameter ConfigPath Set ODT config path Create from 'Show-WsustainableSettingsView' .Example # Simply command sample Optimize-WsusContents -ConfigFileName 'C:\ProgramData\Wsustainable\0.1\Config.json' #> $VerbosePreference = 'Continue' Function Optimize-WsusContents{ Param( [Parameter(Mandatory)][String]$ConfigPath ) Function Deny-WsusFilteredUpdates($Config, $DeclineRule, $UpdateScope, $RetryCount, $Month, $Mode){ $CategoryTitle = $UpdateScope.Categories[0].Title $DeclineUpdateCount = 0 If ($RetryCount -gt $Config.UpdatesFindMode.MaximumRetry){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム取得はスキップされました" Return } If (($Config.UpdatesFindMode | Get-Member -Name 'ForceHalfModePerMonthLength').Count -eq 1){ If ($Month -ne $Null){ $UpdateScope.FromCreationDate = $Month $UpdateScope.ToCreationDate = $Month.AddMonths(1).AddSeconds(-1) } $UpdateCount = $WsusServer.GetUpdateCount($UpdateScope) If ($UpdateCount -eq 0){ Switch ($Mode){ ([WsusFilteredUpdatesMode]::H1){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) (1/5) はありませんでした" } ([WsusFilteredUpdatesMode]::H2){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) (2/5) はありませんでした" } ([WsusFilteredUpdatesMode]::H3){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) (3/5) はありませんでした" } ([WsusFilteredUpdatesMode]::H4){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) (4/5) はありませんでした" } ([WsusFilteredUpdatesMode]::H5){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) (5/5) はありませんでした" } ([WsusFilteredUpdatesMode]::Full){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) はありませんでした" } Default{ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラムはありませんでした" } } Return } ElseIf (($Mode -eq $Null) -and ($UpdateCount -ge $Config.UpdatesFindMode.ForceHalfModePerMonthLength)){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラムが $UpdateCount 件ありましたので分割して取得します" ForEach($Month in $Months){ Deny-WsusFilteredUpdates $Config $DeclineRule $UpdateScope $RetryCount $Month ([WsusFilteredUpdatesMode]::Full) } Return } ElseIf (($Month -ne $Null) -and ($Mode -eq ([WsusFilteredUpdatesMode]::Full)) -and ($UpdateCount -ge $Config.UpdatesFindMode.ForceHalfModePerMonthLength)){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) が $UpdateCount 件ありましたので分割して取得します" Deny-WsusFilteredUpdates $Config $DeclineRule $UpdateScope $RetryCount $Month ([WsusFilteredUpdatesMode]::H1) Return } } Switch ($Mode){ ([WsusFilteredUpdatesMode]::H1){ $UpdateScope.FromCreationDate = $Month $UpdateScope.ToCreationDate = $Month.AddDays(8).AddSeconds(-1) Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) (1/5) [未承認 $($WsusServer.GetUpdateCount($UpdateScope)) 個]" } ([WsusFilteredUpdatesMode]::H2){ $UpdateScope.FromCreationDate = $Month.AddDays(7) $UpdateScope.ToCreationDate = $Month.AddDays(15).AddSeconds(-1) Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) (2/5) [未承認 $($WsusServer.GetUpdateCount($UpdateScope)) 個]" } ([WsusFilteredUpdatesMode]::H3){ $UpdateScope.FromCreationDate = $Month.AddDays(14) $UpdateScope.ToCreationDate = $Month.AddDays(22).AddSeconds(-1) Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) (3/5) [未承認 $($WsusServer.GetUpdateCount($UpdateScope)) 個]" } ([WsusFilteredUpdatesMode]::H4){ $UpdateScope.FromCreationDate = $Month.AddDays(21) $UpdateScope.ToCreationDate = $Month.AddDays(28).AddSeconds(-1) Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) (4/5) [未承認 $($WsusServer.GetUpdateCount($UpdateScope)) 個]" } ([WsusFilteredUpdatesMode]::H5){ $UpdateScope.FromCreationDate = $Month.AddDays(28) $UpdateScope.ToCreationDate = $Month.AddMonths(1).AddSeconds(-1) Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) (5/5) [未承認 $($WsusServer.GetUpdateCount($UpdateScope)) 個]" } ([WsusFilteredUpdatesMode]::Full){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) [未承認 $UpdateCount 個]" } Default{ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム [未承認 $UpdateCount 個]" } } # Try { $Updates = $WsusServer.GetUpdates($UpdateScope) $DeclineReason = "" If ($LatestDeclineUpdate -ne $Null){ $Script:LatestDeclineUpdate = $_.Decline() } $Updates | Where-Object { $IsMatch = $False $Update = $_ If ($DeclineRule.LegacyNameFilter -ne $Null){ If ($True -in ($DeclineRule.LegacyNameFilter -split "`n" | ForEach-Object {$Update.LegacyName -like $_})){ $IsMatch = $True $DeclineReason += $DeclineRule.LegacyNameFilter } } If ($DeclineRule.TitleFilter -ne $Null){ If ($True -in ($DeclineRule.TitleFilter -split "`n" | ForEach-Object {$Update.Title -like $_})){ $IsMatch = $True $DeclineReason += $DeclineRule.TitleFilter } } If ($IsMatch){ If ($Updates.Count -eq $DeclineUpdateCount){ $Script:LatestDeclineUpdate = $Update.Decline() } Else{ $DeclineUpdateCount++ $Update.Decline() } } If ($CurrentConfig.Log.IsLogging){ If ($Config.Log.Verbose){ $Update | Select-Object Title, @{Name="ProductTitles";Expression={($_.ProductTitles -Join "`n")}}, CreationDate, LegacyName, @{Name="Id.RevisionNumber";Expression={($_.Id.RevisionNumber -Join "`n")}}, @{Name="Id.UpdateId";Expression={($_.Id.UpdateId -Join "`n")}}, @{Name="KnowledgebaseArticles";Expression={($_.KnowledgebaseArticles -Join "`n")}}, @{Name="SecurityBulletins";Expression={($_.SecurityBulletins -Join "`n")}}, UpdateClassificationTitle, @{Name="ProductFamilyTitles";Expression={($_.ProductFamilyTitles -Join "`n")}}, UpdateType, @{Name="DeclineResult";Expression={$DeclineResult}} | Export-Csv -Path (Join-Path $LogDirectory "$($DeclineRule.LogFileNameBase).csv") -Encoding UTF8 -NoTypeInformation -Append } Else{ If ($IsMatch){ $Update | Select-Object Title, LegacyName, UpdateClassificationTitle, @{Name="DeclineReason";Expression={$DeclineReason}} | Export-Csv -Path (Join-Path $LogDirectory "$($DeclineRule.LogFileNameBase).csv") -Encoding UTF8 -NoTypeInformation -Append } } } } # } # Catch{ # $WsusServer.PreferredCulture = $CurrentWsusServerPreferredCulture # Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラムを取得できませんでした" # Write-Verbose $_.Exception # $RetryCount++ # Deny-WsusFilteredUpdates $Config $DeclineRule $UpdateScope $RetryCount $Month $Mode # } Switch ($Mode){ ([WsusFilteredUpdatesMode]::H1){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) (1/5) [拒否 $DeclineUpdateCount 個]" Deny-WsusFilteredUpdates $Config $DeclineRule $UpdateScope $RetryCount $Month ([WsusFilteredUpdatesMode]::H2) } ([WsusFilteredUpdatesMode]::H2){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) (2/5) [拒否 $DeclineUpdateCount 個]" Deny-WsusFilteredUpdates $Config $DeclineRule $UpdateScope $RetryCount $Month ([WsusFilteredUpdatesMode]::H3) } ([WsusFilteredUpdatesMode]::H3){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) (3/5) [拒否 $DeclineUpdateCount 個]" Deny-WsusFilteredUpdates $Config $DeclineRule $UpdateScope $RetryCount $Month ([WsusFilteredUpdatesMode]::H4) } ([WsusFilteredUpdatesMode]::H4){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) (4/5) [拒否 $DeclineUpdateCount 個]" Deny-WsusFilteredUpdates $Config $DeclineRule $UpdateScope $RetryCount $Month ([WsusFilteredUpdatesMode]::H5) } ([WsusFilteredUpdatesMode]::H5){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) (5/5) [拒否 $DeclineUpdateCount 個]" } ([WsusFilteredUpdatesMode]::Full){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム $($Month.ToString("y")) [拒否 $DeclineUpdateCount 個]" } Default{ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $CategoryTitle の更新プログラム [拒否 $DeclineUpdateCount 個]" } } Return } Function Stop-WsusSynchronization($WsusServer, $TimeOut){ If ($TimeOut -eq $Null){ $TimeOut = (Get-Date).AddMinutes(10) } Switch ($WsusServer.GetSubscription().GetSynchronizationStatus()){ ([Microsoft.UpdateServices.Administration.SynchronizationStatus]::NotProcessing){ Write-Verbose "$(Get-Date -Format F): [Stop-WsusSynchronization] Already stopped." } ([Microsoft.UpdateServices.Administration.SynchronizationStatus]::Running){ Write-Verbose "$(Get-Date -Format F): [Stop-WsusSynchronization] Stopping now..." $WsusServer.GetSubscription().StopSynchronization() Start-Sleep -Seconds 5 Stop-WsusSynchronization -WsusServer $WsusServer -TimeOut $TimeOut } ([Microsoft.UpdateServices.Administration.SynchronizationStatus]::Stopping){ If ((Get-Date) -ge $TimeOut){ Write-Error "$(Get-Date -Format F): [Stop-WsusSynchronization] Timed out." } Else{ Write-Verbose "$(Get-Date -Format F): [Stop-WsusSynchronization] Stopping now..." Start-Sleep -Seconds 10 Stop-WsusSynchronization -WsusServer $WsusServer -TimeOut $TimeOut } } } } Import-Module UpdateServices If (@(Get-Module –Name UpdateServices).Count -eq 0){ Write-Error "このスクリプトの動作に必要な UpdateServices が見つかりませんでした" } #$LegacyNameFiltersDirectory = (Join-Path $PSScriptRoot "DeclineFilters\LegacyName") #$TitleFiltersDirectory = (Join-Path $PSScriptRoot "DeclineFilters\Title.en") If (-Not (Test-Path $ConfigPath -PathType Leaf)){ Write-Error ([System.IO.FileNotFoundException]::new("ConfigPath が見つかりませんでした: [$ConfigPath]")) -ErrorAction Stop } $CurrentConfig = (Get-Content $ConfigPath -Encoding UTF8 | ConvertFrom-Json) Start-Logging $CurrentConfig Get-DeclineRules $CurrentConfig | Out-Null $CurrentConfig = Set-RequiredConfigurationValues $CurrentConfig If ($CurrentConfig.Log.Verbose){ $CurrentConfig | ConvertTo-Json -Depth 10 | Out-File -FilePath (Join-Path $LogDirectory "InternalConfig.json") -Encoding UTF8 } $WsusServer = Get-WsusServer -Name $CurrentConfig.Wsus.Server -PortNumber $CurrentConfig.Wsus.Port If ($WsusServer -eq $Null){ Write-Error "WSUS サーバーに接続できませんでした" Break } Stop-WsusSynchronization -WsusServer $WsusServer If ($CurrentConfig.Wsus.PreferredCulture -ne $Null){ $WsusServer.PreferredCulture = $CurrentConfig.Wsus.PreferredCulture } $CurrentDate = [datetime]$CurrentConfig.UpdatesFindMode.MinimumDate $Months = @() Do{ $Months += $CurrentDate $CurrentDate = $CurrentDate.AddMonths(1) } While($CurrentDate -lt (Get-Date -Day 1)) ForEach($DeclineRule in $CurrentConfig.DeclineRules){ # DeclineRulesに必要な条件 If ((($DeclineRule | Get-Member -Name 'LogFileNameBase').Count -eq 0) -or (($DeclineRule | Get-Member -Name 'TargetProduct.Id').Count -eq 0) -and (($DeclineRule | Get-Member -Name 'TargetProduct.Title').Count -eq 0) -or (($DeclineRule | Get-Member -Name 'LegacyNameFilterPath').Count -eq 0) -and (($DeclineRule | Get-Member -Name 'TitleFilterPath').Count -eq 0)){ Write-Verbose "$(Get-Date -Format F): [$($DeclineRule.LogFileNameBase)] の条件には必要なパラメータがありません (TargetProduct.Id: $($DeclineRule.'TargetProduct.Id'), TargetProduct.Title: $($DeclineRule.'TargetProduct.Title'))" -Warning Continue } Else{ Write-Verbose "$(Get-Date -Format F): [$($DeclineRule.LogFileNameBase)] の条件に合う更新プログラムを拒否します (TargetProduct.Id: $($DeclineRule.'TargetProduct.Id'), TargetProduct.Title: $($DeclineRule.'TargetProduct.Title'))" If ($DeclineRule.LegacyNameFilter -eq $Null){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] LegacyNameFilter はありません" } If ($DeclineRule.TitleFilter -eq $Null){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] TitleFilter はありません" } } #Try{ If ($DeclineRule.'TargetProduct.Id' -ne $Null){ $CurrentCategory = $WsusServer.GetUpdateCategory($DeclineRule.'TargetProduct.Id') } ElseIf ($DeclineRule.'TargetProduct.Title' -ne $Null){ $CurrentCategory = $WsusServer.GetUpdateCategories | Where-Object Title -eq $DeclineRule.'TargetProduct.Title' } $UpdateScope = New-Object Microsoft.UpdateServices.Administration.UpdateScope $UpdateScope.ApprovedStates = [Microsoft.UpdateServices.Administration.ApprovedStates]::NotApproved $UpdateScope.Categories.Add($CurrentCategory) | Out-Null If (($DeclineRule | Get-Member -Name 'UpdateClassification.Id').Count -eq 1){ $UpdateClassification = $WsusServer.GetUpdateClassifications() $DeclineRule.'UpdateClassification.Id' | ForEach-Object {$UpdateClassification | Where-Object Id -eq $_ | ForEach-Object {$UpdateScope.Classifications.Add($_) | Out-Null}} } Deny-WsusFilteredUpdates -Config $CurrentConfig -DeclineRule $DeclineRule -UpdateScope $UpdateScope -RetryCount 0 If ($LatestDeclineUpdate -ne $Null){ If ($DeclineRule.'NotDeclineLatestUpdate' -ne $True){ $Script:LatestDeclineUpdate = $_.Decline() } Else{ $Script:LatestDeclineUpdate = $_.Decline() } } Try{ } Catch{ Write-Error "$(Get-Date -Format F): $($CurrentCategory.Title) の更新プログラムを取得できませんでした`n$($_.Exception)" } } Stop-Logging } Export-ModuleMember -Function Optimize-WsusContents |