My XenApp 6.5 Farm Health Powershell Script

This is a script I wrote to get some XenApp Farm Health info and to show statuses. It also works with the XenApp Rolling Reboot script by Dane Young. It still needs a lot of cleanup and changes. I just haven’t gotten to them, but eventually will. This is the quick and dirty. Don’t even think about asking me for support on it. Use at your own risk.

Thanks to Jason Poyner for getting me started with this by hacking his awesome script!

Last Update: 1.8.2013
## XenAppServerHealthCheck
##
## Original basis scipt by Jason Poyner, techblog.deptive.co.nz 28 May 2012
## Modified / Hacked / Compiled by Mike Nelson, Jan-2013
##
## The script checks the health of a XenApp 6.x farm and e-mails two reports. The full farm
## health report is attached to the e-mail and any errors encountered are in an html report
## embedded in the email body.
##
## ver. 1.01
## Revisions –
## Jan-2013
## -MN Added check for IMA and xTE Services
## -MN Added LastRebootTime
## -MN Changed Email function for multiple recipients
## -MN Added Offline Server code
## -MN Added Farm Information code
## -MN hacked a lot of code
##
######################################
## Add-PSSnapin Citrix.XenApp.Commands if not already loaded
If ((Get-PSSnapin -Name “Citrix*” -ErrorAction SilentlyContinue | Measure-Object).count -eq 0) {
Add-PSSnapin -Name “Citrix*”}

## Change the below variables to suit your environment
#===================================
## Default load evaluator assigned to servers. If the load evaluator assigned to a server does
## not match this load evaluator the server is flagged in the script report.
$defaultLE = “Advanced – UW”
## Set the maxUpTimeDays variable to the maximum number of days a XenApp server should be up for.
## Idea! Use this with Dane Young’s Rolling Reboot Script!
$maxUpTimeDays = 14
## Email information
$emailFrom = “someone@company.com”
$emailTo = “Person One <person.one@company.com>”, “Person Two <person.two@company.com>”
$smtpServer = “emailserver.company.com”
## Farm XML port
$XMLPortNumber = 8080
## Farm environment (displays on report only)
$environment = “Development”
## Where the script is run from
$scriptfolder = “C:Scripts”
## What title do you want on the HTML report?
$reporttitle = “XenApp Farm Health Report”
#====================================
## Valid success codes
$successCodes = @(“success”,”ok”,”enabled”)
## Set placement of output files
$currentDir = Split-Path $MyInvocation.MyCommand.Path
$logfile = Join-Path $currentDir (“XenAppServerHealthCheck.log”)
$resultsHTM = Join-Path $currentDir (“XenAppServerHealthCheck.htm”)
$scriptStartTime = get-date
#Farm Info variables
$Applications = Get-XAApplicationReport *
$Applications_Count = (($Applications | Measure-Object).Count)
$Zones = GET-XAZone | sort ZoneName
$Zones_Count = (($Zones | Measure-Object).Count)
$WorkGpt = GET-XAWorkerGroup | sort WorkerGroupName
$WorkGpt_Count = (($WorkGpt | Measure-Object).Count)
$LoadEvaluator = GET-XALoadEvaluator | sort LoadEvaluatorName
$LoadEvaluator_Count = (($LoadEvaluator | Measure-Object).Count)
$Discsession = Get-XASession | where { $_.State -eq “Disconnected” } | sort servername
$Discsession_Count = (($Discsession | Measure-Object).Count)
$farm = Get-XAFarm
$Domain = $env:USERDOMAIN
## Policy computer/user variables
## if you use local gpo change “localfarmgpo” by “LocalGpo”
## or if you use domain GPO change by example “New-PSDrive -Name Gpo1 -PSProvider CitrixGroupPolicy -Root -DomainGpo Site1GPO”
$PolicyCompMode = “localfarmgpo:Computer*”
$PolicyComp = get-item $PolicyCompMode | sort Priority
$PolicyComp_Count = (($PolicyComp | Measure-Object).Count)
## if you use local gpo change “localfarmgpo” by “LocalGpo”
## or if you use domain GPO change by example “New-PSDrive -Name Gpo1 -PSProvider CitrixGroupPolicy -Root -DomainGpo Site1GPO”
$PolicyUserMode = “localfarmgpo:user*”
$PolicyUser = get-item $PolicyUserMode | sort Priority
$PolicyUser_Count = (($PolicyUser | Measure-Object).Count)
## Filter folders – Un-comment when needed
## Not implemented yet
#$AppFolderExclude = “Qualif”, “app2”
#$AppNameExclude = “Qualif”, “app2”
#$ServFolderExclude = “Qualif”, “app2”

## Database information
$DsnPath = Get-Content “C:Program Files (x86)CitrixIndependent Management Architecturemf20.dsn”
foreach ($str in $DsnPath) {$1=$str.contains(“DRIVER”) ; $2=$str.contains(“SERVER”) ; if($1 -eq $True) {$DataStoreFile = $Str} ElseIF ($2 -eq $True) {$DataStoreServer = $Str} }

## If logfile exists, write a new one
rm $logfile -force

#=======================================
function LogMe() {
Param(
[parameter(Mandatory = $true, ValueFromPipeline = $true)] $logEntry,
[switch]$display,
[switch]$error,
[switch]$warning,
[switch]$progress
)
if ($error) {
$logEntry = “[ERROR] $logEntry” ; Write-Host “$logEntry” -Foregroundcolor Red}
elseif ($warning) {
Write-Warning “$logEntry” ; $logEntry = “[WARNING] $logEntry”}
elseif ($progress) {
Write-Host “$logEntry” -Foregroundcolor Green}
elseif ($display) {
Write-Host “$logEntry” }
#$logEntry = ((Get-Date -uformat “%D %T”) + ” – ” + $logEntry)
$logEntry | Out-File $logFile -Append
}

#=======================================
function Ping([string]$hostname, [int]$timeout = 200) {
$ping = new-object System.Net.NetworkInformation.Ping #creates a ping object
try {
$result = $ping.send($hostname, $timeout).Status.ToString()
} catch {
$result = “failure”
}
return $result
}

#======================================
Function writeHtmlHeader
{
param($title, $fileName)
$date = ( Get-Date ).ToString(‘MM/dd/yyyy’)
$head = @”
<html>
<head>
<meta http-equiv=’Content-Type’ content=’text/html; charset=iso-8859-1′>
<title>$title</title>
<STYLE TYPE=”text/css”>
<!–
td {
font-family: Tahoma;
font-size: 11px;
font-weight: bold;
padding-top: 0px;
padding-right: 0px;
padding-bottom: 0px;
padding-left: 0px;
}
body {
margin-left: 0px;
margin-top: 0px;
margin-right: 0px;
margin-bottom: 0px;
}
–>
</style>
</head>
<body>
<table width=’100%’>
<tr>
<td height=’25’><font face=’verdana, tahoma’ size=’4′><strong>$title</strong></font></td></tr>
<tr><td><font face=’verdana, tahoma’ size=’-1′>Environment – $environment</font></td></tr>
<tr><td><font face=’verdana, tahoma’ size=’-1′>Generated on: $($ENV:Computername)</font></td></tr>
<tr><td><font face=’verdana, tahoma’ size=’-1′>Run Date: $(Get-date -format g)</font></td>
</tr><tr><td>&nbsp;</td></tr>
</table>
“@
$head | Out-File $fileName
}

# ========================================
Function writeTableHeader
{
param($fileName)
$tableHeader = @”
<table style=’border-bottom: 1px solid #999999;’ width=’100%’><tbody>
<tr bgcolor=#2B75B2><td colspan=’11’><font face=’verdana,tahoma’ size=’3′ color=’#FFFFFF’><strong>Farm Status</strong></td></tr>
<tr style=’border-bottom: 1px solid #999999;’ bgcolor=#CCCCCC>
<td align=’center’><strong>Name</strong></td>
<td align=’center’><strong>Primary Worker Group</strong></td>
<td align=’center’><strong>Ping</strong></td>
<td align=’center’><strong>Logons</strong></td>
<td align=’center’><strong>IMA Service</strong></td>
<td align=’center’><strong>XTE Server</strong></td>
<td align=’center’><strong>ICA Port</strong></td>
<td align=’center’><strong>XML Port</strong></td>
<td align=’center’><strong>WMI</strong></td>
<td align=’center’><strong>Scheduled Reboot</strong></td>
<td align=’center’><strong>Last Reboot Time</strong></td>
</tr>
“@
$tableHeader | Out-File $fileName -append
}

# =========================================
Function writeData
{
param([string[]]$infoColumns, [string[]]$rowData, $fileName)
## Populate info cells
$tableEntry = “<tr style=’border-bottom: 1px solid #999999;’>”
$infoColumns | % {
$tableEntry += “<td style=’border-bottom: 1px solid #999999;’>$_</td>”
}
## Populate data cells and colour them red or green based on success/failure
$rowData | % {
## Check for possible success messages
if ($_ -eq “Cannot Ping” -or $_ -eq “Error” -or $_ -eq “Disabled” -or $_ -eq “failure”)
{
$tableEntry += “<td bgcolor=’#FF0000′ align=center><font color=’#FFFFFF’>$_</font></td>”
}
else
{
$tableEntry += “<td bgcolor=’#387C44′ align=center><font color=’#FFFFFF’>$_</font></td>”
}
}
$tableEntry += “</tr>”
$tableEntry | Out-File $fileName -append
}

## =========================================
Function writeHtmlFooter
{
param($fileName)
@”
<br><br><center><font size=’-3′><em>Copyright 2013 Mike Nelson – nGenx LLC</em></font><br><img src=’ngenx.jpg’ height=’37’ width=’117′></center></body>
</html>
“@ | Out-File $FileName -append
}

## ========================================
## == MAIN SCRIPT ==
## ===========================================
“Checking server health…” | LogMe -display

$allResults = @()

Get-XAServer | % {

$Results = “” | Select-Object ComputerName, WorkerGroups, Ping, Logons, IMAService, XTEServer, ICAPort, XMLPort, WMI, ScheduledReboot, LastRebootTime
$server = $_.ServerName
$server | LogMe -display -progress
$Results.ComputerName = $server
# $WGCheck = Get-XAWorkerGroup -ServerName $server | % {$_.WorkerGroupName}
if ((Get-XAWorkerGroup -ServerName $_.ServerName).WorkerGroupName -eq $null) {
“No Worker Group assigned” | LogMe -display -warning
$Results.WorkerGroups = “No Group Assigned”
} else {
$Results.WorkerGroups = “Success”
$Results.WorkerGroups = Get-XAWorkerGroup -ServerName $_.ServerName
}

## Check IMA Service
$IMAService = (get-service -computer $server | where-object{$_.name -eq “IMAService”}| Select Status)
if($IMAService.status -eq “running”) {
$results.IMAService = “Success”
} else {
“IMAService Not Running” | LogMe -display -error
$results.IMAService = “Error”
}

## Check XTE Server Service
$XTEServer = (get-service -computer $server | where-object{$_.name -eq “CitrixXTEServer”}| Select Status)
if($XTEServer.status -eq “running”) {
$results.XTEServer = “Success”
} else {
“XTEServer Not Running” | LogMe -display -error
$results.XTEServer = “Error”
}

## Ping
$result = Ping $server 100
$Results.Ping = $result

## Check server logons
if($_.LogOnsEnabled -eq $false){
“Logons are disabled on this server” | LogMe -display -warning
$Results.Logons = “Disabled”
} else {
$Results.Logons = “Enabled”
}

## Check Load Evaluator
if ((Get-XALoadEvaluator -ServerName $_.ServerName).LoadEvaluatorName -ne $defaultLE) {
“Non-default Load Evaluator assigned” | LogMe -display -warning
$Results.LoadEvaluator = Get-XALoadEvaluator -ServerName $_.ServerName
} else {
$Results.LoadEvaluator = “Success”
}

if($result -eq “Success”){

## Test ICA connectivity
$Results.ICAPort = “Error”
try {
$socket = new-object System.Net.Sockets.TcpClient($ip, $_.IcaPortNumber) ## creates a socket connection to see if the port is open
} catch {
$socket = $null
}
if($socket -ne $null) {
“Socket Connection Successful” | LogMe
$stream = $socket.GetStream() ## gets the output of the response
$buffer = new-object System.Byte[] 1024
$encoding = new-object System.Text.AsciiEncoding
Start-Sleep -Milliseconds 500 ## records data for half a second
while($stream.DataAvailable)
{
$read = $stream.Read($buffer, 0, 1024)
$response=$encoding.GetString($buffer, 0, $read)
if($response -like ‘*ICA*’){
“ICA protocol responded” | LogMe
$Results.ICAPort = “Success”
} else {
“ICA did not respond” | LogMe -display -error
}
}
} else {
“Socket connection failed” | LogMe -display -error
}

## Test WMI
$Results.WMI = “Error”
try {
$wmi=Get-WmiObject -class Win32_OperatingSystem -computer $_.ServerName
} catch {
$wmi = $null
}

## Test XML Port connectivity
$Results.XMLPort = “Error”
$socket = new-object System.Net.Sockets.TcpClient
$socket.Connect($server, $XMLPortNumber) ## creates a socket connection to see if the port is open
if($socket.Connected) {
$status = “Open”
“Socket Connection Successful” | LogMe
“XML port responded” | LogMe
$Results.XMLPort = “Success”
$socket.Close()
} else {
“XML did not respond” | LogMe -display -error
“Socket connection failed” | LogMe -display -error
$Results.XMLPort = “Error”
}

## Check Print Spooler is Running
$PrintSpooler=(get-service -computer $server | Where-Object {$_.name -eq “Spooler”} | Select Status)
if($PrintSpooler.status -eq “running”) {
$results.Spooler = “Success”
} else {
“PrintSpooler Not Running” | LogMe -display -error
$results.Spooler = “Error”
}

## Check for server uptime
if ($wmi -ne $null) {
$Results.WMI = “Success”
$LBTime=$wmi.ConvertToDateTime($wmi.Lastbootuptime)
[TimeSpan]$uptime=New-TimeSpan $LBTime $(get-date)

if ($uptime.days -gt $maxUpTimeDays){
“Server reboot warning, last reboot: {0:D}” -f $LBTime | LogMe -display -error
$Results.ScheduledReboot = “Error”
$Results.LastRebootTime = $LBTime
} else {
$Results.ScheduledReboot = “Success”
$Results.LastRebootTime = $LBTime
}
} else {
“WMI connection failed – check WMI for corruption” | LogMe -display -error
}
}
else {
(“Cannot ping ” + $server) | LogMe -display -error
}

$allResults += $Results
}
##
## ——————————————-
## START Write to HTML Coding for Status table
## ——————————————-
## Write all results to an html file
Write-Host (“Saving results to html report: ” + $resultsHTM)
#$allResults | sort-object -property ComputerName | export-csv $resultsCSV -noTypeInformation
writeHtmlHeader $reporttitle $resultsHTM
writeTableHeader $resultsHTM
$allResults | sort-object -property ComputerName | % {
writeData $_.ComputerName, $_.WorkerGroups $_.Ping, $_.Logons, $_.IMAService, $_.XTEServer, $_.ICAPort, $_.XMLPort, $_.WMI, $_.ScheduledReboot, $_.LastRebootTime $resultsHTM
}

## To copmpensate for bad HTML coding – Need to fix!
$EndTable = “</table><br><table width=’100%’><td colspan=’2′ bgcolor=’#2B75B2′><font face=’verdana,tahoma’ size=’3′ color=’#FFFFFF’><strong>Farm Information</strong></td></tr>”
$EndTable | Out-File -filepath $resultsHTM -Append

### —————————–###
### Offline Server Listing Code ###
### —————————–###

## Server Listing of Offline Farm servers
$AllXAServers = Get-XAServer | Sort-Object ServerName
$XAServers = @()
ForEach( $XAServer in $AllXAServers)
{
$XAServers += $XAServer.ServerName
}

$OnlineXAServers = get-xazone | Get-XAServer -OnlineOnly | Sort-Object ServerName

$OnlineServers = @()
ForEach( $OnlineServer in $OnlineXAServers)
{
$OnlineServers += $OnlineServer.ServerName
}

$OfflineServers = @()
ForEach($Server in $XAServers)
{
If($OnLineServers -notcontains $Server)
{
$OfflineServers += $Server
}
}

### ——————————–###
### START Farm Information HTML code
### ——————————–###
$strOutput1 = ‘<tr><td>Farm Name:</td><td>’ + $farm + ‘</td></tr>’
$strOutput1 | Out-File -filepath $resultsHTM -Append
$strOutput1 = ‘<tr><td>Farm Version:</td><td>’ + ($farm.ServerVersion) + ‘</td></tr>’
$strOutput1 | Out-File -filepath $resultsHTM -Append
$strOutput1 = ‘<tr><td>Domain:</td><td>’ + $Domain + ‘</td></tr>’
$strOutput1 | Out-File -filepath $resultsHTM -Append
$strOutput1 = ‘<tr><td>Datastore Type:</td><td>’ + (@($DataStoreFile.Substring(7))) + ‘</td></tr>’
$strOutput1 | Out-File -filepath $resultsHTM -Append
$strOutput1 = ‘<tr><td>Datastore Server:</td><td>’ + (@($DataStoreServer.Substring(7))) + ‘</td></tr>’
$strOutput1 | Out-File -filepath $resultsHTM -Append

Foreach ($PolicyCompGpo in $PolicyComp)
{
cd (“LocalFarmGpo:computer”+($PolicyCompGpo.Name)+”settingslicensing”)
$LicSrv = get-itemproperty LicenseServerHostName
$LicPort = get-itemproperty LicenseServerPort

if (($LicSrv.state-eq “enabled”) -or ($LicSrv.state -eq “UseDefault”))
{
$strOutPut1 ='<tr><td>Citrix Licence Server Name and port :</td><td>’ + (@($LicSrv.Value + ‘ (‘+$LicPort.value+’) – Policy Name : ‘+$PolicyCompGpo.Name))
$strOutPut1 | Out-File -filepath $resultsHTM -Append
}
else
{}
}
Set-Location $scriptfolder

## Create HTML Output – Offline Servers
$strOutPut1 = ‘<tr><td><font color=#000000><strong>’ + ‘Servers Currently Marked Offline In Farm:’ + ‘</strong></font></td>’
## Write HTML to File – Offline Servers
$strOutPut1 | out-file -filepath $resultsHTM -append
## Create HTML Output- Offline Servers
if( $OfflineServers -ne $null) {
foreach( $line in $OfflineServers ) { $strOutput4 += ‘<td><strong>’ + $line + ‘<br />’ }
$strOutput4 += ‘</strong></td></tr>’
} else {
$strOutput4 = ‘<td><strong>None</strong></td></tr>’
}

## Write HTML to File – Offline Servers
$strOutPut4 | out-file -filepath $resultsHTM -Append

## Write HTML to File
$strOutput5 = ‘<tr><td>Scheduled Rolling Reboot Setting (Days):</td><td>’ + $maxUpTimeDays + ‘</td></tr>’
$strOutput5 | Out-File -filepath $resultsHTM -Append

$strOutput6 = ‘<tr><td>Number of Applications:</td><td>’ + $Applications_Count + ‘</td></tr>’
$strOutput6 | Out-File -filepath $resultsHTM -Append

$strOutput7 = ‘<tr><td>Number of Zones:</td><td>’ + $Zones_Count + ‘</td></tr>’
$strOutput7 | Out-File -filepath $resultsHTM -Append

$strOutput8 = ‘<tr><td>Number of Worker Groups:</td><td>’ + $WorkGpt_Count + ‘</td></tr>’
$strOutput8 | Out-File -filepath $resultsHTM -Append

$strOutput9 = ‘<tr><td>Number of Load Evaluators:</td><td>’ + $LoadEvaluator_Count + ‘</td></tr>’
$strOutput9 | Out-File -filepath $resultsHTM -Append

$strOutput10 = ‘<tr><td>Number of Sessions in Disconnected State:</td><td>’ + $Discsession_Count + ‘</td></tr>’
$strOutput10 | Out-File -filepath $resultsHTM -Append

## Write out ending table
$strOutEnd = ‘</table></center>’
$strOutEnd | Out-File -filepath $resultsHTM -Append

## —————————————————-
## TESTING SECTION
## —————————————————-
## List Sessions in Disconnected State
#if ($Discsession_Count -gt 0) {
#$startTable = ‘<br><table width=’100%’><td colspan=’2′ bgcolor=’#2B75B2′><font face=’verdana,tahoma’ size=’3′ color=’#FFFFFF’><strong>Disconnected Sessions</strong></td></tr>”
#$strOutput1 = ‘<tr><td>’
#} else {
#}

## Get Rolling Reboot Event Log Entries
#$Date = [DateTime]::Now.AddDays(-30)
#$Date.tostring(“MM-dd-yyyy”), $env.Computername
#$eventlist = @()
#ForEach( $XAServer in $AllXAServers)
#{
#Get-EventLog “application” -After $Date |where -FilterScript {$_.Source -eq “Citrix Rolling Reboot” -and $_.EventID -eq 911}
#}
#$eventlist | Out-File -filepath $resultsHTM -Append
## Write out the Footer
writeHtmlFooter $resultsHTM

## Email Params
$mailMessageParameters = @{
From = $emailFrom
# To = $emailTo
To = [string[]] ($emailTo)
Subject = (“XenApp Health Report” + $environment + (Get-Date).ToString(‘dddd MM/dd/yyyy’))
SmtpServer = $smtpServer
Body = (get-content $resultsHTM) | Out-String
Attachment = $resultsHTM
}

## Send the Emails
Send-MailMessage @mailMessageParameters -BodyAsHtml

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.