Powershell: WMI Timeouts locking up scripts
There are a few folks with suggestions out there. One is to use a job to run the query. Unfortunately this leaves those jobs stuck out there so if a lot of my servers have WMI screwed up I suppose doing this could crash my management machine.
This example is to get the current time and time zone from every server machine in my AD domain.
##########################################################################################
# CHECK-TIME.PS1
#
# Gather local time and time zone for all servers in AD. Convert times to GMT & compare
# Report servers with time different from machine on which script is run
# E-Mail report to designated recipient.
#
##########################################################################################
# E-Mail Recipient
$recipient="user@domain.com"
# Greatest acceptable time difference
$maxdiff=59
$outfile = "c:\dev\check-time.html"
If (Test-Path $outfile){
Remove-Item $outfile
}
$logfile = "c:\dev\check-time.log"
If (Test-Path $logfile){
Remove-Item $logfile
}
$mytimezone = get-wmiobject Win32_Computersystem -property CurrentTimeZone, daylightineffect
$myoffset = $mytimezone.CurrentTimeZone #GMT offset in minutes
$mydst = $mytimezone.daylightineffect
if ($mydst) {
$myoffset+=60
}
##########################################################################################
# FUNCTION: Check for TCP response on $port
function Test-Port {
Param(
[string] $srv,
$port=135,
$timeout=1500,
[switch]$verbose
)
# TCP connect $port
$ErrorActionPreference = "SilentlyContinue"
$tcpclient = new-Object system.Net.Sockets.TcpClient
$iar = $tcpclient.BeginConnect($srv,$port,$null,$null)
$wait = $iar.AsyncWaitHandle.WaitOne($timeout,$false)
# Check to see if the connection is done
if(!$wait)
{
# Close connection, report timeout
$tcpclient.Close()
if($verbose){write-host "Connection Timeout" }
Return $false
}
else
{
# Close connection, report any error
$error.Clear()
$tcpclient.EndConnect($iar) | out-Null
if(!$?){if($verbose){write-host $error[0]};$failed = $true}
$tcpclient.Close()
}
# Return $true if connection established
if($failed){
return $false
} else {
return $true
}
} # http://technet.microsoft.com/en-us/library/ff730959.aspx
#
# End of functions
##########################################################################################
############################################################################################
# Create $list of server names for all Windows servers in Active Directory
#
$strCategory = "computer"
$strOS = "Windows*Server*"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.Filter = ("OperatingSystem=$strOS")
$colProplist = "dnshostname"
foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
$colResults = $objSearcher.FindAll()
foreach ($objResult in $colResults)
{
$objComputer = $objResult.Properties;
$Server = $objComputer.dnshostname
$Server = $Server -replace "\s{2,}", ""
$Server = $Server -replace "\.usa\.domain\.com", ""
if ($Server) { $list = $list + $Server } #skip a null value
}
$list = $list | sort-object
###
clear-host
$today = get-date
############################################################################################
# Report Heading
$report=@'
Server Time Issues
'@
$report+=$today
$report+="
Server | Date | Time | Off(s) | Time Zone | "
############################################################################################
# Query every server in list
foreach ($result in $list) {
$flag=" "
$timezone=""
$dt=""
$srvtime=""
$hour = ""
$min = ""
$sec = ""
$comp = ""
$d = ""
$t = ""
$computer = $result
$comp = "{0,-16}" -f $computer
$comp = $comp.padright(16," ")
#write-host ("$Computer"+":")
#("$Computer"+":")|out-file $logfile -append
If (Test-Connection -computername $computer -Quiet -count 1){ #respond to ping?
$a = Test-Port $computer
$dst=""
$timezone=""
$output=""
$offset=""
if ($a) { # resonds on RPC?
#timezone
$block = "get-wmiobject Win32_Computersystem -computer $computer -property CurrentTimeZone, daylightineffect"
$sb = [scriptblock]::create($block)
start-job -name $computer $sb > $null
Wait-Job -name $computer -Timeout 10 > $null
$output = Receive-Job $computer
$block = "Get-WmiObject -class Win32_TimeZone -ComputerName $computer"
$sb = [scriptblock]::create($block)
start-job -name $computer $sb > $null
Wait-Job -name $computer -Timeout 10 > $null
$timezonedesc = Receive-Job $computer
$tz = $timezonedesc.description
if ($output -ne $null) {
$timezone = $output
$offset = $timezone.CurrentTimeZone #GMT offset in minutes
$dst = $timezone.daylightineffect
if ($dst) {
$offset+=60
}
}
else {
write-host "$computer`tERROR: No WMI Query Output"
"$computer`tERROR: No WMI Query Output" | out-file $logfile -append
$report+='' + $comp + ' | '
$report+='' + "WMI ERROR - No response to timezone query" + ' | '
$report+='
'
continue
}#end if output
#date/time
$block = "Get-WmiObject -class win32_localtime -ComputerName $computer"
$sb = [scriptblock]::create($block)
start-job -name $computer $sb > $null
Wait-Job -name $computer -Timeout 10 > $null
$output = Receive-Job $computer
if ($output -ne $null) {
$dt = $output
}
else {
write-host "$computer`tERROR: No WMI Query Output"
"$computer`tERROR: No WMI Query Output" | out-file $logfile -append
$report+='' + $comp + ' | '
$report+='' + "WMI ERROR - No response to date/time query" + ' | '
$report+='
'
continue
} # end if output
}#end if port
else {# No response on port
write-host "$computer`tERROR: No RPC Response"
"$computer`tERROR: No RPC Response" | out-file $logfile -append
$report+='' + $comp + ' | '
$report+='' + "RPC ERROR - No response on port " + $port + ' | '
$report+='
'
continue
}
}#end if ping
else { # No PING response
write-host "$computer`tERROR: No PING Response"
"$computer`tERROR: No PING Response" | out-file $logfile -append
$report+='' + $comp + ' | '
$report+='' + "CONNECTION ERROR: No response to PING" + ' | '
$report+='
'
continue
}
[string] $month = [System.Convert]::ToString($dt.Month)
[string] $day = [System.Convert]::ToString($dt.Day)
[string] $year = [System.Convert]::ToString($dt.Year)
[string] $hour = [System.Convert]::ToString($dt.Hour)
$hour = $hour.padleft(2,"0")
[string] $min = [System.Convert]::ToString($dt.Minute)
$min = $min.padleft(2,"0")
[string] $sec = [System.Convert]::ToString($dt.Second)
$sec = $sec.padleft(2,"0")
$d = $month + "/" + $day + "/" + $year
$t = $hour + ":" + $min + ":" + $sec
if ($dt) { #$dt not null
#convert to object
$dObj = get-date "$d $t"
#adjust to GMT
$srvtime=$dObj.addminutes(-$offset)
#write-host " $computer time=$srvtime"
#" $computer time=$srvtime" | out-file $logfile -append
$now = get-date
$cmptime = $now.addminutes(-$myoffset)
[string] $min = [System.Convert]::ToString($now.Minute)
$diff = $cmptime-$srvtime
$diff = $diff.totalseconds
$diff = [decimal]::round($diff)
if (($diff -gt $maxdiff) -or ($diff -lt (-1*$maxdiff))) { $flag="*" }
write-host "$flag$comp`t$d`t$t`t$flag$diff$flag`t$tz"
"$flag$comp`t$d`t$t`t$flag$diff$flag`t$tz" | out-file $logfile -append
$zone = $timezonedesc.Description.tostring()
if (-not($timezonedesc )) { #no zone returned
$flag="*"
$zone = "ERROR: Invalid Time Zone Response"
write-host "*$zone*"
"*$zone*" | out-file $logfile -append
}
if ($flag -eq "*") { #time difference is too great
$report+=('' + $comp + ' | ')
$report+=('' + $d + ' | ')
$report+=('' + $t + ' | ')
$report+=('' + $diff + ' | ')
$report+=('' + $zone + ' | ')
$report+=('
')
}
}# end if null
}#end foreach computer
###
$report+="
"
$report | out-file $outfile
############################################################################################
#e-mail the report
$messageSubject = "Server Time Report"
$smtpServer = "smtp.domain.com"
$smtpFrom = "noreply@domain.com"
$smtpTo = $recipient
$message = $report
send-mailmessage -to $smtpTo -cc "admin@domain.com" -from $smtpFrom -subject $messageSubject -body $message -smtpserver $smtpServer -BodyAsHtml
###
remove-job * -force