decline-WSUSUpdatesTypes.ps1
<#PSScriptInfo .VERSION 1.4 .GUID 8facf0bf-cade-41a6-8855-5c80e0b50ed9 .AUTHOR Fabian Niesen (Infrastrukturhelden.de) .COMPANYNAME .COPYRIGHT Fabian Niesen 2018 .TAGS Update .LICENSEURI .PROJECTURI https://www.infrastrukturhelden.de/microsoft-infrastruktur/wsus/windows-server-update-services-bereinigen.html .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES First version with Config File. Might be a little bit buggy. Any comments or issues with this release are Welcome. .PRIVATEDATA #> <# .SYNOPSIS Decline several Update Types in Windows Server Update Services (WSUS) .DESCRIPTION Decline several Update Types in Windows Server Update Services (WSUS). For example Beta and Preview Updates, Updates for Itanium, Drivers, Dell Hardware, Surface Hardware, SharePoint Updates in Office Channel, Language on Demand Feature updates and superseded updates. The scrips send, if configured a list of the decliened updates. .EXAMPLE decline-WSUSUpdatesTypes.ps1 -Preview -Itanium -Superseded -SmtpServer "Mail.domai.tld" -EmailLog .EXAMPLE decline-WSUSUpdatesTypes.ps1 -Preview -Itanium -SharePoint .PARAMETER Preview Decline Updates with the phrases -Preview- or -Beta- in the title or the attribute -beta- set .PARAMETER Itanium Decline Updates with the phrases -ia64- or -itanium- .PARAMETER LanguageFeatureOnDemand Decline Updates with the phrases -LanguageFeatureOnDemand- or -Lang Pack (Language Feature) Feature On Demand- or -LanguageInterfacePack- .PARAMETER Sharepoint Decline Updates with the phrases -SharePoint Enterprise Server- or -SharePoint Foundation- or -SharePoint Server- or -FAST Search Server- Some of these are part of the Office Update Channel .PARAMETER Dell Decline Updates with the phrases -Dell- for reducing for example the updates in the drivers category, if no Dell Hardware is used .PARAMETER Surface Decline Updates with the phrases -Surface- and -Microsoft- .PARAMETER Drivers Decline Updates with the Classification -Drivers- .PARAMETER OfficeWebApp Decline Updates with the phrases -Excel Web App- or -Office Web App- or -Word Web App- or -PowerPoint Web App- .PARAMETER Officex86 Decline Updates with the phrases -32-Bit- and one of these -Microsoft Office-, -Microsoft Access-, -Microsoft Excel-, -Microsoft Outlook-, -Microsoft Onenote-, -Microsoft PowerPoint-, -Microsoft Publisher-, -Microsoft Word- .PARAMETER Officex64 Decline Updates with the phrases -64-Bit- and one of these -Microsoft Office-, -Microsoft Access-, -Microsoft Excel-, -Microsoft Outlook-, -Microsoft Onenote-, -Microsoft PowerPoint-, -Microsoft Publisher-, -Microsoft Word- .PARAMETER Superseded Decline Updates with the attribute -IsSuperseded- .NOTES Author : Fabian Niesen Filename : decline-WSUSUpdatesTypes.ps1 Requires : PowerShell Version 3.0 Version : 1.4 History : 1.4 Add Config file 1.3 Coments, Header added 1.2 Fix issues 1.1 added Mail funtion 1.0 initial version .LINK https://www.infrastrukturhelden.de/microsoft-infrastruktur/wsus/windows-server-update-services-bereinigen.html #> [cmdletbinding()] Param( [Parameter(Position=1)] [string]$WsusServer = ([system.net.dns]::GetHostByName('localhost')).hostname, [Parameter(Position=2)] [bool]$UseSSL = $False, [Parameter(Position=3)] [int]$PortNumber = 8530, [Parameter(Position=4)] [switch]$Preview, [Parameter(Position=5)] [switch]$Itanium, [Parameter(Position=6)] [switch]$LanguageFeatureOnDemand, [Parameter(Position=7)] [switch]$Sharepoint, [Parameter(Position=8)] [switch]$Dell, [Parameter(Position=9)] [switch]$Surface, [Parameter(Position=10)] [switch]$OfficeWebApp, [Parameter(Position=11)] [switch]$Drivers, [Parameter(Position=12)] [switch]$Officex86, [Parameter(Position=13)] [switch]$Officex64, [Parameter(Position=14)] [switch]$Superseded, [Parameter(Position=15)] [switch]$ListNeeded, [Parameter(Position=16)] [string]$SmtpServer, [Parameter(Position=17)] [string]$From, [Parameter(Position=18)] [string]$To, [Parameter(Position=19)] [string]$Subject = "WSUS Update Report $WsusServer", [Parameter(Position=20)] [switch]$WhatIf, [Parameter(Position=21)] [switch]$TLS, [Parameter(Position=22)] [switch]$SmtpAuth, [Parameter(Position=23)] [string]$smtppw = "", [Parameter(Position=24)] [string]$smtpuser = "", [Parameter(Position=25)] [switch]$EmailLog, [Parameter(Position=26)] [switch]$TestMail, [Parameter(Position=27)] [switch]$Default, [Parameter(Position=28)] [switch]$save, [switch]$load ) cls $conffile = "./decline-WSUSUpdatesType.clixml" IF ($save) { IF (Test-Path -Path $conffile) { Write-Debug "Configfile found, overwrite" } $WsusServer,$UseSSL,$PortNumber,$Preview,$Itanium,$LanguageFeatureOnDemand,$Sharepoint,$Dell,$Surface,$OfficeWebApp,$Drivers,$Officex86,$Officex64,$Superseded,$ListNeeded,$SmtpServer,$From,$To,$Subject,$WhatIf,$TLS,$SmtpAuth,$smtppw,$smtpuser,$EmailLog | Export-CliXml $conffile -Force -Depth 2 #Get-Variable | Export-Clixml Write-Output "Settings saved to $conffile" break } IF ($load) { IF (Test-Path -Path $conffile) { Write-Debug "Configfile found, loading" Import-CliXml $conffile | Set-Variable } } $TestBody = "<h1>Testmail from $WsusServer</h1><BR>Send over: $SmtpServer" $Style = "<Style>BODY{font-size:12px;font-family:verdana,sans-serif;color:navy;font-weight:normal;}" + "TABLE{border-width:1px;cellpadding=10;border-style:solid;border-color:navy;border-collapse:collapse;}" + "TH{font-size:12px;border-width:1px;padding:10px;border-style:solid;border-color:navy;}" + "TD{font-size:10px;border-width:1px;padding:10px;border-style:solid;border-color:navy;}</Style>" $Table = @{Name="Title";Expression={[string]$_.Title}},@{Name="KB Article";Expression={[string]::join(' | ',$_.KnowledgebaseArticles[0])}},@{Name="Classification";Expression={[string]$_.UpdateClassificationTitle}},@{Name="Product Title";Expression={[string]::join(' | ',$_.ProductTitles[0])}},@{Name="MsrcSeverity";Expression={[string]::join(' | ',$_.MsrcSeverity)}},@{Name="CreationDate";Expression={[string]::join(' | ',$_.CreationDate)}},@{Name="Product Family";Expression={[string]::join(' | ',$_.ProductFamilyTitles[0])}},@{Name="Kind of Patch";Expression={[string]::join(' | ',$_.PatchType)}} IF ($Default) { $Preview = $true; $Itanium = $true ; $LanguageFeatureOnDemand = $true} Function SendEmailStatus($From, $To, $Subject, $SmtpServer, $BodyAsHtml, $Body) { $SmtpMessage = New-Object System.Net.Mail.MailMessage $From, $To, $Subject, $Body $SmtpMessage.IsBodyHTML = $BodyAsHtml $SmtpClient = New-Object System.Net.Mail.SmtpClient $SmtpServer IF ($TLS) { $SmtpClient.EnableSsl = $true } IF ($SmtpAuth) { $SmtpClient.Credentials = New-Object System.Net.NetworkCredential($smtpuser, $smtppw) } $SmtpClient.Send($SmtpMessage) If($? -eq $False){Write-Warning "$($Error[0].Exception.Message) | $($Error[0].Exception.GetBaseException().Message)"} $SmtpMessage.Dispose() Remove-Variable SmtpClient Remove-Variable SmtpMessage } $Updates = $null [reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | out-null $WsusServerAdminProxy = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($WsusServer,$UseSSL,$PortNumber); IF ($WhatIF) { Write-Warning "WhatIF Mode, no changes will be made!!!"} IF ($Preview -eq $true) { Write-Output "Declining of Beta and Preview updates selected, starting query." $BetaUpdates = $WsusServerAdminProxy.GetUpdates() | ?{-not $_.IsDeclined -and ($_.Title -match �preview|beta� -or -not $_.IsDeclined -and $_.IsBeta -eq $true)} Write-Output "Found $($BetaUpdates.count) Preview or Beta Updates to decline" If($BetaUpdates) { IF (! $WhatIF) {$BetaUpdates | %{$_.Decline()}} $BetaUpdates | Add-Member -MemberType NoteProperty -Name PatchType -value BetaUpdate $Updates = $Updates + $BetaUpdates } Else {"No Preview / Beta Updates found that needed declining. Come back next 'Patch Tuesday' and you may have better luck."} } IF ($Itanium -eq $true) { Write-Output "Declining of Itanium updates selected, starting query." $ItaniumUpdates = $WsusServerAdminProxy.GetUpdates() | ?{-not $_.IsDeclined -and $_.Title -match �ia64|itanium�} Write-Output "Found $($ItaniumUpdates.count) Itanium Updates to decline" If($ItaniumUpdates) { IF (! $WhatIF) {$ItaniumUpdates | %{$_.Decline()}} $ItaniumUpdates | Add-Member -MemberType NoteProperty -Name PatchType -value "Itanium" $Updates = $Updates + $ItaniumUpdates } Else {"No Itanium Updates found that needed declining. Come back next 'Patch Tuesday' and you may have better luck."} } IF ($LanguageFeatureOnDemand -eq $true) { Write-Output "Declining of Language Feature on Demand selected, starting query." $LanguageFeatureOnDemandU = $WsusServerAdminProxy.GetUpdates() | ?{-not $_.IsDeclined -and $_.Title -match �LanguageFeatureOnDemand|Lang Pack (Language Feature) Feature On Demand|LanguageInterfacePack�} Write-Output "Found $($LanguageFeatureOnDemandU.count) LanguageFeatureOnDemand to decline" If($LanguageFeatureOnDemandU) { IF (! $WhatIF) {$LanguageFeatureOnDemandU | %{$_.Decline()}} $LanguageFeatureOnDemandU | Add-Member -MemberType NoteProperty -Name PatchType -value "LanguageFeatureOnDemand" $Updates = $Updates + $LanguageFeatureOnDemandU } Else {"No LanguageFeatureOnDemand Updates found that needed declining. Come back next 'Patch Tuesday' and you may have better luck."} } IF ($Sharepoint -eq $true) { Write-Output "Declining of Sharepoint Updates selected, starting query." $SharepointU = $WsusServerAdminProxy.GetUpdates() | ?{-not $_.IsDeclined -and $_.Title -match �SharePoint Enterprise Server|SharePoint Foundation|SharePoint Server|FAST Search Server�} Write-Output "Found $($SharepointU.count) Sharepoint Updates to decline" If($SharepointU) { IF (! $WhatIF) {$SharepointU | %{$_.Decline()}} $SharepointU | Add-Member -MemberType NoteProperty -Name PatchType -value "SharePoint" $Updates = $Updates + $SharepointU } Else {"No Sharepoint Updates found that needed declining. Come back next 'Patch Tuesday' and you may have better luck."} } IF ($Dell -eq $true) { Write-Output "Declining of Dell Updates selected, starting query." $DellU = $WsusServerAdminProxy.GetUpdates() | ?{-not $_.IsDeclined -and $_.Title -match �Dell�} Write-Output "Found $($DellU.count) Dell Updates to decline" If($DellU) { IF (! $WhatIF) {$DellU | %{$_.Decline()}} $DellU | Add-Member -MemberType NoteProperty -Name PatchType -value "Dell" $Updates = $Updates + $DellU } Else {"No Dell Updates found that needed declining. Come back next 'Patch Tuesday' and you may have better luck."} } IF ($Surface -eq $true) { Write-Output "Declining of Microsoft Surface updates selected, starting query." $SurfaceU = $WsusServerAdminProxy.GetUpdates() | ?{-not $_.IsDeclined -and $_.Title -match �Surface� -and $_.Title -match �Microsoft�} Write-Output "Found $($SurfaceU.count) Microsoft Surface updates to decline" If($SurfaceU) { IF (! $WhatIF) {$SurfaceU | %{$_.Decline()}} $SurfaceU | Add-Member -MemberType NoteProperty -Name PatchType -value "Surface" $Updates = $Updates + $SurfaceU } Else {"No Surface Updates found that needed declining. Come back next 'Patch Tuesday' and you may have better luck."} } IF ($Officex86 -eq $true) { Write-Output "Declining of Office updates for 32 bit selected, starting query." $Officex86U = $WsusServerAdminProxy.GetUpdates() | ?{-not $_.IsDeclined -and $_.Title -match �Microsoft Office|Microsoft Access|Microsoft Excel|Microsoft Outlook|Microsoft Onenote|Microsoft PowerPoint|Microsoft Publisher|Microsoft Word� -and $_.Title -match �32-Bit�} Write-Output "Found $($Officex86U.count) Microsoft Surface updates to decline" If($Officex86U) { IF (! $WhatIF) {$Officex86U | %{$_.Decline()}} $Officex86U | Add-Member -MemberType NoteProperty -Name PatchType -value "Office x86" $Updates = $Updates + $Officex86U } Else {"No Office updates for 32 bit found that needed declining. Come back next 'Patch Tuesday' and you may have better luck."} } IF ($Officex64 -eq $true) { Write-Output "Declining of Office updates for 64 bit selected, starting query." $Officex64U = $WsusServerAdminProxy.GetUpdates() | ?{-not $_.IsDeclined -and $_.Title -match �Microsoft Office|Microsoft Access|Microsoft Excel|Microsoft Outlook|Microsoft Onenote|Microsoft PowerPoint|Microsoft Publisher|Microsoft Word� -and $_.Title -match �64-Bit�} Write-Output "Found $($Officex64U.count) Microsoft Surface updates to decline" If($Officex64U) { IF (! $WhatIF) {$Officex64U | %{$_.Decline()}} $Officex64U | Add-Member -MemberType NoteProperty -Name PatchType -value "Office x64" $Updates = $Updates + $Officex64U } Else {"No Office updates for 64 bit found that needed declining. Come back next 'Patch Tuesday' and you may have better luck."} } IF ($Drivers -eq $true) { Write-Output "Declining of Drivers selected, starting query." $DriversUpdates = $WsusServerAdminProxy.GetUpdates() | ?{-not $_.IsDeclined -and $_.Classification -match �Drivers�} Write-Output "Found $($DriversUpdates.count) Drivers to decline" If($DriversUpdates) { IF (! $WhatIF) {$DriversUpdates | %{$_.Decline()}} $DriversUpdates | Add-Member -MemberType NoteProperty -Name PatchType -value "Driver Update" $Updates = $Updates + $DriversUpdates } Else {"No Driver found that needed declining. Come back next 'Patch Tuesday' and you may have better luck."} } IF ($OfficeWebApp -eq $true) { Write-Output "Declining of Office WebApp Updates selected, starting query." $OfficeWebAppU = $WsusServerAdminProxy.GetUpdates() | ?{-not $_.IsDeclined -and $_.Title -match �Excel Web App|Office Web App|Word Web App|PowerPoint Web App�} Write-Output "Found $($OfficeWebAppU.count) Office WebApp Updates to decline" If($OfficeWebAppU) { IF (! $WhatIF) {$OfficeWebAppU | %{$_.Decline()}} $OfficeWebAppU | Add-Member -MemberType NoteProperty -Name PatchType -value "OfficeWebApp" $Updates = $Updates + $OfficeWebAppU } Else {"No OfficeWebApp Updates found that needed declining. Come back next 'Patch Tuesday' and you may have better luck."} } IF ($Superseded -eq $true ) { Write-Output "Declining Superseded Updates selected, starting query." $SupersededU = $WsusServerAdminProxy.GetUpdates() | ?{-not $_.IsDeclined -and $_.IsSuperseded -eq $true} Write-Output "Found $($SupersededU.count) Superseded Updates to decline" If($SupersededU) { IF (! $WhatIF) {$SupersededU | %{$_.Decline()}} $SupersededU | Add-Member -MemberType NoteProperty -Name PatchType -value "Superseded" $Updates = $Updates + $SupersededU } Else {"No IsSuperseded Updates found that needed declining. Come back next 'Patch Tuesday' and you may have better luck."} } $Updates | select $Table | sort -Property "KB Article" | ft -AutoSize -Property "Kind of Patch",Title,"KB Article" IF ($EmailLog -and $Updates.Count -ge 1) { $Body = "<h1>Declined Updates</h1>$($Updates | Select $Table | ConvertTo-HTML -head $Style)" } Else { $Body ="" } IF ($WhatIf) { $Body += "<br><p>WhatIf mode enabled!!</p>" } IF ($ListNeeded -eq $true) { Write-Output "List needed updates selected, starting query." $updatescope = New-Object Microsoft.UpdateServices.Administration.UpdateScope $updatescope.ApprovedStates = [Microsoft.UpdateServices.Administration.ApprovedStates]::NotApproved $updatescope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::NotInstalled $NeededUpdates = $WsusServerAdminProxy.GetUpdates($updatescope) Write-Output "Found $($NeededUpdates.count) needed Updates" If($NeededUpdates) { #IF (! $WhatIF) {$SupersededU | %{$_.Decline()}} Write-Output "Needed Updates:" $NeededUpdates | Select $Table | FT -AutoSize $Body = $Body +"<br><h1>Needed Updates</h1>"+$($NeededUpdates | Select $Table | ConvertTo-HTML -head $Style) } Else {"No Needed Updates found to list. Come back next 'Patch Tuesday' and you may have better luck."} } If($TestMail){SendEmailStatus -From $From -To $To -Subject $Subject -SmtpServer $SmtpServer -BodyAsHtml $True -Body $TestBody } If($EmailLog){SendEmailStatus -From $From -To $To -Subject $Subject -SmtpServer $SmtpServer -BodyAsHtml $True -Body $Body} |