Many companies rely on WSUS respective SUS services from Microsoft – aka. Windows Server Update Services as internal source and control of their update deployment to clients and servers within their network.
One of the big challenges for IT is to keep them clean and performant. The Cleanup-Assistant in the SUS management console tends to run forever and in any case means manual labor over and over again.
Below are two scripts – a CMD script that needs to be adjusted with parameters and a powershell script that will be called with those parameters. The scripts acutally will call the same API as the MMC Assistant does, just that this can be automatically performed via a scheduled task in Windows.
It helps you to keep your SUS slim and more performant.
In any way – I highly recommend to not blindly just enable all categories rather then limiting it to the once you have in place as well as once you reached a certain patch-level even actively denying updates you never will need again (keep in mind, new rolled out systems might still need older updates – but you could possibly refresh your base images or rely on Microsoft update services / online updates for those cases).
The combination of making updates obsolete and actually running a cleanup periodically will improve your SUS server performance.
As for the parameters, those are explained in the CMD script header – therefor I will not explain them here again.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | @echo off REM SUS - CleanUp Script REM Script start a Windows PowerShell Script that will acces the WSUS API and start a cleanup. REM All parameters are set in this file, there is no need to change the PS script. REM An email with results will be generated as well. REM ScriptPath: Path where this and the PS1 script resides REM Log: name of the logfile / shouldn't need to be adjusted REM PSLog: name of PS script logfile, shouldn't need to be adjusted REM CleanupScript: name of the PS1 script - you shouldn't need to adjust this REM SUSServerFQDN: FQDN/full DNS name of the SUS Server (hostname.dns.tld) REM SUSServerPort: Port-Number (80 / 443 / 8530 / 8531 - depending on your installation, check IIS if necessary) REM SUSContentDrive: Drive-Letter of the partition that holds the WSUS-Content ( C or D or E - without the : ) REM supersededUpdates: 1 or 0 => Decline updates that have not been approved for 30 days or more, are not currently needed by any clients, and are superseded by an aproved update. REM expiredUpdates: 1 or 0 => Decline updates that aren't approved and have been expired my Microsoft. REM obsoleteUpdates: 1 or 0 => Delete updates that are expired and have not been approved for 30 days or more. REM compressUpdates: 1 or 0 => Delete older update revisions that have not been approved for 30 days or more. REM obsoleteComputers: 1 or 0 => Delete computers that have not contacted the server in 30 days or more. REM unneededContentFiles: 1 or 0 => Delete update files that aren't needed by updates or downstream servers. REM SMTPServer: DNS-Name of the Mail-Server (hostname.dns.tld) REM MailFrom: Mail-Sender address REM MailTo: Mail-Recipient address REM ****** BEGIN Parameter Configuration ****** Set ScriptPath=C:\Batch\SUSCleanUp Set Log=%ScriptPath%\Logs\wsus-cleanup.log Set PSLog=%ScriptPath%\Logs\ps-cleanup.log Set CleanupScript=%ScriptPath%\SUSCleanUp.ps1 Set SUSServerFQDN=our-sus-server.domain.local Set SUSServerPort=8530 Set SUSContentDrive=D Set supersededUpdates=1 Set expiredUpdates=1 Set obsoleteUpdates=1 Set compressUpdates=1 Set obsoleteComputers=1 Set unneededContentFiles=1 Set SMTPServer=relay.domain.com Set MailFrom=administrator@domain.com Set MailTo=suslogfiles@domain.com REM ****** END Paremeter Configuration ****** REM CleanUp and PreRequirements MD %ScriptPath%\Logs 1>NUL 2>NUL REM DEL %Log% 1>NUL 2>NUL DEL %PSLog% 1>NUL 2>NUL REM Script Execution echo. >> "%log%" echo ############################################################ >> "%log%" echo. >> "%log%" echo Begin Cleanup Report %wsus-server-01% on %date% %time%: >> "%log%" echo ------------------------------------------------------------ >> "%log%" "%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe" "%cleanupscript% '%susserverfqdn%' '%pslog%' '%smtpserver%' '%mailfrom%' '%mailto%'" %supersededUpdates% %expiredUpdates% %obsoleteUpdates% %compressUpdates% %obsoleteComputers% %unneededContentFiles% %SUSContentDrive% %SUSServerPort% >> "%log%" echo ------------------------------------------------------------ >> "%log%" echo End Cleanup Report %wsus-server-01% on %date% %time%: >> "%log%" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | # WSUS Connection Parameters: [String]$WSUSServer = $args[0] [Boolean]$useSecureConnection = $False [Int32]$portNumber = $args[12] [String]$LogFile = $args[1] [String]$SMTPServer = $args[2] [String]$MailFrom = $args[3] [String]$MailTO = $args[4] [String]$SUSDrive = $args[11] [String]$WMIDiskSpaceRequest = "\\" + $WSUSServer + "\root\cimv2:Win32_logicalDisk.DeviceID='" + $SUSDrive + ":'" # Windows PowerShell example to check 'If File Exists' #$FileExists = Test-Path $LogFile #If ($FileExists -eq $True) { #Delete old LogFiles # Remove-Item $LogFile #} # Cleanup Parameters: # Decline updates that have not been approved for 30 days or more, are not currently needed by any clients, and are superseded by an aproved update. [Boolean]$supersededUpdates = $True If ($args[5] = 0) { $supersededUpdates = $False } # Decline updates that aren't approved and have been expired my Microsoft. [Boolean]$expiredUpdates = $True If ($args[6] = 0) { $expiredUpdates = $False } # Delete updates that are expired and have not been approved for 30 days or more. [Boolean]$obsoleteUpdates = $True If ($args[7] = 0) { $obsoleteUpdates = $False } # Delete older update revisions that have not been approved for 30 days or more. [Boolean]$compressUpdates = $True If ($args[8] = 0) { $compressUpdates = $False } # Delete computers that have not contacted the server in 30 days or more. [Boolean]$obsoleteComputers = $True If ($args[9] = 0) { $obsoleteComputers = $False } # Delete update files that aren't needed by updates or downstream servers. [Boolean]$unneededContentFiles = $True If ($args[10] = 0) { $unneededContentFiles = $False } #EndRegion VARIABLES #Region SCRIPT # Load .NET assembly [void][reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration"); # Connect to WSUS Server $wsusParent = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer($WSUSServer,$useSecureConnection,$portNumber); # Log the date first "Microsoft SUS Server CleanUp" | out-file -filepath $LogFile -append -noClobber; $date = date $info = "Start Date / Time: " + $date $info | out-file -filepath $LogFile -append -noClobber; # Log the SUS Server Name $info = "Microsoft SUS Server Name: " + $WSUSServer $info | out-file -filepath $LogFile -append -noClobber; "" | out-file -filepath $LogFile -append -noClobber; # Log Current Free DiskSpace $diskbefore = ([wmi]$WMIDiskSpaceRequest) "Free disk space before cleanup:" | out-file -filepath $LogFile -append -noClobber; "Drive " + $SUSDrive + ": has {0:#.0} GB free of {1:#.0} GB Total" -f ($diskbefore.FreeSpace/1GB),($diskbefore.Size/1GB) | out-file -filepath $LogFile -append -noClobber; "" | out-file -filepath $LogFile -append -noClobber; # Perform Cleanup "Microsoft SUS Server CleanUp Results" | out-file -filepath $LogFile -append -noClobber; "====================================" | out-file -filepath $LogFile -append -noClobber; "" | out-file -filepath $LogFile -append -noClobber; $CleanupManager = $wsusParent.GetCleanupManager(); "CleanUp: supersededUpdates = " + $supersededUpdates | out-file -filepath $LogFile -append -noClobber; "----------------------------------" | out-file -filepath $LogFile -append -noClobber; date | out-file -filepath $LogFile -append -noClobber; $CleanupScope_supersededUpdates = New-Object Microsoft.UpdateServices.Administration.CleanupScope($supersededUpdates,$False,$False,$False,$False,$False); $CleanupManager.PerformCleanup($CleanupScope_supersededUpdates) | out-file -filepath $LogFile -append -noClobber; "" | out-file -filepath $LogFile -append -noClobber; "CleanUp: expiredUpdates = " + $expiredUpdates | out-file -filepath $LogFile -append -noClobber; "---------------------------------------" | out-file -filepath $LogFile -append -noClobber; date | out-file -filepath $LogFile -append -noClobber; $CleanupScope_expiredUpdates = New-Object Microsoft.UpdateServices.Administration.CleanupScope($False,$expiredUpdates,$False,$False,$False,$False); $CleanupManager.PerformCleanup($CleanupScope_expiredUpdates) | out-file -filepath $LogFile -append -noClobber; "" | out-file -filepath $LogFile -append -noClobber; "CleanUp: obsoleteUpdates = " + $obsoleteUpdates | out-file -filepath $LogFile -append -noClobber; "---------------------------------------" | out-file -filepath $LogFile -append -noClobber; date | out-file -filepath $LogFile -append -noClobber; $CleanupScope_obsoleteUpdates = New-Object Microsoft.UpdateServices.Administration.CleanupScope($False,$False,$obsoleteUpdates,$False,$False,$False); $CleanupManager.PerformCleanup($CleanupScope_obsoleteUpdates) | out-file -filepath $LogFile -append -noClobber; "" | out-file -filepath $LogFile -append -noClobber; "CleanUp: compressUpdates = " + $compressUpdates | out-file -filepath $LogFile -append -noClobber; "---------------------------------------" | out-file -filepath $LogFile -append -noClobber; date | out-file -filepath $LogFile -append -noClobber; $CleanupScope_compressUpdates = New-Object Microsoft.UpdateServices.Administration.CleanupScope($False,$False,$False,$compressUpdates,$False,$False); $CleanupManager.PerformCleanup($CleanupScope_compressUpdates) | out-file -filepath $LogFile -append -noClobber; "" | out-file -filepath $LogFile -append -noClobber; "CleanUp: obsoleteComputers = " + $obsoleteComputers | out-file -filepath $LogFile -append -noClobber; "---------------------------------------" | out-file -filepath $LogFile -append -noClobber; date | out-file -filepath $LogFile -append -noClobber; $CleanupScope_obsoleteComputers = New-Object Microsoft.UpdateServices.Administration.CleanupScope($False,$False,$False,$False,$obsoleteComputers,$False); $CleanupManager.PerformCleanup($CleanupScope_obsoleteComputers) | out-file -filepath $LogFile -append -noClobber; "" | out-file -filepath $LogFile -append -noClobber; "CleanUp: unneededContentFiles = " + $unneededContentFiles | out-file -filepath $LogFile -append -noClobber; "---------------------------------------" | out-file -filepath $LogFile -append -noClobber; date | out-file -filepath $LogFile -append -noClobber; $CleanupScope_unneededContentFiles = New-Object Microsoft.UpdateServices.Administration.CleanupScope($False,$False,$False,$False,$False,$unneededContentFiles); $CleanupManager.PerformCleanup($CleanupScope_unneededContentFiles) | out-file -filepath $LogFile -append -noClobber; "" | out-file -filepath $LogFile -append -noClobber; # Log Current Free DiskSpace $diskafter = ([wmi]$WMIDiskSpaceRequest) "Free disk space after cleanup:" | out-file -filepath $LogFile -append -noClobber; "Drive " + $SUSDrive + ": has {0:#.0} GB free of {1:#.0} GB Total" -f ($diskafter.FreeSpace/1GB),($diskafter.Size/1GB) | out-file -filepath $LogFile -append -noClobber; "" | out-file -filepath $LogFile -append -noClobber; # Log the date after $date = date $info = "End Date / Time: " + $date $info | out-file -filepath $LogFile -append -noClobber; #EndRegion SCRIPT # Source: http://gallery.technet.microsoft.com/scriptcenter/90ca6976-d441-4a10-89b0-30a7103d55db#content # Mail the report... $message = new-object Net.Mail.MailMessage $mailer = new-object Net.Mail.SmtpClient($SMTPServer) $message.From = $MailFrom #"Sender <Sender@Domain.TLD>" $message.To.Add($MailTo) #("Recipient <Recipient@Domain.TLD>") $MeinText = "WSUS - Server CleanUp Report " + $WSUSServer $message.Subject = $MeinText $message.Body = [string]::join([environment]::NewLine, (get-content $logfile)) $mailer.Send($message) #Delete Log => will happen at the next run #Remove-Item $LogFile |