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' .Parameter FistLaunch FistLaunch mode .Example # Simply command sample Optimize-WsusContents -ConfigFileName 'C:\ProgramData\Wsustainable\0.1\Config.json' #> $VerbosePreference = 'Continue' Function Optimize-WsusContents{ Param( [Parameter(Mandatory)][String]$ConfigPath, [Switch]$FistLaunch ) 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) $DeclineRule.DeclineOldVersions 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) $LastDeclineUpdate = $Null $Updates | Where-Object { $DeclineReason = "" $IsMatch = $False $Update = $_ If ($DeclineRule.LegacyNameFilter -ne $Null){ $Global:DeclineRuleLegacyNameFilter = $DeclineRule.LegacyNameFilter $Global:UpdateLegacyName = $Update.LegacyName If ($True -in ($DeclineRule.LegacyNameFilter -split "`n" | ForEach-Object {$Update.LegacyName -like $_})){ $IsMatch = $True $DeclineReason += "LegacyNameFilter is mtach" } } If ($DeclineRule.TitleFilter -ne $Null){ If ($True -in ($DeclineRule.TitleFilter -split "`n" | ForEach-Object {$Update.Title -like $_})){ $IsMatch = $True $DeclineReason += "TitleFilter is mtach" } } If ($IsMatch){ $DeclineUpdateCount++ $LastDeclineUpdate = $Update $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="DeclineReason";Expression={$DeclineReason}} | 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 } } } } If ($DeclineRule.DeclineOldVersions -and ($LastDeclineUpdate -ne $Null)){ $LastDeclineUpdate.Approve("Install", $WsusServer.GetComputerTargetGroups()[0]) | Out-Null Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] $($LastDeclineUpdate.ProductTitles[0]) は一度拒否されましたが、ルールにより承認されました" If ($Config.Log.Verbose){ $LastDeclineUpdate | 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="DeclineReason";Expression={"Approved"}} | Export-Csv -Path (Join-Path $LogDirectory "$($DeclineRule.LogFileNameBase).csv") -Encoding UTF8 -NoTypeInformation -Append } Else{ If ($IsMatch){ $LastDeclineUpdate | Select-Object Title, LegacyName, UpdateClassificationTitle, @{Name="DeclineReason";Expression={"Approved"}} | 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 $DeclineRule.DeclineOldVersions # } 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) $DeclineOldVersions } ([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) $DeclineOldVersions } ([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) $DeclineOldVersions } ([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) $DeclineOldVersions } ([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 が見つかりませんでした" } 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 $ApprovedStates = [Microsoft.UpdateServices.Administration.ApprovedStates]::unknown If ($FistLaunch){ @($CurrentConfig.FistLaunch.ApprovedStates) | ForEach-Object { $ApprovedStates = $ApprovedStates -bor [Microsoft.UpdateServices.Administration.ApprovedStates]::$_ } } Else{ @($CurrentConfig.UpdatesFindMode.ApprovedStates) | ForEach-Object { $ApprovedStates = $ApprovedStates -bor [Microsoft.UpdateServices.Administration.ApprovedStates]::$_ } } Write-Verbose "$(Get-Date -Format F): ApprovedStates is $ApprovedStates" If ($ApprovedStates -eq [Microsoft.UpdateServices.Administration.ApprovedStates]::unknown){ Write-Verbose "$(Get-Date -Format F): ApprovedStates is NotApproved" $ApprovedStates = [Microsoft.UpdateServices.Administration.ApprovedStates]::NotApproved } 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){ If ($DeclineRule.'TargetProduct.Id' -ne $Null){ $TargetProductDetails = "TargetProduct.Id: $($DeclineRule.'TargetProduct.Id')" If ($WsusServer.GetUpdateCategory($DeclineRule.'TargetProduct.Id') -ne $Null){ $TargetProductTitle = $WsusServer.GetUpdateCategory($DeclineRule.'TargetProduct.Id').Title $TargetProductDetails = "TargetProductTitle: $TargetProductTitle, TargetProduct.Id: $($DeclineRule.'TargetProduct.Id')" } } Else{ $TargetProductDetails = "TargetProductTitle: $($DeclineRule.'TargetProduct.Title')" } # 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)] の条件には必要なパラメータがありません ($TargetProductDetails)" -Warning Continue } Else{ Write-Verbose "$(Get-Date -Format F): [$($DeclineRule.LogFileNameBase)] の条件に合う更新プログラムを拒否します ($TargetProductDetails)" If ($DeclineRule.LegacyNameFilter -eq $Null){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] LegacyNameFilter はありません" } Else{ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] LegacyNameFilter: $($DeclineRule.LegacyNameFilter.Replace("`n",","))" } If ($DeclineRule.TitleFilter -eq $Null){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] TitleFilter はありません" } Else{ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] TitleFilter: $($DeclineRule.TitleFilter.Replace("`n",","))" } If ($DeclineRule.DeclineOldVersions){ Write-Verbose "$(Get-Date -Format F): [Deny-WsusFilteredUpdates] DeclineOldVersions" } } #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 = $ApprovedStates $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}} } $Script:LatestDeclineUpdate = $Null Deny-WsusFilteredUpdates -Config $CurrentConfig -DeclineRule $DeclineRule -UpdateScope $UpdateScope -RetryCount 0 Try{ } Catch{ Write-Error "$(Get-Date -Format F): $($CurrentCategory.Title) の更新プログラムを取得できませんでした`n$($_.Exception)" } } If ($CurrentConfig.DeclineOptions.CleanupWizard.CompressUpdates){ #クリーンアップウィザード: 不要な更新および更新のリビジョン $WsusServer | Invoke-WsusServerCleanup -CompressUpdates } If ($CurrentConfig.DeclineOptions.CleanupWizard.CleanupUnneededContentFiles){ #クリーンアップウィザード: 不要な更新ファイル・期限切れの更新・置き換えられた更新 $WsusServer | Invoke-WsusServerCleanup -CleanupUnneededContentFiles } If ($CurrentConfig.DeclineOptions.CleanupWizard.CleanupObsoleteUpdates){ # $WsusServer | Invoke-WsusServerCleanup -CleanupObsoleteUpdates } If ($CurrentConfig.DeclineOptions.CleanupWizard.DeclineSupersededUpdates){ #置き換えられた更新プロラム (すべて) $WsusServer | Invoke-WsusServerCleanup -DeclineSupersededUpdates } If ($CurrentConfig.DeclineOptions.CleanupWizard.DeclineExpiredUpdates){ # $WsusServer | Invoke-WsusServerCleanup -DeclineExpiredUpdates } If ($CurrentConfig.MaintenanceSql.ScriptPath -ne $Null){ If (Test-Path $CurrentConfig.MaintenanceSql.ScriptPath){ # } } Stop-Logging } Export-ModuleMember -Function Optimize-WsusContents |