<#=========================================================================================================================== Script Name: GetServerUpdates.ps1 Description: Reports on the last date a patch was installed on servers. Inputs: List of server names fed from text file, one server name per line. Outputs: Report showing Server name, date and time patched, and how many days ago the server was patched. Notes: Example: .\GetServerUpdates.ps1 Author: Richard Wright Date Created: 11/3/2017 Credits: Last Revised: 7:44 AM 12/20/2017 ChangeLog: Date Who Description of changes 11/04/2017 RMW Added BG colors to highlight good, warning, critical days. 11/06/2017 RMW Added email notification. 12/06/2017 RMW Changed the querying processes 12/20/2017 RWM Aestetics, shared on Spiceworks ============================================================================================================================= Edit these with your preferences in the section following this one: $DateStamp = the format of dates shown in the report. $FileDateStamp = Appends yyyyMMdd to the Report File. $ServerList = File with the list of servernames for which to provide patch statistics; one per line. $ReportFileName = The outputted HTML filename and location $ReportTitle = Name of the report that is shown in the generated HTML file and in email subject. $EmailTo = Who should receive the report via email $EmailCc = Who should receive the report via email Cc: $EmailFrom = Sender email address $EmailSubject = Subject for the email $SMTPServer = SMTP server name $BGColorTbl = Background color for tables. $BGColorGood = Background color for "Good" results. #4CBB17 is green. $BGColorWarn = Background color for "Warning" results. #FFFC33 is yellow. $BGColorCrit = Background color for "Critical" results. #FF0000 is red. $Warning = # of days since last update to indicate Warning (Yellow) in report. Must be less than $Critical amount. $Critical = # of days since last update to indicate Critical (RED) in report. Must be more than $Warning amount. =============================================================================================================================#> $DateStamp = (Get-Date -Format D) $FileDateStamp = Get-Date -Format yyyyMMdd $ServerList = Get-Content "C:\Admin\ServerList.txt" $ScriptPath = Get-Location $ReportFileName = "$ScriptPath\ServerPatchReport-$FileDateStamp.html" $ReportTitle = "Server Patch Report" $EmailTo = "emailto@domain.com" #$EmailCc = "EmailCc@domain.com" $EmailFrom = "noreply@domain.com" $EmailSubject = "Server Patch Report for $DateStamp" $SMTPServer = "SMTPServerName" $BGColorTbl = "#EAECEE" $BGColorGood = "#4CBB17" $BGColorWarn = "#FFFC33" $BGColorCrit = "#FF0000" $Warning = 30 $Critical = 90 <#================================================== Do not edit below this section ==================================================#> Clear <#================================================== Begin MAIN ==================================================#> # Create output file and nullify display output New-Item -ItemType file $ReportFileName -Force > $null <#================================================== Write the HTML Header to the report file ==================================================#> Add-Content $ReportFileName "" Add-Content $ReportFileName "" Add-Content $ReportFileName "" Add-Content $ReportFileName "$ReportTitle" Add-Content $ReportFileName '" Add-Content $ReportFileName "" Add-Content $ReportFileName "" Add-Content $ReportFileName "" Add-Content $ReportFileName "" Add-Content $ReportFileName "" Add-Content $ReportFileName "" Add-Content $ReportFileName "" Add-Content $ReportFileName "" Add-Content $ReportFileName "" Add-Content $ReportFileName "" Add-Content $ReportFileName "" <#================================================== Function to write the HTML footer ==================================================#> Function writeHtmlFooter { param($FileName) Add-Content $FileName "
" Add-Content $ReportFileName "$ReportTitle
" Add-Content $ReportFileName "$DateStamp

" # Add color descriptions Add-content $ReportFileName "" Add-Content $ReportFileName "" Add-Content $ReportFileName "" Add-Content $ReportFileName "" Add-Content $ReportFileName "" Add-Content $ReportFileName "" Add-Content $ReportFileName "
Patched < $Warning DaysPatched $Warning - $Critical DaysPatched > $Critical Days
" # Add Column Headers Add-Content $ReportFileName "
Server NameLast Patch Date & TimeDays Since Last Patch
" Add-content $FileName "" Add-Content $FileName "" Add-Content $FileName "" Add-Content $FileName "" Add-Content $FileName "
Total Servers: $ServerCount
" Add-Content $FileName "" Add-Content $FileName "" } <#================================================== Function to write server update information to the HTML report file ==================================================#> Function writeUpdateData { param($FileName,$Server,$InstalledOn) Add-Content $FileName "" Add-Content $FileName "$Server" Add-Content $FileName "$InstalledOn" # Color BG depending on $Warning and $Critical days set in script If ($InstalledOn -eq "Error collecting data") { $DaySpanDays = "Error" } Else { $System = (Get-Date -Format "MM/dd/yyyy hh:mm:ss") $DaySpan = New-TimeSpan -Start $InstalledOn -End $System $DaySpanDays = $DaySpan.Days } If ($InstalledOn -eq "Error collecting data" -or $DaySpan.Days -gt $Critical) { # Red for Critical or Error retrieving data Add-Content $FileName "$DaySpanDays" Add-Content $FileName "" } ElseIf ($DaySpan.Days -le $Warning) { # Green for Good Add-Content $FileName "$DaySpanDays" Add-Content $FileName "" } Else { # Yellow for Warning Add-Content $FileName "$DaySpanDays" Add-Content $FileName "" } Add-Content $FileName "" } <#================================================== Query servers for their update history Try registry first, if error Get-Hotfix ==================================================#> Write-Host "Querying servers for installed updates..." -foreground "Yellow" $ServerCount = 0 ForEach ($Server in $ServerList) { Try { Write-host "Checking $Server..." $ServerCount++ $key = "SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\Results\Install" $keytype = [Microsoft.Win32.RegistryHive]::LocalMachine $RemoteBase = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($keytype,$Server) $regKey = $RemoteBase.OpenSubKey($key) $KeyValue = "" $KeyValue = $regkey.GetValue("LastSuccessTime") $InstalledOn = "" $InstalledOn = Get-Date $KeyValue -Format 'MM/dd/yyyy hh:mm:ss' } Catch { $ServerLastUpdate = (Get-HotFix -ComputerName $Server | Sort-Object -Descending -Property InstalledOn -ErrorAction SilentlyContinue | Select-Object -First 1) $InstalledOn = $ServerLastUpdate.InstalledOn } If ($InstalledOn -eq "") { $InstalledOn = "Error collecting data" } writeUpdateData $ReportFileName $Server $InstalledOn } Write-Host "Finishing report..." -ForegroundColor "Yellow" writeHtmlFooter $ReportFileName <#================================================== Send email ==================================================#> Write-Host "Sending email..." $BodyReport = Get-Content "$ReportFileName" -Raw $StopEmailLoop=$false [int]$RetryCount=0 Do { Try { Send-MailMessage -To $EmailTo ` -Subject $EmailSubject ` -From $EmailFrom ` -SmtpServer $SMTPServer ` -BodyAsHtml -Body $BodyReport ` -ErrorAction Stop; $StopEmailLoop = $true } Catch { If ($RetryCount -gt 5) { Write-Host "Cannot send email. The script will exit." $StopEmailLoop = $true } Else { Write-Host "Cannot send email. Will try again in 15 seconds..." Start-Sleep -Seconds 15 $RetryCount = $RetryCount+1 } } } While ($StopEmailLoop -eq $false)