Following on my previous post I spent some time today refining our ability to check the ICA listener across the farm and created a little powershell script that I thought I’d share.
It probably wont be much use to anyone else as it only does a few fairly specific checks but here it is. It’s by no means perfect but does what I need it to
Script will:
1. output servers that do not respond to a port query on 1494 – this is the test used to check if the ICA listener is responding
2. check if the following file exists: ‘c:Program’ file and rename it to Temp.$date if found ($date i.e 31082011). This check was created as one of the customers troublesome application had a habit of occasionally writing a log file to the C: called Program.
3. display servers that have an uptime less then 3 hours. This test is just useful for the particular customer : )
An input file will be requested, this cen be created by running a qfarm /online and taking the server netbios names from there. Ideally I would have liked to use the XenApp Cmdlets to obtain the information from the server but this wasn’t an option in this environment.
The Script has now been amended to return the list of online XenApp Servers from the Farm rather then using a file input.
test-port function was borrowed from http://learn-powershell.net/2010/09/11/scanning-ports-on-multiple-hosts/ to provide the port scanning functionality
—Checker.ps1 Start—
#Test-port function from – http://learn-powershell.net/2010/09/11/scanning-ports-on-multiple-hosts/
function Test-Port{
[cmdletbinding(
DefaultParameterSetName = ”,
ConfirmImpact = ‘low’
)]
Param(
[Parameter(
Mandatory = $True,
Position = 0,
ParameterSetName = ”,
ValueFromPipeline = $True)]
[array]$computer,
[Parameter(
Position = 1,
Mandatory = $True,
ParameterSetName = ”)]
[array]$port,
[Parameter(
Mandatory = $False,
ParameterSetName = ”)]
[int]$TCPtimeout=1000,
[Parameter(
Mandatory = $False,
ParameterSetName = ”)]
[int]$UDPtimeout=1000,
[Parameter(
Mandatory = $False,
ParameterSetName = ”)]
[switch]$TCP,
[Parameter(
Mandatory = $False,
ParameterSetName = ”)]
[switch]$UDP
)
Begin {
If (!$tcp -AND !$udp) {$tcp = $True}
#Typically you never do this, but in this case I felt it was for the benefit of the function
#as any errors will be noted in the output of the report
$ErrorActionPreference = “SilentlyContinue”
$report = @()
}
Process {
ForEach ($c in $computer) {
ForEach ($p in $port) {
If ($tcp) {
#Create temporary holder
$temp = “” | Select Server, Port, TypePort, Open, Notes
#Create object for connecting to port on computer
$tcpobject = new-Object system.Net.Sockets.TcpClient
#Connect to remote machine’s port
$connect = $tcpobject.BeginConnect($c,$p,$null,$null)
#Configure a timeout before quitting
$wait = $connect.AsyncWaitHandle.WaitOne($TCPtimeout,$false)
#If timeout
If(!$wait) {
#Close connection
$tcpobject.Close()
Write-Verbose “Connection Timeout”
#Build report
$temp.Server = $c
$temp.Port = $p
$temp.TypePort = “TCP”
$temp.Open = “False”
$temp.Notes = “Connection to Port Timed Out”
}
Else {
$error.Clear()
$tcpobject.EndConnect($connect) | out-Null
#If error
If($error[0]){
#Begin making error more readable in report
[string]$string = ($error[0].exception).message
$message = (($string.split(“:”)[1]).replace(‘”‘,””)).TrimStart()
$failed = $true
}
#Close connection
$tcpobject.Close()
#If unable to query port to due failure
If($failed){
#Build report
$temp.Server = $c
$temp.Port = $p
$temp.TypePort = “TCP”
$temp.Open = “False”
$temp.Notes = “$message”
}
#Successfully queried port
Else{
#Build report
$temp.Server = $c
$temp.Port = $p
$temp.TypePort = “TCP”
$temp.Open = “True”
$temp.Notes = “”
}
}
#Reset failed value
$failed = $Null
#Merge temp array with report
$report += $temp
}
If ($udp) {
#Create temporary holder
$temp = “” | Select Server, Port, TypePort, Open, Notes
#Create object for connecting to port on computer
$udpobject = new-Object system.Net.Sockets.Udpclient($p)
#Set a timeout on receiving message
$udpobject.client.ReceiveTimeout = $UDPTimeout
#Connect to remote machine’s port
Write-Verbose “Making UDP connection to remote server”
$udpobject.Connect(“$c”,$p)
#Sends a message to the host to which you have connected.
Write-Verbose “Sending message to remote host”
$a = new-object system.text.asciiencoding
$byte = $a.GetBytes(“$(Get-Date)”)
[void]$udpobject.Send($byte,$byte.length)
#IPEndPoint object will allow us to read datagrams sent from any source.
Write-Verbose “Creating remote endpoint”
$remoteendpoint = New-Object system.net.ipendpoint([system.net.ipaddress]::Any,0)
Try {
#Blocks until a message returns on this socket from a remote host.
Write-Verbose “Waiting for message return”
$receivebytes = $udpobject.Receive([ref]$remoteendpoint)
[string]$returndata = $a.GetString($receivebytes)
}
Catch {
If ($Error[0].ToString() -match “bRespond after a period of timeb”) {
#Close connection
$udpobject.Close()
#Make sure that the host is online and not a false positive that it is open
If (Test-Connection -comp $c -count 1 -quiet) {
Write-Verbose “Connection Open”
Build report
$temp.Server = $c
$temp.Port = $p
$temp.TypePort = “UDP”
$temp.Open = “True”
$temp.Notes = “”
}
Else {
<#
It is possible that the host is not online or that the host is online,
but ICMP is blocked by a firewall and this port is actually open.
#>
Write-Verbose “Host maybe unavailable”
#Build report
$temp.Server = $c
$temp.Port = $p
$temp.TypePort = “UDP”
$temp.Open = “False”
$temp.Notes = “Unable to verify if port is open or if host is unavailable.”
}
}
ElseIf ($Error[0].ToString() -match “forcibly closed by the remote host” ) {
#Close connection
$udpobject.Close()
Write-Verbose “Connection Timeout”
#Build report
$temp.Server = $c
$temp.Port = $p
$temp.TypePort = “UDP”
$temp.Open = “False”
$temp.Notes = “Connection to Port Timed Out”
}
Else {
$udpobject.close()
}
}
#Merge temp array with report
$report += $temp
}
}
}
}
End {
#Generate Report
$report
}
}
#Obtain Servers from Farm
$farm = new-Object -com “MetaframeCOM.MetaframeFarm”
$farm.Initialize(1)
$OnlineServers=$farm.zones | %{$_.OnlineServers} |select ServerName | %{$_.ServerName} | sort-object
$date=(get-date (get-date) -uformat %dm%Y)
Write-Host “The Script will now check if Online Servers are listening on port 1494 and display those that are not (ICA Listener Down check):”
foreach ($server in $OnlineServers)
{
test-port -computer $server -port 1494 | where {$_.open -match “False”}
}
Write-Host “The Script will now check if Online Servers contain an invalid file (C:Program check):”
foreach ($server in $OnlineServers)
{
if (Test-Path -path \$serverc$Program){
Write-Host $server “has Program File – This has been renamed to: Program.”$date
rename-item -path \$serverc$Program -newname Temp.$date
}
}
Write-Host “The Script will now check if Online Servers have been up for more then 4 hours (random reboot check):”
foreach($server in $OnlineServers)
{
$wmi=Get-WmiObject -class Win32_OperatingSystem -computer $server
$LBTime=$wmi.ConvertToDateTime($wmi.Lastbootuptime)
[TimeSpan]$uptime=New-TimeSpan $LBTime $(get-date)
if ($uptime.days -lt 1-and $uptime.hours -lt 4){
Write-Host $server “Uptime: ” $uptime.days “Days” $uptime.hours “Hours” $uptime.minutes “Minutes” $uptime.seconds “Seconds”}
}
—Checker.ps1 End—
Updates – 1/9/11