Pages

1/02/2014

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=@'
<STYLE>
BODY{font-family: Verdana, Arial, Helvetica, sans-serif;font-size:12;font-color: #000000}
TABLE{border-width: 2px;padding: 1px;border-style: solid;border-color: black;border-collapse: collapse;} 
TH{border-width: 2px;padding: 1px;border-style: solid;border-color: black;background-color: #dddddd;font-size:16;font-weight:bold}
TD{border-width: 2px;padding: 2px;border-style: solid;border-color: black;background-color: #efefef; font-size:12;font-weight:normal} 
TD.error{border-width: 2px;padding: 2px;border-style: solid;border-color: black;background-color: #ffffff;font face="monospace";font-size:10;font-color: #cccccc}
</STYLE> 
<HTML> 
<HEAD> 
<TITLE></TITLE> 
</HEAD> 
<BODY> 
<H2>Server Time Issues</H2> 
<H4>
'@
$report+=$today
$report+="</H4><table><th>Server</th><th>Date</th><th>Time</th><th>Off(s)</th><th>Time Zone</th></tr>"

############################################################################################
# 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+='<tr><td class="error">' + $comp + '</td>' 
		         $report+='<td colspan="4" class="error">' + "WMI ERROR - No response to timezone query" + '</td>'  
			 $report+='</tr>' 
			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+='<tr><td class="error">' + $comp + '</td>' 
		         $report+='<td colspan="4" class="error">' + "WMI ERROR - No response to date/time query" + '</td>'  
			 $report+='</tr>' 
			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+='<tr><td class="error">' + $comp + '</td>' 
	         $report+='<td colspan="4" class="error">' + "RPC ERROR - No response on port " + $port + '</td>'  
		 $report+='</tr>' 
		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+='<tr><td class="error">' + $comp + '</td>' 
	         $report+='<td colspan="4" class="error">' + "CONNECTION ERROR:  No response to PING" + '</td>'  
		 $report+='</tr>' 
		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+=('<tr><td>' + $comp + '</td>') 
				$report+=('<td >' + $d + '</td>')  
				$report+=('<td >' + $t + '</td>')  
				$report+=('<td >' + $diff + '</td>')  
				$report+=('<td >' + $zone + '</td>')  
				$report+=('</tr>') 
				}
	 }# end if null 
}#end foreach computer
###
$report+="</TABLE></BODY></HTML>" 

$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

No comments: