2013-07-16

WSUS Clean Up Automatically (伺服器清理精靈)

WSUS 自 3.0 版起有【伺服器清理精靈】的功能, 可以清除已經過期或不再使用的 HotFix
預設在 MMC 中執行
Update Services】->【(Server Name)】->【選項】->【伺服器清理精靈

這個功能很棒, 但手動執行實在很不方便, 還好在 Microsoft TechNet 上找到了這個 PowerShell
WSUS Server Cleanup against parent server and All downstream servers



  • 2015.09.08 Update:
    原本的 Script 在 Windows Server 2012 R2 的 WSUS 報表是空的, 但有 PowerShel Command 可以直接做了

  • 2018.01.19  Update:
    先前的 Command 在 DB 長大後常常會 Timeout 失敗, 修改一下執行方式並加入 Transcript Log


2018.01.19 Update

只要把內容中的 #E-mail Configuration 段落設定好, 然後定時跑即可
觸發動作程式要用 PowerShell
"%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe"

===== 程式開始 =====

# Variablen
$DateFormat = Get-Date -format yyyyMMdd_HHmm
$Logfile = (Get-Item -Path ".\" -Verbose).FullName + "\" + ("WSUS Clean Up " + $DateTimeString + ".log")

start-transcript -path $TranscriptLog

# WSUS CleanUp Command Start

do {
$Result = Invoke-WsusServerCleanup -CleanupObsoleteUpdates
write-host $Result
} while ($Result -ne 'Obsolete Updates Deleted:0')

do {
$Result = Invoke-WsusServerCleanup -CleanupUnneededContentFiles
write-host $Result
} while ($Result -ne 'Diskspace Freed:0')

do {
$Result = Invoke-WsusServerCleanup -CompressUpdates
write-host $Result
} while ($Result -ne 'Updates Compressed:0')

do {
$Result = Invoke-WsusServerCleanup -DeclineExpiredUpdates
write-host $Result
} while ($Result -ne 'Expired Updates Declined: 0')

do {
$Result = Invoke-WsusServerCleanup -DeclineSupersededUpdates
write-host $Result
} while ($Result -ne 'Obsolete Updates Deleted:0')

# WSUS CleanUp Command End

stop-transcript

# Mail Variablen
$MailSMTPServer = "smtp.contoso.com"
$MailFrom = "wsus@contoso.com"
$MailTo = "admin@contoso.com"
$MailSubject = "WSUS Server Cleanup $DateFormat - ${env:COMPUTERNAME}"
$MailBody = Get-Content $Logfile | Out-String

# Mail versenden
Send-MailMessage -SmtpServer $MailSMTPServer -From $MailFrom -To $MailTo -subject $MailSubject -body $MailBody -Encoding Unicode

Remove-Item $Logfile

===== 程式結束 =====



2015.09.08 Update: 存成 .ps1 直接跑就可以了, 預設報表沒有精美表格, 但資訊足夠

===== 程式開始 =====

# Variablen
$DateFormat = Get-Date -format yyyyMMdd_HHmm
$Logfile = "WSUS-CleanUp-Temp.log"

# WSUS CleanUp Command
Invoke-WsusServerCleanup -CleanupObsoleteUpdates -CleanupUnneededContentFiles -CompressUpdates -DeclineExpiredUpdates -DeclineSupersededUpdates | Out-File $Logfile

# Mail Variablen
$MailSMTPServer = "smtp.contoso.com"
$MailFrom = "wsus@contoso.com"
$MailTo = "admin@contoso.com"
$MailSubject = "WSUS Server Cleanup $DateFormat - ${env:COMPUTERNAME}"
$MailBody = Get-Content $Logfile | Out-String

# Mail versenden
Send-MailMessage -SmtpServer $MailSMTPServer -From $MailFrom -To $MailTo -subject $MailSubject -body $MailBody -Encoding Unicode

Remove-Item $Logfile

===== 程式結束 =====

以下為舊版 Script

===== 程式開始 =====

#Upstream WSUS server to cleanup and retrieve downstream servers to cleanup
$WsusUpstreamServer = "wsus.company.com"
$UseSSL = $false
$PortNumber = 80
$TrialRun = $false

#E-mail Configuration
$SMTPServer = "smtp.company.com"
$FromAddress = "wsus@company.com"
$Recipients = "wsusadmins@company.com"
$MessageSubject = "WSUS Server Cleanup."

#HTML variables referenced during the script for output formatting
$sHTMLCellStyle = "`r`n<td style=`"font-family: Verdana, sans-serif; font-size: 11px; color: navy`">"
$sHTMLHeadingStyle = "`r`n<th style=`"font-family: Verdana, sans-serif; font-size: 12px; color: navy`">"
$sHtmlTableStyle = "`r`n<table border=`"1`", cellpadding=`"10`", cellspacing=`"0`", TABLE BORDER WIDTH=`"75%`">"
$sHTMLParagraphStyle = "`r`n<p style=`"font-family: Verdana, sans-serif; font-size: 12px; color: navy`">"

$global:MessageBody = "$sHtmlTableStyle <tr>$sHTMLHeadingStyle WSUS Server</th>$sHTMLHeadingStyle Parent WSUS Server</th>$sHTMLHeadingStyle WSUS Version</th>$sHTMLHeadingStyle Start</th>$sHTMLHeadingStyle Finish</th>$sHTMLHeadingStyle Superseded Updates Deleted</th>$sHTMLHeadingStyle Expired Updates Declined</th>$sHTMLHeadingStyle Obsolete Updates Deleted</th>$sHTMLHeadingStyle Updates Compressed</th>$sHTMLHeadingStyle Obsolete Computers Deleted</th>$sHTMLHeadingStyle Disk Space Freed (MB)</th></tr>"

Function SendEmailStatus
{
$SMTPMessage = New-Object System.Net.Mail.MailMessage $FromAddress, $Recipients, $MessageSubject, $MessageBody
$SMTPMessage.IsBodyHTML = $true
#Send the message via the local SMTP Server
$SMTPClient = New-Object System.Net.Mail.SMTPClient $SMTPServer
$SMTPClient.Send($SMTPMessage)
$SMTPMessage.Dispose()
rv SMTPClient
rv SMTPMessage
}

Function PerformCleanup($WsusServer, $ParentWsusServer)
{
$errorActionPreference = "SilentlyContinue"
$Start = Get-Date
Write-Host "-------------------------"
Write-Host "Upstream Server: $ParentWsusServer"
Write-Host "Downstream Server: $WsusServer"
Write-Host "Started processing $WsusServer at $Start"
$Error.Clear()
$WsusServerAdminProxy = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($WsusServer,$UseSSL,$PortNumber);
If ($? -eq $False)
{
$sTemp = $sHTMLCellStyle.Replace("<td", "<td colspan=9"); $sTemp = $sTemp.Replace("navy", "red")
switch ($UseSSL)
{
$true {$global:MessageBody += "`r`n<tr>$sHTMLCellStyle $WsusServer</td>$sHTMLCellStyle $ParentWsusServer</td>$sTemp <b> Something went wrong connecting to the WSUS interface on $WsusServer using Port $PortNumber with SSL: <br> `r`n $Error</b></td></tr>"}
$false {$global:MessageBody += "`r`n<tr>$sHTMLCellStyle $WsusServer</td>$sHTMLCellStyle $ParentWsusServer</td>$sTemp <b> Something went wrong connecting to the WSUS interface on $WsusServer using Port $PortNumber without SSL: <br> `r`n $Error</b></td></tr>"}
}
Write-Warning "Something went wrong connecting to the WSUS interface on $WsusServer server"
}
Else
{
Write-Host "Connected to the AdminProxy on $WsusServer"
$CleanupManager = $WsusServerAdminProxy.GetCleanupManager();
Write-Host "Connected to the CleanupManager on $WsusServer"
Write-Host "Calling PerformCleanup on $WsusServer"
If ($TrialRun)
{$Finish = Get-Date; $global:MessageBody += "`r`n<tr>$sHTMLCellStyle $WsusServer</td>$sHTMLCellStyle $ParentWsusServer</td>$sHTMLCellStyle " + $WsusServerAdminProxy.Version + "</td>$sHTMLCellStyle $Start</td>$sHTMLCellStyle $Finish</td>$sHTMLCellStyle Trial Run</td>$sHTMLCellStyle Trial Run</td>$sHTMLCellStyle Trial Run</td>$sHTMLCellStyle Trial Run</td>$sHTMLCellStyle Trial Run</td>$sHTMLCellStyle Trial Run</td></tr>"}
Else
{$CleanupResults = $CleanupManager.PerformCleanup($CleanupScope);
$Finish = Get-Date; $global:MessageBody += "`r`n<tr>$sHTMLCellStyle $WsusServer</td>$sHTMLCellStyle $ParentWsusServer</td>$sHTMLCellStyle " + $WsusServerAdminProxy.Version + "</td>$sHTMLCellStyle $Start</td>$sHTMLCellStyle $Finish</td>$sHTMLCellStyle" + $CleanupResults.SupersededUpdatesDeclined + "</td>$sHTMLCellStyle" + $CleanupResults.ExpiredUpdatesDeclined + "</td>$sHTMLCellStyle" + $CleanupResults.ObsoleteUpdatesDeleted + "</td>$sHTMLCellStyle" + $CleanupResults.UpdatesCompressed + "</td>$sHTMLCellStyle" + $CleanupResults.ObsoleteUpdatesDeleted + "</td>$sHTMLCellStyle" + [math]::truncate($CleanupResults.DiskSpaceFreed/1MB) + "</td></tr>"}
Write-Host "Finished processing $WsusServer at $Finish"
$WsusDownstreamServers = $WsusServerAdminProxy.GetDownstreamServers()
If ($WsusDownstreamServers.Count -gt 0)
{
Write-Host "-------------------------"
Write-Host "Cleaning up downstream servers..."
$WsusDownstreamServers | %{$WsusDownstreamServer = ($_.FullDomainName).ToLower(); PerformCleanup $WsusDownstreamServer $WsusServer}
}
}
}

#Connect to the WSUS 3.0 interface.
[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | out-null
$errorActionPreference = "Continue"
$Error.Clear()
$WsusUpstreamServerAdminProxy = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($WsusUpstreamServer,$UseSSL,$PortNumber);
If ($? -eq $False)
{
$MessageBody = ""
$sHTMLCellStyle = $sHTMLCellStyle.Replace("navy", "red")
  switch ($UseSSL)
{
$true {$MessageBody = "$sHtmlTableStyle `r`n<tr>$sHTMLCellStyle <b> Something went wrong connecting to the WSUS interface on $WsusServer using Port $PortNumber with SSL: <br> `r`n $Error</b></td></tr></table>"}
$false {$MessageBody = "$sHtmlTableStyle `r`n<tr>$sHTMLCellStyle <b> Something went wrong connecting to the WSUS interface on $WsusServer using Port $PortNumber without SSL: <br> `r`n $Error</b></td></tr></table>"}
}
Write-Warning "Something went wrong connecting to the WSUS interface on $WsusUpstreamServer upstream server"
SendEmailStatus
Exit
}
Else
{
Write-Host "-------------------------"
Write-Host "Connected to upstream WSUS server $WsusUpstreamServer"
$CleanupScope = New-Object Microsoft.UpdateServices.Administration.CleanupScope;
$CleanupScope.CleanupObsoleteComputers = $true
$CleanupScope.CleanupObsoleteUpdates = $true
$CleanupScope.CleanupUnneededContentFiles = $true
$CleanupScope.CompressUpdates = $true
$CleanupScope.DeclineExpiredUpdates = $true
$CleanupScope.DeclineSupersededUpdates = $true
PerformCleanup $WsusUpstreamServer "--"
$MessageBody += "</table>"
SendEmailStatus
}

===== 程式結束 =====

5 則留言:

  1. 請問有個疑問,就是我所清理掉的package,我該怎樣去驗證說這些確定就是被expire的package...謝謝!

    回覆刪除
  2. 這個 Power Shell 只是執行跟 GUI 介面中清理精靈相同的處理程序而已,驗證可以自行從更新清單中做紀錄,執行完後去比對。或者可以找找微軟的 KB 有沒有提到,我是覺得沒什麼好驗證的啦。

    回覆刪除
  3. 那我有辦法可以用powershell去直接比對WSUS裡面的KB嗎?我有一份用powershell弄出來的txt,裡面都是KB,該如何去跟WSUS比對說,這個KB我的WSUS到底有沒有去執行...感謝指導!

    回覆刪除
    回覆
    1. 比對這種事情我覺得應該要用 Excel 啦。
      至於你說的我沒有做過也沒有這種需求所以不知道,如果你有找到解答請務必分享給我 m(_ _)m

      刪除
  4. 因為我也不知道怎樣用powershell去WSUSserver撈資料.不然我就可以去做雙方比對

    回覆刪除