PS: WSUS Reporting an Chef

Moin,

auch wieder so ein Ding, das mich lange Beschäftigt hat. Grundlage für das Script kommt aus dem Technet. Auftrag vom Chef war klar, er möchte ein Reporting, das aktueller bzw. genauer ist als das was der WSUS an Reporting bietet. Soweit ist klar, dass man dafür an jeden Server ran muss. Mein Chef möchte monatlich wissen, wann die Server neugestartet sind, welche Server noch Updates ausstehen haben usw.

Meine Anforderung war, dass es hübscher als eine Plaintext Mail sein sollte (html). Im Laufe des Lösens war dann klar das wir 2 Datenquellen anbei haben sollten: eine CSV mit dem Status aller Server und eine die direkt gefiltert nur Server beinhaltet, die einen Neustart brauchen bzw. ausstehenden Updates haben. Nun kommt der unschöne Part, bei mehr als 300 Servern mochte die Powershell die Daten so gar nicht über Variablen austauschen, in sofern einiges an Export und Import. Des weiteren stellte sich heraus, dass die Standardfirewallregeln der Server eine Abfrage nicht zuließen, deswegen wird eine Textdatei erstellt, für die man das Firewallscript (nachfolgend) einmal durchlaufen lässt (dieses erstellt die benötigte Firewallregel). Wenn die lokale Firewall nicht an ist, um so besser. Dann gibt es aber noch Server die andere Fehler haben (keine WSUS Richtlinie, etc), diese kommen dann in die andere Textdatei. Wie immer, am ende alles via Mail an den Chef und zur Kontrolle an mich. Läuft jeden 01. irgendwann nachts und hat dann nach rund 1 -2 Stunden Laufzeit alle Daten morgens um 7h fertig 🙂 (Wir filtern die Citrix Server heraus, weil das nur falsche Ergebnisse liefern würde)

#########################################################
# #
# Monitoring Windows Updates and Pending Restarts #
# #
#########################################################
### Needs installed Feature: Acitve Directory Module for Powershell
#########################################################
# List of computers to be monitored
#########################################################
$servers = Get-ADComputer -LDAPFilter „(&(objectcategory=computer)(OperatingSystem=*Windows Server*))“ | Sort-Object DNSHostName
$x = $servers | where{$_.DistinguishedName -notlike „*Citrix*“} |foreach {$_.DNSHostName}
$servers = $x

$datum = get-date -format d
$localecomputa = $env:computername + „.“ + $env:userdnsdomain

#########################################################
# SMTP properties
#########################################################
$servername = $env:computername
$mailto = „chef@firma.tld“
$mailcopyto = „Admin@firma.tld“
$emailFrom = $servername + „@firma.tdl“
$smtpServer = „Mailserver.firma.tld“ #SMTP Server.
$mailSubject = „Windows Update Compliance | SERVER | “ + $datum
########################################################
$results = foreach ($Computer in $Servers)
{
try
{
$service = Get-WmiObject Win32_Service -Filter ‚Name=“wuauserv“‚ -ComputerName $Computer -Ea 0
$WUStartMode = $service.StartMode
$WUState = $service.State
$WUStatus = $service.Status

try{
if (Test-Connection -ComputerName $Computer -Count 1 -Quiet)
{
#check if the server is the same where this script is running
if($Computer -eq $localecomputa)
{
$UpdateSession = New-Object -ComObject Microsoft.Update.Session
}
else { $UpdateSession = [activator]::CreateInstance([type]::GetTypeFromProgID(„Microsoft.Update.Session“,$Computer)) }
$UpdateSearcher = $UpdateSession.CreateUpdateSearcher()
$SearchResult = $UpdateSearcher.Search(„IsAssigned=1 and IsHidden=0 and IsInstalled=0“)
$Critical = $SearchResult.updates | where { $_.MsrcSeverity -eq „Critical“ }
$important = $SearchResult.updates | where { $_.MsrcSeverity -eq „Important“ }
$other = $SearchResult.updates | where { $_.MsrcSeverity -eq $null }
# Get windows updates counters
$totalUpdates = $($SearchResult.updates.count)
$totalCriticalUp = $($Critical.count)
$totalImportantUp = $($Important.count)

if($totalUpdates -gt 0)
{
$updatesToInstall = $true
}
else { $updatesToInstall = $false }
}
else
{
# if cannot connected to the server the updates are listed as not defined

$totalUpdates = „No Connection“
$totalCriticalUp = „No Connection“
$totalImportantUp = „No Connection“
}
}
catch
{
# if an error occurs the updates are listed as not defined
if ($error[0].Exception -like „*800706ba*“){
$computer >> c:\temp\800706ba.txt
}
else {
$computer >> c:\temp\andererfehler.txt
}
Write-Warning „$Computer`: $_“
$totalUpdates = „error“
$totalCriticalUp = „error“
$totalImportantUp = „error“
$updatesToInstall = $false
}

# Querying WMI for build version
$WMI_OS = Get-WmiObject -Class Win32_OperatingSystem -Property LastBootUpTime,BuildNumber, CSName -ComputerName $Computer -Authentication PacketPrivacy -Impersonation Impersonate

#Querying last boot time
$WMI_Boot = $WMI_OS.ConvertToDateTime($WMI_OS.LastBootUpTime)

# Making registry connection to the local/remote computer
$RegCon = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]“LocalMachine“,$Computer)

# If Vista/2008 & Above query the CBS Reg Key
If ($WMI_OS.BuildNumber -ge 6001)
{
$RegSubKeysCBS = $RegCon.OpenSubKey(„SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\“).GetSubKeyNames()
$CBSRebootPend = $RegSubKeysCBS -contains „RebootPending“
}
else{
$CBSRebootPend = $false
}

# Query WUAU from the registry
$RegWUAU = $RegCon.OpenSubKey(„SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\“)
$RegSubKeysWUAU = $RegWUAU.GetSubKeyNames()
$WUAURebootReq = $RegSubKeysWUAU -contains „RebootRequired“

If($CBSRebootPend –OR $WUAURebootReq)
{
$machineNeedsRestart = $true
}
else
{
$machineNeedsRestart = $false
}

# Closing registry connection
$RegCon.Close()

#Alle Ergebnisse

New-Object PSObject -Property @{
„Letzter Reboot“ = $WMI_Boot
„Abfragedatum“ = $datum
„Servername“ = $WMI_OS.CSName
„WU Dienst“ = $WUStartMode
„Austehende Installationen“ = $updatesToInstall
„Austehende Insgesamt“ = $totalUpdates
„Kritische Updates“ = $totalCriticalUp
„Neustart Austehend“ = $machineNeedsRestart
}

}
Catch
{
Write-Warning „$Computer`: $_“
}
}
$results | export-csv -path c:\temp\windowsupdateall.csv -NoTypeInformation

########################
# Und alles wieder importieren und filtern
########################
$servers = Import-CSV c:\temp\windowsupdateall.csv -header („Servername“,“totalCriticalUp“,“machineNeedsRestart“,“WUStartMode“,“totalUpdates“,“reBoot“,“Abfragedatum“,“updatesToInstall“)

$resultsfiltered = foreach ($server in $servers)

{
if(($server.machineNeedsRestart -eq „true“) -or ($server.updatesToInstall -eq „true“) -or ($server.WUStartMode -eq „Manual“) -or ($server.totalUpdates -eq „nd“))
{
New-Object PSObject -Property @{
„Servername“ = $server.Servername
„WU Dienst“ = $server.WUStartMode
„Austehende Installationen“ = $server.updatesToInstall
„Austehende Insgesamt“ = $server.totalUpdates
„Kritische Updates“ = $server.totalCriticalUp
„Neustart Austehend“ = $server.machineNeedsRestart
„Letzter Reboot“ = $server.reBoot
„Abfragedatum“ = $datum
}
}
}

$resultsfiltered | export-csv -path c:\temp\windowsupdatefiltered.csv -NoTypeInformation
#########################################################
# Formating result
#########################################################
$tableFragment = $resultsfiltered | ConvertTo-HTML -fragment

# HTML Format for Output
$HTMLmessage = @“
<font color=““black““ face=““Arial““ size=““3″“>
<h1 style=’font-family:arial;‘><b>Windows Updates und Austehende Neustarts Bericht</b></h1>
<p style=’font: .8em „“Lucida Grande““, Tahoma, Arial, Helvetica, sans-serif;‘>This report was generated because the server(s) listed below have Windows Updates ready to be installed, Windows Updates configured to be checked manually or servers that required a reboot. Servers that do not fall under these conditions will not be listed.</p>
<br><br>
<style type=““text/css““>body{font: .8em „“Lucida Grande““, Tahoma, Arial, Helvetica, sans-serif;}
ol{margin:0;}
table{width:80%;}
thead{}
thead th{font-size:120%;text-align:left;}
th{border-bottom:2px solid rgb(79,129,189);border-top:2px solid rgb(79,129,189);padding-bottom:10px;padding-top:10px;}
tr{padding:10px 10px 10px 10px;border:none;}
middle{background-color:#900;}
</style>
<body BGCOLOR=““white““>
$tableFragment
</body>
„@
#########################################################
# Validation and sending email
#########################################################
# Regular expression to get what’s inside of <td>’s
$regexsubject = $HTMLmessage
$regex = [regex] ‚(?im)<td>‘

$Attachments = @(get-childitem „c:\temp\windowsupdat*.csv“)

Send-MailMessage -to $mailto -CC $mailcopyto -Subject $mailSubject -Smtpserver $smtpServer -Body $HTMLmessage -from $emailFrom -Attachments $Attachments -Bodyashtml

del -Force c:\temp\windowsupdat*.csv

Und das benötige Firewallscript: (benötigt PSexec aus den Sysinternaltools)

$computers = get-content c:\temp\800706ba.txt

foreach ($computer in $computers)
{
c:\Scripte\psexec \\$computer netsh advfirewall firewall add rule name=“RPCIn“ dir=in action=allow edge=no remoteip=any protocol=TCP localport=RPC
$error[0].Exception > errorlist.txt
}

 

Fragen gerne in die Kommentare.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.