Powershell Script to monitor a Citrix XenApp 6.5 Farm's Health

by Stan Czerno June 12, 2014 05:06 CST

Check out my new script for XenApp and XenDesktop 7.xhttps://www.czerno.com/Blog/post/2019/10/11/xendesktop-and-xenapp-powershell-monitor-and-web-page

In a previous post I had mentioned my "homegrown monitoring service" so today I thought I would elaborate and share it.

While looking for some sort of monitoring script for XenApp, I found an excellent script written by Jason Poyner, XenApp Farm Health Report, http://deptive.co.nz/xenapp-farm-health-report/.

His script does a Health Check and emails an HTML report. The script checks just about everything concerning a XenApp Farm.

What I was looking for was something to check the servers and only send me an email if an issue is witnessed. So, as with most of my scripts, I took someone elses script to the next level. But kudos goes to Jason for laying the foundation, he did an excellent job.

I changed the script to log errors and send an email about the error, as they are witnessed. I added a lag time to the script so you can set how often to be emailed about the same error message. So in my scenario, the script runs every 15 minutes but I set the lag time to 3600 seconds. This way I am not alerted to the same error more than once per hour. If new errors occur an email is set anyway.

I then changed the script to write the report an HTML file. The script copies the HTML file and images to a web server instead of emailing it. The Web Page will auto-refresh so you could keep it open all day and the latest results will be displayed.

Here is what the Web Page looks like:

Here are the images used in the web page. Just place the images in the same folder as the script. You can replace the Citrix.PNG image with whatever you choose, just try to keep it a similar size.

Here is what an email alert looks like.

I disabled and stopped these services to get the email. The Script actually attempts to start services it finds that arenot running.

Below are the scripts. There is one for XenApp 6.x and one for XenApp 5. They are basically the same except for some column names.

XenApp 6.x

 

XenApp 5

The script requires the Powershell SDKs to be installed. The SDKs can be found here:

XenApp 6.5 https://www.citrix.com/downloads/xenapp/sdks/powershell-sdk.html
XenApp 5 http://blogs.citrix.com/2010/09/14/xenapp-5-powershell-sdk-tech-preview-3-released/

The script must run from a XenApp server. I schedule mine to run every 15 minutes.

[UPDATED 02/11/2015]

Below are Aaron Argent's contributions to the XenApp 6.x script. He has added a Multiple Zones option to the script that you can run from different ZDC's to reduce the script runtime. He has also added a PVS RAMCache and DiskCache Check as well.

Here is  Aaron's XenApp 6.x Script:

Attached is Aaron's PVS Script:

Thanks Aaron for your contributions!

PVS_Cache.txt (10.5KB)

Tags: , ,

Catergories: Citrix | XenApp | Powershell

Comments (74) -

Khoi
June 30, 2014 10:21 CST

Question: Is there a way to specify what the generates the error? In place of the value, I want it to be more specific as to what caused the error. I do like your script a lot, especially since it generates and send emails only when errors were logged. However I am wanting to see about changing the error value. Maybe the value saying "IMA Service stopped" so to speak. I'm not too familiar with Powershell, but this script has been one of the better options available for monitoring my company's servers.

Please let me know what your thoughts are on this. If I need to clarify myself, please let me know. Thank you for your time.

Stan Czerno
June 30, 2014 11:45 CST

I would not be able to provide information on what caused the error, there are a too many reasons why a Service would not be running. The script is to simply alert you that there is an issue and you will need to investigate the cause.

When one of the Services are in an "Error" state it implies they are Not Running. When a Port is in an "Error" state it implies they are not reachable.

tony
September 12, 2014 06:15 CST

HI
thanks for a great script but do you think its possible to get powershell to show peak sessions on a Xenapp Server and add it to the report

Stan Czerno
September 12, 2014 07:40 CST

I think you are referring to historical data. I am not saving this info to a Database so there is no History to report from. The Monitor does show current connections.

You might be interested in my other blog post, www.czerno.com/.../Application-and-User-Usage-Database-and-Reports.

Paul
October 2, 2014 19:19 CST

Fantastic script and really expands on Jason's, however is the means to speed it up in any way? I currently have various farms with 50+ servers in each and it can take up to 60 minutes in some instances even after ensuring the task is run at the highest priority.
Cheers, Paul.

Stan Czerno
October 3, 2014 02:19 CST

Thanks, but I really did not write it with large deployments in mind. I mainly wrote it for my home lab which only has three Citrix Servers. I do use it at work as well but only in the development lab, which has ten servers.

I would look into a commercially available solution to monitor that many servers.

Paul
October 3, 2014 23:09 CST

You're absolutely right of course, alas our leaders vault Edgesight which is nothing short of clunky and painful to use when trying to extract anything in a reader friendly way!

I think I may of noticed a bug and/or as misreported statistic. When filtering to report against a subset of servers ($excludedFolders) it continues to include the count of total connected and disconnected sessions from those excluded servers.

Although looking at the code I'm struggling to understand why that is!
Cheers, Paul.

Paul
October 3, 2014 23:52 CST

Spotted it = Calls the totals from the $sessions array / Created variables for running count instead.
Cheers, Paul.

Sran Czerno
October 4, 2014 02:47 CST

You know, I never did really test the excluded servers. Can you share the corrected code?

Paul
October 7, 2014 04:29 CST

Sure;
#Additional user variables
$newac = 0
$newdc = 0
$CPUAverage = 0
$RAMAverage = 0
Included the modified sections in whole;
  #====================================================================================
        #                 CHECK ACTIVE AND DISCONNECTED USER SESSIONS
        #====================================================================================
      # Report on active server sessions
      $activeServerSessions = [array]($sessions | ? {$_.State -eq "Active" -and $_.Protocol -eq "Ica" -and $_.ServerName -match $server})
      if($activeServerSessions) { $totalActiveServerSessions = $activeServerSessions.count }
      else { $totalActiveServerSessions = 0 }
        $tests.ActiveApps = "SUCCESS", $totalActiveServerSessions
        "Active ICA sessions: $totalActiveServerSessions" | LogMe -display
        $newac = $newac + $totalActiveServerSessions
        # Report on disconnected server sessions
      $discServerSessions = [array]($sessions | ? {$_.State -eq "Disconnected" -and $_.Protocol -eq "Ica" -and $_.ServerName -match $server})
      if($discServerSessions) { $totalDiscServerSessions = $discServerSessions.count }
      else { $totalDiscServerSessions = 0 }
        $tests.DiscUsers = "SUCCESS", $totalDiscServerSessions
        "Disconnected ICA sessions: $totalDiscServerSessions" | LogMe -display
        $newdc = $newdc + $totalDiscServerSessions

#==============================================================================================
        #               CHECK CPU AND MEMORY USAGE
        #==============================================================================================
        # Check the AvgCPU value for 5 seconds
        $AvgCPUval = CheckCpuUsage ($server)
        if( [int] $AvgCPUval -lt 60) { "CPU usage is normal [ $AvgCPUval % ]" | LogMe -display; $tests.AvgCPU = "SUCCESS", ($AvgCPUval) }
    elseif([int] $AvgCPUval -lt 90) { "CPU usage is medium [ $AvgCPUval % ]" | LogMe -warning; $tests.AvgCPU = "WARNING", ($AvgCPUval) }     
    elseif([int] $AvgCPUval -lt 95) { "CPU usage is high [ $AvgCPUval % ]" | LogMe -error; $tests.AvgCPU = "ERROR", ($AvgCPUval) }
    elseif([int] $AvgCPUval -eq 101) { "CPU usage test failed" | LogMe -error; $tests.AvgCPU = "ERROR", "Err" }
        else { "CPU usage is Critical [ $AvgCPUval % ]" | LogMe -error; $tests.AvgCPU = "ERROR", ($AvgCPUval) }  
    $CPUAverage =  $CPUAverage + $AvgCPUval
        #$CPUAverage = "{0:N2}" -f $CPUAverage
        $AvgCPUval = 0
        
        # Check the Physical Memory usage      
        $UsedMemory = CheckMemoryUsage ($server)
        if( [int] $UsedMemory -lt 60) { "Memory usage is normal [ $UsedMemory % ]" | LogMe -display; $tests.MemUsg = "SUCCESS", ($UsedMemory) }
    elseif([int] $UsedMemory -lt 85) { "Memory usage is medium [ $UsedMemory % ]" | LogMe -warning; $tests.MemUsg = "WARNING", ($UsedMemory) }     
    elseif([int] $UsedMemory -lt 90) { "Memory usage is high [ $UsedMemory % ]" | LogMe -error; $tests.MemUsg = "ERROR", ($UsedMemory) }
    elseif([int] $UsedMemory -eq 101) { "Memory usage test failed" | LogMe -error; $tests.MemUsg = "ERROR", "Err" }
        else { "Memory usage is Critical [ $UsedMemory % ]" | LogMe -error; $tests.MemUsg = "ERROR", ($UsedMemory) }  
    $RAMAverage = $RAMAverage + $UsedMemory
        #$RAMAverage = "{0:N2}" -f $RAMAverage
        $UsedMemory = 0  


These two lines were also added to the DISPLAY TOTALS Section;
$CPUAverage = "{0:N2}" -f ($CPUAverage / $TotalServersCount)
$RAMAverage = "{0:N2}" -f ($RAMAverage / $TotalServersCount)

And the final table in the HTML Formatting section
</table>
        <table width='100%'>
        <tr bgcolor='#CCCCCC'>
        <td width=50% align='center' valign="middle">
        <font face='Tahoma' color='#003399' size='2'><strong>Active Applications:  $newac</strong></font>
        <td width=50% align='center' valign="middle">
        <font face='tahoma' color='#003399' size='2'><strong>Disconnected Sessions:  $newdc</strong></font>
        </td>
        <td width=50% align='center' valign="middle">
        <font face='Tahoma' color='#003399' size='2'><strong>AvgCPU:  $CPUAverage</strong></font>
        <td width=50% align='center' valign="middle">
        <font face='tahoma' color='#003399' size='2'><strong>AvgRAM:  $RAMAverage</strong></font>
        </td>
        </tr>
        </table>


This correctly calculates the sessions counts just for the servers reported and also includes an average CPU/RAM utilisation percentage, which is handy as it gives a high level capacity/performance measurement for that application (server farm).

Murugesan Sekar
October 4, 2014 22:18 CST

Very nice script...thanks for developing such a nice script.. is there any way that we can include CPU usage, C drive space usage?

Aaron
October 19, 2014 20:14 CST

Using a Column called DiskFree, you can get the Disk Free via this code, I placed under Memory Usage.
-------------------------------

    $HardDisk = Get-WmiObject Win32_LogicalDisk -ComputerName $server -Filter "DeviceID='C:'" | Select-Object Size,FreeSpace

    $DiskTotalSize = $HardDisk.Size
    $DiskFreeSpace = $HardDisk.FreeSpace

    $PercentageDS = (($DiskFreeSpace / $DiskTotalSize ) * 100); $PercentageDS = "{0:N2}" -f $PercentageDS

    if( [int] $PercentageDS -gt 15) { "Disk Free is normal [ $PercentageDS % ]" | LogMe -display; $tests.DiskFree = "SUCCESS", ($PercentageDS) }
    elseif([int] $UsedMemory -lt 15) { "Disk Free is Low [ $PercentageDS % ]" | LogMe -warning; $tests.DiskFree = "WARNING", ($PercentageDS) }    
    elseif([int] $UsedMemory -lt 5) { "Disk Free is Critical [ $PercentageDS % ]" | LogMe -error; $tests.DiskFree = "ERROR", ($PercentageDS) }
    elseif([int] $UsedMemory -eq 0) { "Disk Free test failed" | LogMe -error; $tests.DiskFree = "ERROR", "Err" }
    else { "Disk Free is Critical [ $PercentageDS % ]" | LogMe -error; $tests.DiskFree = "ERROR", ($PercentageDS) }  
    $PercentageDS = 0

-------------------------------

Murugesan Sekar
October 31, 2014 02:24 CST

Thanks Aaron

Murugesan Sekar
October 4, 2014 22:23 CST

Also for PS 4.5 report, Do we need to install SDK in all the citrix servers in the farm?  

Stan Czerno
October 5, 2014 04:03 CST

The SDK is only needed on the server you run the script from.

Murugesan Sekar
October 31, 2014 02:18 CST

Thanks Stan

Aaron
October 19, 2014 19:56 CST

Using the exisiting code, I have added Disk Free Percentage Check and Event Error Count

Create a New column called "DiskFree" and add the below code, I placed it under the UsedMemory
For the Event Error Counter Create a New Column called "EventErrors" and add the last Code, I placed this after the RPC Check.

-----------------------------------------------------

    $HardDisk = Get-WmiObject Win32_LogicalDisk -ComputerName $server -Filter "DeviceID='C:'" | Select-Object Size,FreeSpace

    $DiskTotalSize = $HardDisk.Size
    $DiskFreeSpace = $HardDisk.FreeSpace

    $PercentageDS = (($DiskFreeSpace / $DiskTotalSize ) * 100); $PercentageDS = "{0:N2}" -f $PercentageDS

    if( [int] $PercentageDS -gt 15) { "Disk Free is normal [ $PercentageDS % ]" | LogMe -display; $tests.DiskFree = "SUCCESS", ($PercentageDS) }
    elseif([int] $UsedMemory -lt 15) { "Disk Free is Low [ $PercentageDS % ]" | LogMe -warning; $tests.DiskFree = "WARNING", ($PercentageDS) }    
    elseif([int] $UsedMemory -lt 5) { "Disk Free is Critical [ $PercentageDS % ]" | LogMe -error; $tests.DiskFree = "ERROR", ($PercentageDS) }
    elseif([int] $UsedMemory -eq 0) { "Disk Free test failed" | LogMe -error; $tests.DiskFree = "ERROR", "Err" }
    else { "Disk Free is Critical [ $PercentageDS % ]" | LogMe -error; $tests.DiskFree = "ERROR", ($PercentageDS) }  
    $PercentageDS = 0

---------------------------------------------------------------

    $EventCatch = @{}  
    $EventCatch = foreach ($log in "application", "system") {get-eventlog -ComputerName $server -LogName $log -EntryType error -After (Get-Date).Adddays(-1) }
    if ($EventCatch.Count -gt 0)
        { $tests.EventErrors = "ERROR", "Errors in Event Logs"; "Event Log Errors" | LogMe -display; $tests.EventErrors = "WARNING", $EventCatch.Count }
    else { $tests.EventErrors = "SUCCESS", "Success"; "No Event Log Errors" | LogMe -display; $tests.EventErrors = "SUCCESS", $EventCatch.Count  }

    }

----------------------------------------------------------------------------

Stan Czerno
October 20, 2014 02:53 CST

Nice job, thanks!

Matthew
October 31, 2014 01:30 CST

Hi Stan,

Great Job, I have been using a modified version of Jason's script for sometime and yours adds some items I have been looking into

Are you looking to add all the additional changes/comments above into your script as some of these I have in my own script and would save me some time adding them Smile

I currently run my script againsts workergroup membership as this is much cleaner than excluding servers/folders and editing a script when servers are added to the farm that i may not want monitored i.e dev servers. All you do is just add it to the healtcheck workgroup and they get monitored

Stan Czerno
October 31, 2014 02:15 CST

Thanks. I may eventually combine all of the additions. Aaron and Paul have done some nice work with their contributions.

Frank Bazan
December 1, 2014 08:56 CST

PLEASE DO!!!!
I'd love to see these in the report.

Stan Czerno
November 7, 2014 07:05 CST

I made a minor modification to the script in the Service Check portion. If the Service does not exist the page is supposed to reflect N/A but it was responding with an error. For example, an XenApp Session Only Server would not have the XML Service.

I changed line 209.

From: {   if (!(Get-Service -Display $ServiceName -ComputerName $server -ErrorAction Stop) ) { "$ServiceName is not available..." | LogMe -display; $ServiceResult = "N/A" }

To: {   if (!(Get-Service -Display $ServiceName -ComputerName $server -ErrorAction SilentlyContinue) ) { "$ServiceName is not available..." | LogMe -display; $ServiceResult = "N/A" }

Jeff Warber
November 19, 2014 09:24 CST

It looks as if it gets stuck in a loop. When a server doesn't have IMA running it looks like it will try to start the service and will just hang there. What could cause this?

Server is responding to ping
Logons are enabled
Active ICA sessions: 0
Disconnected ICA sessions: 0
Default Load Evaluator assigned
Socket connection on 3389 failed
Socket connection on 1494 failed
Socket Connection on 2598 Successful
CPU usage is normal [ 1.1 % ]
Error returned while checking the Memory usage. Perfmon Counters may be at fault
Memory usage test failed
Citrix Independent Management Architecture is not running
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...
WARNING: Waiting for service 'Citrix Independent Management Architecture (IMAService)' to finish starting...

Stan Czerno
November 21, 2014 01:45 CST

That is weird, does the service actually start?

I will try to reproduce...

empyre
December 9, 2014 04:59 CST

Jeff,

Sometimes you have to fix the IMA service.
****************************************
taskkill /f /im mfcom.exe
taskkill /f /im imaservice.exe
sc stop mfcom
sc stop imaservice
Dsmaint recreatelhc
Dsmaint recreaterade
sc start imaservice
sc start mfcom
********************************
you may need to reboot the server but it should work after this little fix.
I'm trying to find a way to incorporate this fix anytime the IMA service fails more than 3 times.
and even add this for more automation:
Anyone want to help?
********************************
$timeout = 300
$message = "Please save your work. You will be logged off in "+ $timeout/60 +" minutes"
$sessions = @()

# Collect session IDs and warn users
query session | select-string "wdica" |
%{$_ -replace " {2,27}"," "} |
foreach {$_.ToString().split(" ")[3]} |
foreach {
$sessions += $_
msg $_ /TIMEEmbarassedtimeout $message
}

# Wait for timeout
sleep $timeout

# Log off sessions
$sessions | foreach { logoff $_ }
*****************************************

Shane
March 20, 2015 08:36 CST

I am also getting this error when service is in a "starting" state. Is there any kind of timeout variable I can set?

WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...

Rick Bankers
December 5, 2014 08:06 CST

There seems to be an issue with gwmi and get-service where the script may hang on the request to the target device. I suggest wrapping those functions in a job and giving it a timeout of 30 seconds to respond, if there isn't a job "Completed" response have the check fail and move on to the next target or check.

Stan Czerno
December 5, 2014 08:09 CST

I will see what I can come up with, thanks for the suggestion.

David Griffiths
February 2, 2015 04:22 CST

Would you be able to add users per server and total users in the Farm

Van Hauwermeiren steven
February 3, 2015 18:38 CST

Hi, I love your script, but after some time (about 4 hours) the column MemUsage changes to the red color, but the values are all arround 30%. Also in the column AvgCPU we see some red colors but again the value is below 30%. Do you know what this can mean?
We are monioring 16 XenApp servers, script runs from a XenApp 65 controller.
Thanks
steven

Van Hauwermeiren steven
February 3, 2015 20:15 CST

extra info:
we are getting this as CPU and Memory usage values:

Server is responding to ping
Logons are enabled
Active ICA sessions: 17
Disconnected ICA sessions: 0
Default Load Evaluator assigned
Socket Connection on 3389 Successful
Socket Connection on 1494 Successful
ICA protocol responded
Socket Connection on 2598 Successful
CPU usage is Critical [ 16,8 % ]
Memory usage is Critical [ 45,74 % ]
Citrix Independent Management Architecture is running
Print Spooler is running
Citrix Print Manager Service is running
Citrix XML Service is not available...
Serverload is normal : 1400
WMI connection success
Server uptime days: 3.03:46:06.4910550
RPC responded

Why are they critical?

Stan Czerno
February 4, 2015 02:16 CST

Very strange. Did you make any modifications to the script? The reason I ask is because there are commas in the percentages. I am not sure where the commas are coming from.

I did a quick test using the comma values from your extra info and the script will show them as Critical.

$AvgCPUval = "16,8"
if( [int] $AvgCPUval -lt 80) { "CPU usage is normal [ $AvgCPUval % ]"}
elseif([int] $AvgCPUval -lt 90) { "CPU usage is medium [ $AvgCPUval % ]"}
elseif([int] $AvgCPUval -lt 95) { "CPU usage is high [ $AvgCPUval % ]"}
elseif([int] $AvgCPUval -eq 101) { "CPU usage test failed"}
else { "CPU usage is Critical [ $AvgCPUval % ]"}
$AvgCPUval = 0

You are going to need to figure out where the commas are coming from.

Rafael
August 13, 2015 08:15 CST

Chance in region and language in formats > additional settings > decimal symbol

Raja
February 10, 2015 04:12 CST

Hi Stan

Really great scripting work done, keep it up. done little changes according to our infra, it works cool.

But I am unable to include the C Drive Free space & percentage of the free space.

Aron/Stan,

Could someone please send the updated script with these columns C DriveFreeSpace & FreePercentage to me.

Thank you

Aaron Argent
February 10, 2015 16:37 CST

Hi Guys, I have modified the code above and created a Multiple Zones script you can run from different ZDC's to reduce the script runtime.  Also added in PVS RAMCache and DiskCache Check as well as the standard  "Ping", "Logons", "ActiveUsers", "DiscUsers", "LoadEvaluator", "ServerLoad", "RDPPort", "ICAPort", "SRPort", "AvgCPU", "MemUsg", "ContextSwitch", "DiskFree", "IMA", "CitrixPrint", "Spooler", "WMI", "RPC", "UptimeDays", "RAMCache", "vDiskCache", "vDiskImage"

Gets PVS RAMCache percentage from a CSV File created by a PowerShell script run on PVS Servers

Hope this is helpful and people can use components from it to improve their own Smile

#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# Script Name: XenAppStatus.ps1
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------


Param (
   [string[]]$LocationName
)

switch ($LocationName)
    {

        'ADE' {

            $StrGroup = "ADE"
            $excludedFolders = @("Servers/AKL","Servers/BNE","Servers/MEL","Servers/SYD","Servers")

            }
        'AKL' {

            $StrGroup = "AKL"
            $excludedFolders = @("Servers/ADE","Servers/BNE","Servers/MEL","Servers/SYD","Servers")

            }
        'BNE' {

            $StrGroup = "BNE"
            $excludedFolders = @("Servers/ADE","Servers/AKL","Servers/MEL","Servers/SYD","Servers")

            }
        'MEL' {

            $StrGroup = "MEL"
            $excludedFolders = @("Servers/ADE","Servers/AKL","Servers/BNE","Servers/SYD","Servers")

            }
        'SYD' {

            $StrGroup = "SYD"
            $excludedFolders = @("Servers/ADE","Servers/AKL","Servers/BNE","Servers/MEL","Servers")

            }
        default {

            $StrGroup = "BNE"
            $excludedFolders = @("Servers/ADE","Servers/AKL","Servers/MEL","Servers/SYD","Servers")

            }
    }

Clear-host


#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# User Definable Variables
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------


# Email Settings
# Multiple email addresses example: "email@domain.com,email2@domain.com"
$emailFrom     = ""
$emailTo       = ""
$emailCC       = ""
$smtpServer    = ""
$SendAlerts    = $false

$SendEmailWarnings = $false
$SendEmailErrors = $true

# Optional: Define the Load Evaluator to be checked in all the servers.
# Example: @("Default","Advanced").
$defaultLE = @("")

# Relative path to the PVS vDisk write cache file
$PvsWriteCache   = "d$\.vdiskcache"
$PvsWriteCache2  = "d$\vdiskdif.vhdx"

# Optional: Excluded folders from health check.
# Example: @("Servers/Application", "Servers/Std Instances")
#$excludedFolders = @("Servers")

# Server to be excluded with any particular name or name filter.
# Example: @("SRV1","SRV2")
$ServerFilter = @("")

# The maximum uptime days a server can report green.
$maxUpTimeDays = 10

# Ports used for the functionality check.
$RDPPort = "3389"
$ICAPort = "1494"
$sessionReliabilityPort = "2598"

# Test Session reliability Port?
$TestSessionReliabilityPort = "true"

# License Server Name for license usage.
$LicenseServer = "SERVERNAME.domain.local"

# License Type to be defined
# Example: @("MPS_PLT_CCU", "MPS_ENT_CCU", "XDT_ENT_UD")
#$LicenseTypes = @("MPS_ENT_CCU")
$LicenseTypes = @("XDT_ENT_UD")

# Alert Spam Protection Timeframe, in seconds
$EmailAlertsLagTime = "1800"

# Image Name for Webpage Logo. Store in Script Folder
$ImageName1 = "logo.jpg"

# Webserver Shared Folder Location
$HTMLServer = "\\SERVERNAME\c$\inetpub\wwwroot"
$HTMLPage   = "XenApp65_" +$StrGroup +".html"

# Webpage URL
$TopLevelURL = "http://SERVERNAME/"
$MonitorURL = $TopLevelURL + $HTMLPage

# Location of PVS Cache CSV File
$CSVFile = $HTMLServer +"\PVSCacheCSV.csv"

# TimeFrame for Emails
$int_Email_Start = 5
$int_Email_End = 20


#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# END - User Definable Variables
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------


#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# System Variables
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------


# Script Start Time
$script:startTime = Get-Date

# Reads the current directory path from the location of this file
$currentDir = Split-Path $MyInvocation.MyCommand.Path

# Define the Global variable and Check for the Citrix Snapin
If ((Get-PSSnapin "Citrix.*" -EA silentlycontinue) -eq $null)
    {
  
    Try { Add-PSSnapin Citrix.* -ErrorAction Stop }
  Catch { Write-Error "Error loading XenApp Powershell snapin"; Return }
    
    }

# Get farm details once to use throughout the script
$FarmDetails = Get-XAFarm
$CitrixFarmName = $FarmDetails.FarmName
$WebPageTitle = "$CitrixFarmName Health Status"

# Email Subject with the farm name
$emailSubject  = "Citrix Health Alert: " + $CitrixFarmName + "Farm - Site: " + $StrGroup

# Log files created in the location of script.
$LogFile = Join-Path $currentDir ("XenAppStatus_"+$StrGroup+".log")
$PreviousLogFile = Join-Path $currentDir ("XenAppStatus_"+$StrGroup+"_PreviousRun.log")
$ResultsHTML = Join-Path $currentDir ("XenAppStatus_"+$StrGroup+".html")
$AlertsFile = Join-Path $currentDir ("XenAppStatus_"+$StrGroup+"_Alerts.log")
$PreviousAlertsFile = Join-Path $currentDir ("XenAppStatus_"+$StrGroup+"_PreviousAlerts.log")
$AlertsEmailFile = Join-Path $currentDir ("XenAppStatus_"+$StrGroup+"_Email.log")

# Table headers
$headerNames  = "Ping", "Logons", "ActiveUsers", "DiscUsers", "LoadEvaluator", "ServerLoad", "RDPPort", "ICAPort", "SRPort", "AvgCPU", "MemUsg", "ContextSwitch", "DiskFree", "IMA", "CitrixPrint", "Spooler", "WMI", "RPC", "UptimeDays", "RAMCache", "vDiskCache", "vDiskImage"
$headerWidths = "6",      "6",      "6",           "6",         "6",          "6",          "4",       "4",     "5",      "5",      "5",   "5",  "6",  "6",    "6",           "8",       "8",   "6",   "8",   "8",   "8",   "8"

# Cell Colors
$ErrorStyle = "style=""background-color: #000000; color: #FF3300;"""
$WarningStyle = "style=""background-color: #000000;color: #FFFF00;"""

# Farm Average
$CPUAverage = 0
$RAMAverage = 0

# The variable to count the server names
[int]$TotalServers = 0; $TotalServersCount = 0

$allResults = @{}



#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# END - System Variables
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------


#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# Functions
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------


Function LogMe()
    {
    
    Param ( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $logEntry,
     [switch]$display,
     [switch]$error,
     [switch]$warning
     )

    If ($error) { Write-Host "$logEntry" -Foregroundcolor Red; $logEntry = "[ERROR] $logEntry" }
  ElseIf ($warning) { Write-Host "$logEntry" -Foregroundcolor Yellow; $logEntry = "[WARNING] $logEntry"}
  ElseIf ($display) { Write-Host "$logEntry" -Foregroundcolor Green; $logEntry = "$logEntry" }
    Else { Write-Host "$logEntry"; $logEntry = "$logEntry" }

  $logEntry | Out-File $LogFile -Append
    
    } #End Function: LogMe


Function CheckLicense()
    {

  If (!$LicenseServer) { "No License Server Name defined" | LogMe -Error; $LicenseResult = " Error; Check Detailed Logs "; return $LicenseResult }
  If (!$LicenseTypes) { "No License Type defined" | LogMe -Error; $LicenseResult = " Error; Check Detailed Logs "; return $LicenseResult }
  
  [int]$TotalLicense = 0; [int]$InUseLicense = 0; [int]$PercentageLS = 0; $LicenseResult = " "
  
  Try
      {
        
        If (Get-Service -Display "Citrix Licensing" -ComputerName $LicenseServer -ErrorAction Stop) { "Citrix Licensing service is available." | LogMe -Display }
    Else { "Citrix Licensing' service is NOT available." | LogMe -Error; Return "Error; Check Logs" }

    Try
            {
           
            If ($licensePool = gwmi -class "Citrix_GT_License_Pool" -Namespace "ROOT\CitrixLicensing" -comp $LicenseServer -ErrorAction Stop)
        {
                
                "License Server WMI Class file found" | LogMe -Display
        $LicensePool | ForEach-Object{
                    
                    Foreach ($Ltype in $LicenseTypes)
            {

                        If ($_.PLD -match $Ltype) { $TotalLicense = $TotalLicense + $_.count; $InUseLicense = $InUseLicense + $_.InUseCount }

                        }

                    }
  
        "The total number of licenses available: $TotalLicense " | LogMe -Display
        "The number of licenses are in use: $InUseLicense " | LogMe -Display
        If (!(($InUseLicense -eq 0) -or ($TotalLicense -eq 0 ))) { $PercentageLS = (($InUseLicense / $TotalLicense ) * 100); $PercentageLS = "{0:N2}" -f $PercentageLS }
        
        If ($PercentageLS -gt 90) { "The License usage is $PercentageLS % " | LogMe -Error }
        ElseIf ($PercentageLS -gt 80) { "The License usage is $PercentageLS % " | LogMe -Warning }
        Else { "The License usage is $PercentageLS % " | LogMe -Display }
  
        $LicenseResult = "$InUseLicense/$TotalLicense [ $PercentageLS % ]"; return $LicenseResult

                }

            }
        Catch
            {
            
            $ErrorMessage = $_.Exception.Message
            $FailedItem = $_.Exception.ItemName
            "License Server WMI Class file failed. An Error Occured while capturing the License information" | LogMe -Error
            "You may need to uninstall your License Server and reinstall." | LogMe -Error
            "There are known issues with doing an in place upgrade of the license service." | LogMe -Error
      $LicenseResult = " Error; Check Detailed Logs "; return $LicenseResult

            }

        }
    Catch { "Error returned while checking the Licensing Service. Server may be down or some permission issue" | LogMe -error; return "Error; Check Detailed Logs" }

    } #End Function: CheckLicense


Function CheckService()
    {

  Param ($ServiceName)
  
    Try
      {

        If (!(Get-Service -Display $ServiceName -ComputerName $server -ErrorAction Stop) ) { "$ServiceName is not available..." | LogMe -display; $ServiceResult = "N/A" }
      Else
            {
          
            If ((Get-Service -Display $ServiceName -ComputerName $server -ErrorAction Stop).Status -Match "Running") { "$ServiceName is running" | LogMe -Display; $ServiceResult = "Success" }
          Else
                {
                
                "$ServiceName is not running"  | LogMe -error
        
                Try
                    {
                    
                    Start-Service -InputObject $(Get-Service -Display $ServiceName -ComputerName $server) -ErrorAction Stop
          "Start command sent for $ServiceName"  | LogMe -warning
                Start-Sleep 5 # Sleep a bit to allow service to start
          If ((Get-Service -Display $ServiceName -ComputerName $server).Status -Match "Running") { "$ServiceName is now running" | LogMe -Display; $ServiceResult = "Success" }
          Else {  "$ServiceName failed to start."  | LogMe -error  $ServiceResult = "Error" }

                    }
                Catch { "Start command failed for $ServiceName. You need to check the server." | LogMe -Error; return "Error" }
                
                }
            }

      return $ServiceResult

      }
    Catch { "Error while checking the Service. Server may be down or has a permission issue." | LogMe -error; return "Error" }

    } #End Function: CheckService


Function CheckCpuUsage()
    {
  
    Param ($hostname)

  Try
        {
        
        $CpuUsage = (get-counter -ComputerName $hostname -Counter "\Processor(_Total)\% Processor Time" -SampleInterval 1 -MaxSamples 5 -ErrorAction Stop | select -ExpandProperty countersamples | select -ExpandProperty cookedvalue | Measure-Object -Average).average
      $CpuUsage = "{0:N1}" -f $CpuUsage; return $CpuUsage

        }
    Catch { "Error returned while checking the CPU usage. Perfmon Counters may be at fault." | LogMe -error; return 101 }

    } #End Function: CheckCpuUsage


Function CheckContextSwitch()
    {
  
    Param ($hostname)

  Try
        {

        $ContextSwitch = (get-wmiobject -Computer $hostname -Class "Win32_PerfFormattedData_PerfOS_System" -ErrorAction Stop | Select-Object ContextSwitchesPersec )
        $ContextSwitchPref = $ContextSwitch.ContextSwitchesPersec

        return $ContextSwitchPref

        }
    Catch { "Error returned while checking the Context Switch performance. Perfmon Counters may be at fault." | LogMe -error; return 101 }

    } #End Function: CheckContextSwitch
    

Function CheckMemoryUsage()
    {
  
    Param ($hostname)
    
    Try
      {
        
        $SystemInfo = (Get-WmiObject -Computername $hostname -Class Win32_OperatingSystem -ErrorAction Stop | Select-Object TotalVisibleMemorySize, FreePhysicalMemory)
      $TotalRAM = $SystemInfo.TotalVisibleMemorySize/1MB
      $FreeRAM = $SystemInfo.FreePhysicalMemory/1MB
      $UsedRAM = $TotalRAM - $FreeRAM
      $RAMPercentUsed = ($UsedRAM / $TotalRAM) * 100
      $RAMPercentUsed = "{0:N2}" -f $RAMPercentUsed
      
        return $RAMPercentUsed

        }
    Catch { "Error returned while checking the Memory usage. Perfmon Counters may be at fault" | LogMe -error; return 101 }
    
    } #End Function: CheckMemoryUsage


Function Ping ([string]$hostname, [int]$timeout)
    {

    $ping = new-object System.Net.NetworkInformation.Ping #creates a ping object
  
    Try { $result = $ping.send($hostname, $timeout).Status.ToString() }
    Catch { $result = "Failed" }
  
    return $result
    
    } #End Function: Ping


Function Check-Port()
    {

  Param ([string]$hostname, [string]$port)

    Try { $socket = new-object System.Net.Sockets.TcpClient($hostname, $Port) -ErrorAction Stop } #creates a socket connection to see if the port is open
    Catch { $socket = $null; "Socket connection on $port failed" | LogMe -error; return $false }

  If ($socket -ne $null)
        {
        
        "Socket Connection on $port Successful" | LogMe -Display

        If ($port -eq "1494")
            {
        
            $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 -Display; return $true }

          }

      "ICA did not respond correctly" | LogMe -error; return $false
    
            }
        Else { return $true }

        }
    Else { "Socket connection on $port failed" | LogMe -error; return $false }

    } #End Function: Check-Port


Function writeHtmlHeader
    {

  Param ($title, $fileName)
  
    $date = ( Get-Date -format g)
    $head = @"
    <html>
    <head>
    <meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>
    <meta http-equiv="refresh" content="60">
    <title>$title</title>
    <STYLE TYPE="text/css">
    <!--
    td {
        font-family: Lao UI;
        font-size: 11px;
        border-top: 1px solid #999999;
        border-right: 1px solid #999999;
        border-bottom: 1px solid #999999;
        border-left: 1px solid #999999;
        padding-top: 0px;
        padding-right: 0px;
        padding-bottom: 0px;
        padding-left: 0px;
        overflow: hidden;}

    .header {
      font-family: Tahoma;
    font-size: 40px;
    font-weight:bold;
    border-top: 1px solid #999999;
    border-right: 1px solid #999999;
    border-bottom: 1px solid #999999;
    border-left: 1px solid #999999;
    padding-top: 0px;
    padding-right: 0px;
    padding-bottom: 0px;
    padding-left: 0px;
        overflow: hidden;
    color:#FFFFFF;
    text-shadow:2px 2px 10px #000000;

        }
    body {
        margin-left: 5px;
        margin-top: 5px;
        margin-right: 0px;
        margin-bottom: 10px;
        table {
            table-layout:fixed;
            border: thin solid #FFFFFF;}
  .shadow {
    height: 1em;
    filter: Glow(Color=#000000,
    Direction=135,
    Strength=5);}
        -->
    </style>
    </head>
    <body>
        <table class="header" width='100%'>
        <tr bgcolor='#FAFAFA'>
        <td style="text-align: center; text-shadow: 2px 2px 2px #ff0000;">
        <img src="$ImageName1">
        </td>
        <td class="header" width='826' align='center' valign="middle" style="background-image: url('ekg_wide.jpg'); background-repeat: no-repeat; background-position: center; ">
        <p class="shadow"> $CitrixFarmName<br>Health Status </p>
        </tr>
        </table>
        <table width='100%'>
        <tr bgcolor='#CCCCCC'>
        <td width=33% align='center' valign="middle">
        <font face='Tahoma' color='#8A0808' size='2'><strong>Site ($StrGroup) Last Queried: $date</strong></font>
        </td>
        </tr>
        </table>

        <table width='100%'>
        <tr bgcolor='#CCCCCC'>
        <td align='center' valign="middle">
        <font face='Tahoma' color='#8A0808' size='2'><strong><a href="http://servername/xenapp65_ADE.html">Adelaide Site</a></strong></font>
        </td>
        <td align='center' valign="middle">
        <font face='Tahoma' color='#8A0808' size='2'><strong><a href="http://servername/xenapp65_AKL.html">Auckland Site</a></strong></font>
        </td>
        <td align='center' valign="middle">
        <font face='Tahoma' color='#8A0808' size='2'><strong><a href="http://servername/xenapp65_BNE.html">Brisbane Site</a></strong></font>
        </td>
        <td align='center' valign="middle">
        <font face='Tahoma' color='#8A0808' size='2'><strong><a href="http://servername/xenapp65_MEL.html">Melbourne Site</a></strong></font>
        </td>
        <td align='center' valign="middle">
        <font face='Tahoma' color='#8A0808' size='2'><strong><a href="http://servername/xenapp65_SYD.html">Sydney Site</a></strong></font>
        </td>
        </tr>
        </table>

        <table width='100%'>
        <tr bgcolor='#CCCCCC'>
        <td width=50% align='center' valign="middle">
        <font face='Tahoma' color='#003399' size='2'><strong>Number of Servers in Site: $TotalServersCount</strong></font>
        <td width=50% align='center' valign="middle">
        <font face='tahoma' color='#003399' size='2'><strong>Citrix License Usage:  $LicenseReport</strong></font>
        </td>
        </tr>
        </table>
        <table width='100%'>
        <tr bgcolor='#CCCCCC'>
        <td width=50% align='center' valign="middle">
        <font face='Tahoma' color='#003399' size='2'><strong>Active Sessions:  $TotalActiveSessions [ ICA $TotalICAActiveSessions | RDP $TotalRDPActiveSessions ]</strong></font>
        <td width=50% align='center' valign="middle">
        <font face='tahoma' color='#003399' size='2'><strong>Disconnected Sessions:  $TotalDisconnectedSessions [ ICA $TotalICADisconnectedSessions | RDP $TotalRDPDisconnectedSessions ]</strong></font>
        </td>
        </tr>
        </table>
        <table width='100%'>
        <tr bgcolor='#CCCCCC'>
        <td width=50% align='center' valign="middle">
        <font face='Tahoma' color='#003399' size='2'><strong>Average CPU:  $CPUAverage %</strong></font>
        <td width=50% align='center' valign="middle">
        <font face='tahoma' color='#003399' size='2'><strong>Average RAM:  $RAMAverage %</strong></font>
        </td>
        </tr>
        </table>
"@

    $head | Out-File $fileName

    } #End Function: writeHtmlHeader


Function writeTableHeader
    {
  
    Param ($fileName)
  
    $tableHeader = @"
    <table width='100%'><tbody>
    <tr bgcolor=#CCCCCC>
    <td width='12%' align='center'><strong>ServerName</strong></td>
"@

    $i = 0

    While ($i -lt $headerNames.count)
        {

        $headerName = $headerNames[$i]
        $headerWidth = $headerWidths[$i]
        #$tableHeader += "<td width='" + $headerWidth + "%' align='center'><strong>$headerName</strong></td>"
        $tableHeader += "<td align='center'><strong>$headerName</strong></td>"
        $i++
        
        }

    $tableHeader += "</tr>"
    $tableHeader | Out-File $fileName -append

    } #End Function: writeTableHeader


Function writeData
    {

  Param ($data, $fileName)
  
  $data.Keys | sort | foreach {

        $tableEntry += "<tr>"
      $computerName = $_
      #$tableEntry += ("<td bgcolor='#CCCCCC' align=center><font color='#003399'><a href='.\HostStatus.html?$computerName'>$computerName</a></font></td>")
        $tableEntry += ("<td bgcolor='#CCCCCC' align=center><font color='#003399'>$computerName</font></td>")

      $headerNames | foreach {
            Try
                {
      
                If ($data.$computerName.$_[1] -eq $null ) { $bgcolor = "#FF0000"; $fontColor = "#FFFFFF"; $testResult = "Err" }
                Else
                    {
        
                    If ($data.$computerName.$_[0] -eq "SUCCESS") { $bgcolor = "#387C44"; $fontColor = "#FFFFFF" }
            ElseIf ($data.$computerName.$_[0] -eq "WARNING") { $bgcolor = "#F5DA81"; $fontColor = "#000000" }
            ElseIf ($data.$computerName.$_[0] -eq "ERROR") { $bgcolor = "#FF0000"; $fontColor = "#000000" }
            Else { $bgcolor = "#CCCCCC"; $fontColor = "#003399" }
        
                  $testResult = $data.$computerName.$_[1]

            }
            
                }
            Catch { $bgcolor = "#CCCCCC"; $fontColor = "#003399"; $testResult = "N/A" }

        $tableEntry += ("<td bgcolor='" + $bgcolor + "' align=center><font color='" + $fontColor + "'>$testResult</font></td>")

        }

      $tableEntry += "</tr>"

      }

  $tableEntry | Out-File $fileName -append

    } #End Function: writeData


Function FindErrors
    {
    
  Param ($data)

    Add-Content $AlertsFile "Server,Type,Component,Value"

    If (Test-Path $AlertsEmailFile) { RM $AlertsEmailFile }
  
    Add-Content $AlertsEmailFile "Server,Type,Component,Value,Status"

    $data.Keys | sort | foreach {

        $computerName = $_
        $headerNames | foreach {
        
            Try
                {

                If ($data.$computerName.$_[1] -eq $null ) { $testResult = "Err" }
                Else
                    {

                    If (($data.$computerName.$_[0] -eq "WARNING") -Or ($data.$computerName.$_[0] -eq "ERROR"))
                        {
                        
                        $strPreviousAlert =""

                        $alertServer = $computerName
                        $alertType = $data.$computerName.$_[0]
                        #$alertValue = $data.$computerName.$_[1] | out-string
                        $alertValue = $data.$computerName.$_[1]
                        $alertComp = $_

                        $strOutput = $AlertServer +',' +$alertType +',' +$AlertComp +',' +$AlertValue

                        Add-Content $AlertsFile $strOutput

                        If (Test-Path $PreviousAlertsFile)
                            {
                        
                            $strPreviousAlert = Import-CSV $PreviousAlertsFile | Where { $_.Server -eq $AlertServer -And $_.Type -eq $alertType -And $_.Component -eq $alertComp }
                                    
                            If (($strPreviousAlert -ine "") -And ($strPreviousAlert -ine $null))
                                {

                                ForEach ($aline in $strPreviousAlert)
                                    {

                                    If ($alertComp -ieq $aline.Component)
                                        {
                                                                        
                                        If ($alertValue -ine $aline.Value)
                                            {

                                            If ($alertValue -gt $aline.Value)
                                                {

                                                Write-Host "Alert Exisits: " $strOutput
                                                Write-Host $AlertServer "Alert " $alertComp "value has Increased: " $aline.Value " -> " $alertValue

                                                If ($alertType -ieq "ERROR")
                                                    {

                                                    $strEmailOutput = $strOutput +',Increased'
                                                    Add-Content $AlertsEmailFile $strEmailOutput

                                                    }

                                                }

                                            }

                                        If ($alertType -ine $aline.Type)
                                            {

                                            Write-Host "Alert Type Changed:" $strOutput

                                            If ($alertType -eq "ERROR")
                                                {

                                                $strEmailOutput = $strOutput +',Changed'
                                                Add-Content $AlertsEmailFile $strEmailOutput

                                                }

                                            }
                                        }
                                    Else
                                        {

                                        Write-Host "Alert Does not Exisit:" $strOutput

                                        $strEmailOutput = $strOutput +',New'
                                        Add-Content $AlertsEmailFile $strEmailOutput

                                        }

                                    }

                                }
                            Else
                                {

                                Write-Host "Alert Does not Exisit:" $strOutput

                                $strEmailOutput = $strOutput +',New'
                                Add-Content $AlertsEmailFile $strEmailOutput

                                }

                            }
                        Else
                            {
          
                            Write-Host "Alert Does not Exisit:" $strOutput

                            $strEmailOutput = $strOutput +',New'
                            Add-Content $AlertsEmailFile $strEmailOutput

                            }

                        }

                    $testResult = $data.$computerName.$_[1]

            }
                }
            Catch { $testResult = "N/A" }

            }

        }

    } #End Function: FindErrors


Function writeHtmlFooter
    {
  
    Param ($fileName)

    #$footer=("<br><font face='HP Simplified' color='#003399' size='2'><br><I>Report last updated on {0}.<br> Script Hosted on server {3}.<br>Script Path: {4}</font>" -f (Get-Date -displayhint date),$env:userdomain,$env:username,$env:COMPUTERNAME,$currentDir)
  
    $footer = @"
    </table>
    </body>
    </html>
"@

    $footer | Out-File $FileName -append

    } #End Function: writeHtmlFooter


Function GetElapsedTime([datetime]$starttime)
    {

    $runtime = $(get-date) - $starttime
    $retStr = [string]::format("{0} sec(s)", $runtime.TotalSeconds)
    $retStr

    } #End Function: GetElapsedTime


#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# END - Functions
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------


#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# Main Program
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------


If (Test-Path $LogFile) { Copy $LogFile $PreviousLogFile }

If (Test-Path $AlertsFile)
    {

    Copy $AlertsFile $PreviousAlertsFile
    Clear-Content $AlertsFile
        
    }

RM $LogFile -force -EA SilentlyContinue

"Script Started at $script:startTime" | LogMe -display
"Processing Location: $StrGroup" | LogMe -display
" " | LogMe -display


"Checking Citrix License usage on $LicenseServer" | LogMe -Display
$LicenseReport = CheckLicense


" " | LogMe; "Checking Citrix XenApp Server Health." | LogMe ; " " | LogMe


$sessions = Get-XASession -Farm | where-object {$_.ServerName -match $StrGroup}
    

Get-XAServer | where-object {$_.ServerName -match $StrGroup} | Sort-Object ServerName | % {

    $tests = @{}  
    
    # Check If Server is in Excluded Folder path or server list
    #If ($excludedFolders -contains $_.FolderPath) { $_.ServerName + " in excluded Server folder - skipping" | LogMe -Display; "" | LogMe; return }
    #If ($ServerFilter -contains $_.ServerName) { $_.ServerName + " is excluded in the Server List  - skipping" | LogMe -Display; "" | LogMe; return }

    [int]$TotalServers = [int]$TotalServers + 1; $server = $_.ServerName

    "Server Name: $server" | LogMe

    $ProcessTime = Get-Date -format R
    "Processing Time: $ProcessTime" | LogMe

#    $WorkerGroups = $null, (Get-XAWorkerGroup -ServerName $server | % {$_.WorkerGroupName})
    
#    If ($WorkerGroups -eq $null)
#        {
#
#        "WorkerGroups: N/A "
#        $tests.WorkerGroups = $null, "N/A"
#
#        }
#    Else
#        {
#
#        "WorkerGroupsEmbarassedWorkerGroups "
#        $tests.WorkerGroups = $WorkerGroups
#
#        }
  

    # Ping Remote Server
    $result = Ping $server 1000
    If ($result -ne "SUCCESS")
        {

        $tests.Ping = "ERROR", $result; "NOT able to ping - skipping " | LogMe -error

        }
    Else
        {  

        $tests.Ping = "SUCCESS", $result;  "Server is responding to ping" | LogMe -Display
        

        # Check Logon Mode
        $logonMode = $_.LogonMode
        If ($logonMode -ine 'AllowLogOns'){ "Logon Mode: $logonMode " | LogMe -error; $tests.Logons = "ERROR", "Disabled" }
        Else { "Logon Mode: $logonMode " | LogMe -Display; $tests.Logons = "SUCCESS", "Enabled" }
        
#        If ($_.LogOnsEnabled -eq $false) { "Logons are disabled " | LogMe -error; $tests.Logons = "ERROR", "Disabled" }
#        Else { "Logons are enabled " | LogMe -Display; $tests.Logons = "SUCCESS","Enabled" }


      # Get Active Sessions
      $activeServerSessions = [array]($sessions | ? {$_.State -eq "Active" -and $_.Protocol -ne "Console" -and $_.ServerName -match $server})

      If ($activeServerSessions) { $totalActiveServerSessions = $activeServerSessions.count }
      Else { $totalActiveServerSessions = 0 }

        $tests.ActiveUsers = "SUCCESS", $totalActiveServerSessions

        $ICAActiveSessions = [array]($sessions | ? {$_.State -eq "Active" -and $_.Protocol -eq "Ica" -and $_.ServerName -match $server})
        $ICATotalActiveServerSessions = $ICAActiveSessions.Count
        
        $RDPActiveSessions = [array]($sessions | ? {$_.State -eq "Active" -and $_.Protocol -eq "Rdp" -and $_.ServerName -match $server})
        $RDPTotalActiveServerSessions = $RDPActiveSessions.Count
        
        "Active sessions: ICA $ICATotalActiveServerSessions | RDP $RDPTotalActiveServerSessions" | LogMe -display

    
        # Get Disconnected Sessions
      $discServerSessions = [array]($sessions | ? {$_.State -eq "Disconnected" -and $_.Protocol -ne "Console" -and $_.ServerName -match $server})
  
        If ($discServerSessions) { $totalDiscServerSessions = $discServerSessions.count }
      Else { $totalDiscServerSessions = 0 }
    
        $tests.DiscUsers = "SUCCESS", $totalDiscServerSessions

        $ICADiscSessions = [array]($sessions | ? {$_.State -eq "Disconnected" -and $_.Protocol -eq "Ica" -and $_.ServerName -match $server})
        $ICATotalDiscServerSessions = $ICADiscSessions.Count
    
        $RDPDiscSessions = [array]($sessions | ? {$_.State -eq "Disconnected" -and $_.Protocol -eq "Rdp" -and $_.ServerName -match $server})
        $RDPTotalDiscServerSessions = $RDPDiscSessions.Count
    
        "Disconnected sessions: ICA $ICATotalDiscServerSessions | RDP $RDPTotalDiscServerSessions" | LogMe -display
  

        # Warning If Disconnected Sessions Greater Than Active Sessions.
        If ($totalDiscServerSessions -gt $totalActiveServerSessions) { $tests.DiscUsers = "WARNING", $totalDiscServerSessions }


      # Check Load Evaluator
      $LEFlag = 0; $CurrentLE = ""
      $CurrentLE = (Get-XALoadEvaluator -ServerName $server).LoadEvaluatorName

      Foreach ($LElist in $defaultLE)
            {

            If ($CurrentLE -match $LElist)
                {    
            
                "Default Load Evaluator assigned" | LogMe -display
                $tests.LoadEvaluator = "SUCCESS", $CurrentLE
                $LEFlag = 1; break
                
                }

            }

        If ($LEFlag -eq 0 )
            {

            If ($CurrentLE -match "Offline")
                {

            "Server is in Offline LE; Please check the box" | LogMe -error
            $tests.LoadEvaluator = "WARNING", $CurrentLE
                
                }
            Else
                {

                "Non-default Load Evaluator assigned" | LogMe -warning
                $tests.LoadEvaluator = "WARNING", $CurrentLE

                }
        
            }


        # Test RDP Port
        If (Check-Port $server $RDPPort) { $tests.RDPPort = "SUCCESS", "Success" }
        Else { $tests.RDPPort = "ERROR", "$vDiskCacheSize" }        


        # Test ICA Port
        If (Check-Port $server $ICAPort) { $tests.ICAPort = "SUCCESS", "Success" }
        Else { $tests.ICAPort = "ERROR","No Response" }


        # Test Session Reliability Port  
        If ($TestSessionReliabilityPort -eq "True")
            {
            
            If (Check-Port $server $sessionReliabilityPort) { $tests.SRPort = "SUCCESS", "Success" }
            Else { $tests.SRPort = "ERROR", "No Response" }

            }


        # Check Average CPU Value
        $AvgCPUval = CheckCpuUsage ($server)

        If ( [int] $AvgCPUval -lt 80) { "CPU usage is normal [ $AvgCPUval % ]" | LogMe -display; $tests.AvgCPU = "SUCCESS", ($AvgCPUval) }
    ElseIf ([int] $AvgCPUval -lt 90) { "CPU usage is medium [ $AvgCPUval % ]" | LogMe -warning; $tests.AvgCPU = "WARNING", ($AvgCPUval) }    
    ElseIf ([int] $AvgCPUval -lt 95) { "CPU usage is high [ $AvgCPUval % ]" | LogMe -error; $tests.AvgCPU = "ERROR", ($AvgCPUval) }
    ElseIf ([int] $AvgCPUval -eq 101) { "CPU usage test failed" | LogMe -error; $tests.AvgCPU = "ERROR", "Err" }
        Else { "CPU usage is Critical [ $AvgCPUval % ]" | LogMe -error; $tests.AvgCPU = "ERROR", ($AvgCPUval) }  
        
        $CPUAverage =  $CPUAverage + $AvgCPUval

        $AvgCPUval = 0


        # Check Memory Usage
        $UsedMemory = CheckMemoryUsage ($server)

        If ( [int] $UsedMemory -lt 80) { "Memory usage is normal [ $UsedMemory % ]" | LogMe -display; $tests.MemUsg = "SUCCESS", ($UsedMemory) }
    ElseIf ([int] $UsedMemory -lt 85) { "Memory usage is medium [ $UsedMemory % ]" | LogMe -warning; $tests.MemUsg = "WARNING", ($UsedMemory) }    
    ElseIf ([int] $UsedMemory -lt 90) { "Memory usage is high [ $UsedMemory % ]" | LogMe -error; $tests.MemUsg = "ERROR", ($UsedMemory) }
    ElseIf ([int] $UsedMemory -eq 101) { "Memory usage test failed" | LogMe -error; $tests.MemUsg = "ERROR", "Err" }
        Else { "Memory usage is Critical [ $UsedMemory % ]" | LogMe -error; $tests.MemUsg = "ERROR", ($UsedMemory) }  

        $RAMAverage = $RAMAverage + $UsedMemory

    $UsedMemory = 0


        # Check Context Switching Value
        $ContextSwitchval = CheckContextSwitch ($server)

        If ( [int] $ContextSwitchval -lt 45000) { "Context Switches is normal [ $ContextSwitchval ]" | LogMe -display; $tests.ContextSwitch = "SUCCESS", ($ContextSwitchval) }
    ElseIf ([int] $ContextSwitchval -gt 45000) { "Context Switches is medium [ $ContextSwitchval ]" | LogMe -warning; $tests.ContextSwitch = "WARNING", ($ContextSwitchval) }    
    ElseIf ([int] $ContextSwitchval -gt 60000) { "Context Switches is high [ $ContextSwitchval ]" | LogMe -error; $tests.ContextSwitch = "ERROR", ($ContextSwitchval) }
    ElseIf ([int] $ContextSwitchval -eq 0) { "Context Switches test failed" | LogMe -error; $tests.ContextSwitch = "ERROR", "Err" }
        Else { "Context Switches is Critical [ $ContextSwitchval % ]" | LogMe -error; $tests.ContextSwitch = "ERROR", ($ContextSwitchval) }  

        $ContextSwitchval = 0


        # Check Disk Usage
        $HardDisk = Get-WmiObject Win32_LogicalDisk -ComputerName $server -Filter "DeviceID='C:'" | Select-Object Size,FreeSpace

        $DiskTotalSize = $HardDisk.Size
        $DiskFreeSpace = $HardDisk.FreeSpace

        $PercentageDS = (($DiskFreeSpace / $DiskTotalSize ) * 100); $PercentageDS = "{0:N2}" -f $PercentageDS

        If ( [int] $PercentageDS -gt 15) { "Disk Free is normal [ $PercentageDS % ]" | LogMe -display; $tests.DiskFree = "SUCCESS", ($PercentageDS) }
    ElseIf ([int] $PercentageDS -lt 15) { "Disk Free is Low [ $PercentageDS % ]" | LogMe -warning; $tests.DiskFree = "WARNING", ($PercentageDS) }    
    ElseIf ([int] $PercentageDS -lt 5) { "Disk Free is Critical [ $PercentageDS % ]" | LogMe -error; $tests.DiskFree = "ERROR", ($PercentageDS) }
    ElseIf ([int] $PercentageDS -eq 0) { "Disk Free test failed" | LogMe -error; $tests.DiskFree = "ERROR", "Err" }
        Else { "Disk Free is Critical [ $PercentageDS % ]" | LogMe -error; $tests.DiskFree = "ERROR", ($PercentageDS) }  
    
        $PercentageDS = 0


        # Check Services
        $ServiceOP = CheckService ("Citrix Independent Management Architecture")
        If ($ServiceOP -eq "Error")  { $tests.IMA = "ERROR", $ServiceOP }
        Else { $tests.IMA = "SUCCESS", $ServiceOP }

        $ServiceOP = CheckService ("Print Spooler")
        If ($ServiceOP -eq "Error")  { $tests.Spooler = "ERROR", $ServiceOP }
        Else { $tests.Spooler = "SUCCESS", $ServiceOP }

        $ServiceOP = CheckService ("Citrix Print Manager Service")
        If ($ServiceOP -eq "Error")  { $tests.CitrixPrint = "ERROR", $ServiceOP }
        Else { $tests.CitrixPrint = "SUCCESS", $ServiceOP }
    

        # Check Server Load
      If ($tests.IMA[0] -eq "Success")
            {
            
            $CurrentServerLoad = Get-XAServerLoad -ServerName $server

        If ([int] $CurrentServerLoad.load -lt 7500)
                {
      
                If ([int] $CurrentServerLoad.load -eq 0) { $tests.ActiveUsers = "SUCCESS", $totalActiveServerSessions; $tests.DiscUsers = "SUCCESS", $totalDiscServerSessions }

        "Serverload is normal [ $CurrentServerload ]" | LogMe -display; $tests.Serverload = "SUCCESS", ($CurrentServerload.load)

                }
      ElseIf ([int] $CurrentServerLoad.load -lt 8500) { "Serverload is Medium [ $CurrentServerload ]" | LogMe -warning; $tests.Serverload = "WARNING", ($CurrentServerload.load) }
      ElseIf ([int] $CurrentServerLoad.load -eq 20000) { "Serverload Fault [ Could not Contact License Server ]" | LogMe -Error; $tests.Serverload = "ERROR", "LS Err" }    
      ElseIf ([int] $CurrentServerLoad.load -eq 99999) { "Serverload Fault [ No Load Evaluator is Configured ]" | LogMe -Error; $tests.Serverload = "ERROR", "No LE" }
      ElseIf ([int] $CurrentServerLoad.load -eq 10000) { "Serverload Full [ $CurrentServerload ]" | LogMe -Error; $tests.Serverload = "ERROR", ($CurrentServerload.load) }
      Else { "Serverload is High [ $CurrentServerload ]" | LogMe -error; $tests.Serverload = "ERROR", ($CurrentServerload.load) }

            }
        Else { "Server load can't be determine since IMA failed " | LogMe -error; $tests.Serverload = "ERROR", "IMA Err" }

        $CurrentServerLoad = 0

  
        # Test WMI
        $tests.WMI = "ERROR","Error"
      Try { $wmi=Get-WmiObject -class Win32_OperatingSystem -computer $_.ServerName }
      Catch {  $wmi = $null }
    
        # Perform WMI related checks
      If ($wmi -ne $null)
            {

        $tests.WMI = "SUCCESS", "Success"; "WMI connection success" | LogMe -display
        $LBTime=$wmi.ConvertToDateTime($wmi.Lastbootuptime)
        [TimeSpan]$uptime=New-TimeSpan $LBTime $(get-date)
        
            If ($uptime.days -gt $maxUpTimeDays) { "Server reboot warning, last reboot: {0Laughing}" -f $LBTime | LogMe -warning; $tests.UptimeDays = "WARNING", $uptime.days }
            Else { "Server uptime days: $uptime" | LogMe -display; $tests.UptimeDays = "SUCCESS", $uptime.days }
            
            }
        Else { "WMI connection failed - check WMI for corruption" | LogMe -error }

            
        If (Get-WmiObject win32_computersystem -ComputerName $server -ErrorAction SilentlyContinue)
            {
            
            $tests.RPC = "SUCCESS", "Success"; "RPC responded" | LogMe -Display  
            
            }
        Else { $tests.RPC = "ERROR", "No Response"; "RPC failed" | LogMe -error }


        # Check PVS
        If (Test-Path \\$Server\c$\Personality.ini)
            {

            $RAMCacheSize = 0
            $vDiskCacheSize = 0
        
            $PvsWriteCacheUNC = Join-Path "\\$Server" $PvsWriteCache
            $vDiskexists  = Test-Path $PvsWriteCacheUNC

            If ($vDiskexists -eq $False)
                {
            
                $PvsWriteCacheUNC = Join-Path "\\$Server" $PvsWriteCache2
                $vDiskexists = Test-Path $PvsWriteCacheUNC
            
                $CacheSize = Import-CSV $CSVFile | Where {$_.Server -eq $server}
            
                If ($CacheSize.CacheSize -ine "")
                    {
                
                    $RAMCacheSize = $CacheSize.CacheSize
                
                    }

          }

        If ($vDiskexists -eq $True)
          {

                $CacheDisk = [long] ((get-childitem $PvsWriteCacheUNC -force).length)
                $HardDiskD = Get-WmiObject Win32_LogicalDisk -ComputerName $server -Filter "DeviceID='D:'" | Select-Object FreeSpace
                $DiskDFreeSpace = $HardDiskD.FreeSpace
                $PercentageDS = (($CacheDisk / $DiskDFreeSpace ) * 100); $PercentageDS = "{0:N2}" -f $PercentageDS
                $vDiskCacheSize = [math]::Round($PercentageDS)
                
          }              

            If ($RAMCacheSize -ine 0)
                {

                If ( [int] $RAMCacheSize -lt 80) { "PVS RAM Cache usage is normal [ $RAMCacheSize % ]" | LogMe -display; $tests.RAMCache = "SUCCESS", ($RAMCacheSize) }
                ElseIf ([int] $RAMCacheSize -lt 90) { "PVS RAM Cache usage is medium [ $RAMCacheSize % ]" | LogMe -warning; $tests.RAMCache = "WARNING", ($RAMCacheSize) }    
            ElseIf ([int] $RAMCacheSize -lt 95) { "PVS RAM Cache usage is high [ $RAMCacheSize % ]" | LogMe -error; $tests.RAMCache = "ERROR", ($RAMCacheSize) }
            ElseIf ([int] $RAMCacheSize -eq 101) { "PVS RAM Cache usage test failed" | LogMe -error; $tests.RAMCache = "ERROR", "Err" }
                Else { "PVS RAM Cache usage is Critical [ $RAMCacheSize % ]" | LogMe -error; $tests.RAMCache = "ERROR", ($RAMCacheSize) }  

                }
            Else { $tests.RAMCache = "SUCCESS", "N/A" }
                
            If ($vDiskCacheSize -ine 0)
                {

                If ( [int] $vDiskCacheSize -lt 80) { "PVS vDisk Cache usage is normal [ $vDiskCacheSize % ]" | LogMe -display; $tests.vDiskCache = "SUCCESS", ($vDiskCacheSize) }
                ElseIf ([int] $vDiskCacheSize -lt 90) { "PVS vDisk Cache usage is medium [ $vDiskCacheSize % ]" | LogMe -warning; $tests.vDiskCache = "WARNING", ($vDiskCacheSize) }    
            ElseIf ([int] $vDiskCacheSize -lt 95) { "PVS vDisk Cache usage is high [ $vDiskCacheSize % ]" | LogMe -error; $tests.vDiskCache = "ERROR", ($vDiskCacheSize) }
            ElseIf ([int] $vDiskCacheSize -eq 101) { "PVS vDisk Cache usage test failed" | LogMe -error; $tests.vDiskCache = "ERROR", "Err" }
                Else { "PVS vDisk Cache usage is Critical [ $vDiskCacheSize % ]" | LogMe -error; $tests.vDiskCache = "ERROR", ($vDiskCacheSize) }  

                }        
            Else { $tests.vDiskCache = "SUCCESS", "N/A" }

        $VDISKImage = get-content \\$Server\c$\Personality.ini | Select-String "Diskname" | Out-String | % { $_.substring(12)}
            If ($VDISKImage -ine "")
                {
            
          "vDisk Detected: $VDISKImage" | LogMe -display; $tests.vDiskImage = "SUCCESS", ($VDISKImage)
          #$tests.vDiskImage = "SUCCESS", $VDISKImage
            
                }
            Else
                {
            
          "vDisk Unknown"  | LogMe -error; $tests.vDiskImage = "ERROR", "Err"
          #$tests.vDiskImage = "WARNING", $VDISKImage
            
          }  
            
        }
      Else { $tests.RAMCache = "SUCCESS", "N/A";  $tests.vDiskCache = "SUCCESS", "N/A";  $tests.vDiskImage = "SUCCESS", "N/A" }


        }


  $allResults.$server = $tests

    " " | LogMe -display


    }


# DISPLAY TOTALS
$TotalServersCount = [int]$TotalServers

$ActiveICAUsers = [array]($sessions | ? {$_.State -eq "Active" -and $_.Protocol -eq "Ica"})
$ActiveRDPUsers = [array]($sessions | ? {$_.State -eq "Active" -and $_.Protocol -eq "Rdp"})
$DiscICAUsers = [array]($sessions | ? {$_.State -eq "Disconnected" -and $_.Protocol -eq "Ica"})
$DiscRDPUsers = [array]($sessions | ? {$_.State -eq "Disconnected" -and $_.Protocol -eq "Rdp"})
#$ActiveUsers = [array]($sessions | ? {$_.State -eq "Active" -and $_.Protocol -ne "Console"})
#$DiscUsers = [array]($sessions | ? {$_.State -eq "Disconnected" -and $_.Protocol -ne "Console"})

#If ($ActiveUsers) { $TotalActiveSessions = $ActiveUsers.count } Else { $TotalActiveSessions = 0 }
#If ($DiscUsers) { $TotalDisconnectedSessions = $DiscUsers.count } Else { $TotalDisconnectedSessions = 0 }
If ($ActiveICAUsers) { $TotalICAActiveSessions = $ActiveICAUsers.count } Else { $TotalICAActiveSessions = 0 }
If ($DiscICAUsers) { $TotalICADisconnectedSessions = $DiscICAUsers.count } Else { $TotalICADisconnectedSessions = 0 }
If ($ActiveICAUsers) { $TotalRDPActiveSessions = $ActiveRDPUsers.count } Else { $TotalRDPActiveSessions = 0 }
If ($DiscRDPUsers) { $TotalRDPDisconnectedSessions = $DiscRDPUsers.count } Else { $TotalRDPDisconnectedSessions = 0 }

$TotalActiveSessions = $TotalICAActiveSessions+$TotalRDPActiveSessions
$TotalDisconnectedSessions = $TotalICADisconnectedSessions+$TotalRDPDisconnectedSessions

"Total Number of Servers: $TotalServersCount" | LogMe
"Total Active Applications: $TotalActiveSessions" | LogMe
"Total Disconnected Sessions: $TotalDisconnectedSessions" | LogMe  

$CPUAverage = "{0:N2}" -f ($CPUAverage / $TotalServersCount)
$RAMAverage = "{0:N2}" -f ($RAMAverage / $TotalServersCount)

" " | LogMe -display


# Write Html
("Saving results to html report: " + $ResultsHTML) | LogMe

writeHtmlHeader $WebPageTitle $ResultsHTML
writeTableHeader $ResultsHTML
$allResults | sort-object -property FolderPath | % { writeData $allResults $ResultsHTML }
writeHtmlFooter $ResultsHTML


# Copying Html to Web Server
("Copying $ResultsHTML to: " + $HTMLServer +"\" +$HTMLPage) | LogMe

Try { Copy-Item $ResultsHTML $HTMLServer\$HTMLPage }
Catch
    {

    "Error Copying $ResultsHTML to $HTMLServer\$HTMLPage" | LogMe -error
    $_.Exception.Message | LogMe -error
    
    }

" " | LogMe -display

"Checking Alerts" | LogMe -display
# Process for Errors
FindErrors $allResults


#Checking Email Send Timeframe
[int]$hour = get-date -format HH
If($hour -lt $int_Email_Start -or $hour -gt $int_Email_End){ $EmailSendAllowed = $False; "Email Send Disabled: Outside Timeframe" | LogMe -display }
Else { $EmailSendAllowed = $True; "Email Send Allowed" | LogMe -display }


If ((Test-Path $AlertsEmailFile) -And ($SendAlerts -eq $True) -And ($EmailSendAllowed -eq $True))
    {

    $EmailAlertWarnings = ""
    $EmailAlertErrors = ""

    If (((Import-Csv $AlertsEmailFile | Measure-Object | Select-Object).Count) -ge 1)
        {

        $EmailAlertErrorsCount = 0
        $EmailAlertWarningsCount = 0
        $BODY = ""

        Import-CSV $AlertsEmailFile | Sort-Object Type, Server | Foreach-Object{

            $strAlertServer = ""
            $strAlertComponent = ""
            $strAlertValue = ""
            $strAlertStatus = ""

            $strAlertServer = $_.Server
            $strAlertComponent = $_.Component
            $strAlertValue = $_.Value
            $strAlertStatus = $_.Status

            $strAlertOutput = 'Server: <strong>' +$strAlertServer +'</strong><br>Component: <strong>' +$strAlertComponent +'</strong><br>Value: <strong>' +$strAlertValue +'</strong><br>Status: <strong>' +$strAlertStatus +'</strong></p>'

            If (($_.Type -ieq "ERROR") -And ($SendEmailErrors))
                {

                $EmailAlertErrors += '<p' +$WarningStyle +'>' +$strAlertOutput
                $EmailAlertErrorsCount ++

                }

            If (($_.Type -ieq "WARNING") -And ($SendEmailWarnings))
                {

                $EmailAlertWarnings += '<p' +$ErrorStyle +'>' +$strAlertOutput
                $EmailAlertWarningsCount ++
                            
                }

            }

        If ($EmailAlertErrorsCount -gt 0)
            {

            $BODY = $BODY +"<p><strong>ERRORS Detected:</strong></p>"

            $BODY = $BODY +$EmailAlertErrors

            }

        If ($EmailAlertWarningsCount -gt 0)
            {

            $BODY = $BODY +"<p><strong>WARNINGS Detected:</strong></p>"

            $BODY = $BODY +$EmailAlertWarnings

            }

        $BODY = $BODY +"Check " +$MonitorURL +" for more information"

        If ((!$emailFrom) -Or (!$emailTo) -Or (!$smtpServer))
            {

            If (!$emailFrom) { $MailFlag = $True; Write-Warning "From Email is NULL" | LogMe -error }
            If (!$emailTo) { $MailFlag = $True; Write-Warning "To Email is NULL" | LogMe -error }
            If (!$smtpServer) { $MailFlag = $True; Write-Warning "SMTP Server is NULL" | LogMe -error }

            "Email could not sent. Please Check Configuration and Try again." | LogMe -error

            }
        Else
            {

            If (($EmailAlertWarningsCount -gt 0) -Or ($EmailAlertErrorsCount -gt 0))
                {

                $msg = new-object System.Net.Mail.MailMessage
                $msg.From=$emailFrom
                $msg.to.Add($emailTo)
            
                If ($emailCC) { $msg.cc.add($emailCC) }
            
                $msg.Subject=$emailSubject
                $msg.IsBodyHtml=$true
                $msg.Body=$BODY
                #$msg.Attachments.Add($LogFile)

                $smtp = new-object System.Net.Mail.SmtpClient
                $smtp.host=$smtpServer
            
                Try { $smtp.Send($msg); "" | LogMe -display; "Email Sent" | LogMe -display }
                Catch
                    {
                
                    "" | LogMe -display
                    "Error Sending Email. See Error Messages Below:" | LogMe -error
                    $ErrorMessage = $_.Exception.Message
                    $FailedItem = $_.Exception.ItemName
                    $ErrorMessage | LogMe -error
                    $FailedItem | LogMe -error

                    }

                Start-Sleep 2

                $msg.Dispose()

                $EmailAlertErrors = ""
                $EmailAlertWarnings = ""
                $BODY = ""

                }
            Else { "No Alerts to Email" | LogMe -display }

            }

        }

    }


"" | LogMe -display
"Script Completed" | LogMe -display

"" | LogMe -display
"Script Ended at $(get-date)" | LogMe -display

$elapsed = GetElapsedTime $script:startTime
"Total Elapsed Script Time: $elapsed" | LogMe -display


#Script Cleanup
$allResults = $null
$ErrorsandWarnings = $null
$script:EchoAlerts = $null
$script:EchoErrors = $null
$tests = $null


#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# END - Main Program
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------

Juan
June 9, 2017 03:25 CST

Thanks a lot for this script, it's amazing, keep it up.

I'm having problems when I run the excript I get the error

Attempted to divide by zero.
At C:\Scripts\chk_farm\XenAppStatus.ps1:1256 char:41
+ $CPUAverage = "{0:N2}" -f ($CPUAverage / <<<<  $TotalServersCount)
    + CategoryInfo          : NotSpecified: (Smile [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException

Attempted to divide by zero.
At C:\Scripts\chk_farm\XenAppStatus.ps1:1257 char:41
+ $RAMAverage = "{0:N2}" -f ($RAMAverage / <<<<  $TotalServersCount)
    + CategoryInfo          : NotSpecified: (Smile [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException

And returns everything to 0

Checking Citrix XenApp Server Health.

Total Number of Servers: 0
Total Active Applications: 0
Total Disconnected Sessions: 0

Script Started at 06/09/2017 14:45:53
Processing Location: BNE

Checking Citrix License usage on xxxx
Citrix Licensing service is available.
License Server WMI Class file found
The total number of licenses available: xxxxxx
The number of licenses are in use: xxxxx
The License usage is xx %


Checking Citrix XenApp Server Health.

Total Number of Servers: 0
Total Active Applications: 0
Total Disconnected Sessions: 0
Attempted to divide by zero.
At C:\Scripts\chk_farm\XenAppStatus.ps1:1256 char:41
+ $CPUAverage = "{0:N2}" -f ($CPUAverage / <<<<  $TotalServersCount)
    + CategoryInfo          : NotSpecified: (Smile [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException

Attempted to divide by zero.
At C:\Scripts\chk_farm\XenAppStatus.ps1:1257 char:41
+ $RAMAverage = "{0:N2}" -f ($RAMAverage / <<<<  $TotalServersCount)
    + CategoryInfo          : NotSpecified: (Smile [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException


Checking Alerts
Email Send Allowed

Script Completed

Script Ended at 06/09/2017 14:46:03
Total Elapsed Script Time: 9.9216636 sec(s)

Aaron Argent
February 10, 2015 16:38 CST

PVS RAMCache PowerShell Script that you can run as a Schedule Task on any PVS in your PVS Farm

#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# Script Name: PVSCache.ps1
# Modified: 30/01/2015
# Created By: Aaron Argent
#
# Script Requirements: Powershell 3.0+, McliPSSnapIn
# Description: PVS RAM Cache Collection Script for Citrix Provisioning Servers
#              - Collects RAM Cache Data to CSV File
#              - Creates Web Page
#
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------


Clear-host


#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# User Definable Variables
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------


$strHtmlFilename = 'C:\inetpub\wwwroot\PVSCacheStatus.html'
$strCSVFilename = 'C:\inetpub\wwwroot\PVSCacheCSV.csv'


#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# END - User Definable Variables
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------


#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# Main Program
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------


Add-PSSnapin McliPS* -ErrorAction SilentlyContinue


If (Test-Path $strHtmlFilename)
    {
    
    remove-item $strHtmlFilename
    
    }
    
If (Test-Path $strCSVFilename)
    {    
    
    remove-item $strCSVFilename
    
    }


$date = ( Get-Date -format R)    

$strhead = @"
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>
<meta http-equiv="refresh" content="60">
<title>PVS RAM Cache Status</title>
    <STYLE TYPE="text/css">
    <!--
    td {
        font-family: Arial Bold;
        font-size: 14px;
        border-top: 1px solid #999999;
        border-right: 1px solid #999999;
        border-bottom: 1px solid #999999;
        border-left: 1px solid #999999;
        padding-top: 0px;
        padding-right: 0px;
        padding-bottom: 0px;
        padding-left: 0px;
        overflow: hidden;}

    .header {
      font-family: Tahoma;
    font-size: 40px;
    font-weight:bold;
    border-top: 1px solid #999999;
    border-right: 1px solid #999999;
    border-bottom: 1px solid #999999;
    border-left: 1px solid #999999;
    padding-top: 0px;
    padding-right: 0px;
    padding-bottom: 0px;
    padding-left: 0px;
        overflow: hidden;
    text-shadow:2px 2px 10px #000000;

        }
    body {
        margin-left: 5px;
        margin-top: 5px;
        margin-right: 0px;
        margin-bottom: 10px;
        table {
            table-layout:fixed;
            border: thin solid #FFFFFF;}
  .shadow {
    height: 1em;
    filter: Glow(Color=#000000,
    Direction=135,
    Strength=5);}
        -->
    </style>
</head>
<body>
<center>
<img src='logo.jpg'>
<h1>Provisioning Services RAM Cache Usage Report</h1>
<h3>Last Updated: $date</h3>
<table width='400' align='center'>
<tr><td><b>Device Name</b></td><td align=center><b>RAM Cache Used</b></td></tr>
"@
$strhead | Out-File $strHtmlFilename

"Server,CacheSize" |  Out-File $strCSVFilename

$arrDevices = mcli-get deviceinfo -f devicename | findstr deviceName:

foreach ($strDevice in $arrDevices)
    {
    
    $strServer = $strDevice.split(" ")[1]
    
    $strValue = mcli-get deviceinfo -p devicename=$strServer -f status | findstr status

    [int]$intStatus = $strValue.split(",")[1]

    If ($intStatus -ine 0)
        {
        
        $strServer +"," +$intStatus |  Out-File $strCSVFilename -Append

        If ($intStatus -ge '80')
            {  

            write-host "WARNING - " $strServer $intStatus"%"
    
            "<tr><td bgcolor=#FF0000>" +$strServer +"</td><td align=center bgcolor=#FF0000>" +$intStatus +"%</td></tr>" | Out-File $strHtmlFilename -Append
        
            }
        Else
            {

            write-host "INFO - " $strServer $intStatus"%"
        
            "<tr><td>" +$strServer +"</td><td align=center>" +$intStatus +"%</td></tr>" | Out-File $strHtmlFilename -Append
        
            }
            
        }
    
    #$strContent | Out-File $strHtmlFilename -Append

    }

    
$strfooter = @"
</table>
</body>
</html>
"@
$strfooter | Out-File $strHtmlFilename -Append


#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# END - Main Program
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------

David Griffiths
February 11, 2015 01:09 CST

Would it be possible to add column showing number of users on each server instead of session count ?

Aaron Argent
February 11, 2015 10:55 CST

You could do a unique to get a list of unique users.  
I like to see sessions, I personally like to split Sessions into ICA and RDP sessions (Good to see how many users are connecting incorrectly or Admins are logged in) (not really wanting console sessions)

Stan Czerno
February 11, 2015 02:10 CST

I have updated the Blog Post to include Aaron's contributions. Emoticons have been removed.

Raja
February 11, 2015 03:28 CST

Many thanks Aron,

I have added DiskFree in our production script works like charm as usual. Smile

Keep it up.

Thanks again to Stan for such a wonderful blog maintaining and your scripting work really great. Keep it up.

Raja
February 12, 2015 16:42 CST

Hi Stan / Aron,

One more small help, we thought to include one more column DiskSize of the server C Drive in the report.

Have added DiskSize as a additional column, and below code in main script under Disk Free Space part.

$DiskSizeC = "{0:N2}" -f ($DiskTotalSize / 1gb) | LogMe -display; $tests.Disksize = "SUCCESS", ($DiskSizeC)

I am able to see the output in powershell window without any error, but not able to map the output to report. I feel something is missing in order to link with report.

Could you please help with this.

Raja
February 13, 2015 06:35 CST

Hi

Could someone please correct the code above for DiskSize..

Girdhar
February 16, 2015 12:45 CST

Hi,

Could you please give me a powershell scripts which added security groups in applications.

why I want. suppose I have abc\testgroup in abc domain but since our domain is migrated to xyz\testgroup  (xyz domain) now I need
to add all corresponding xyz domain groups inside the applications.  I need to rephrase that we need to add different groups in different application. I have application details and groups details but I need powershell to automate the task

Dmitry
February 26, 2015 09:22 CST

Any plans on developing something for XenApp/XenDesktop 7.x ?

Stan Czerno
February 27, 2015 08:35 CST

Yes, eventually....

Matt P
March 1, 2015 15:33 CST

My script seems to keep failing on MemUsage, WMI and XML.  I thought it was an issue with WMI so I ran a rebuild but it has made no difference.  Anyone have an insight into this?

AUCLYXA65APP02
Server is able to ping
Logons are enabled
Active ICA sessions: 24
Disconnected ICA sessions: 0
Default Load Evaluator assigned
Socket Connection on 3389 Successful
Socket Connection on 1494 Successful
ICA protocol responded
Socket Connection on 2598 Successful
CPU usage is normal [ 8.5 % ]
[ERROR] Error returned while checking the Memory usage. Perfmon Counters may be fault
[ERROR] Memory usage test failed
Citrix Independent Management Architecture is running...
Print Spooler is running...
Citrix Print Manager Service is running...
[ERROR] Error while checking the Service. Server may be down or some permission issue
Serverload is normal : 6978.load
[ERROR] WMI connection failed - check WMI for corruption
Server belongs to the below path in Citrix Console
Servers/AppServers

DClark
March 13, 2015 13:52 CST

If all WMI calls to something other than the local host are failing, it is possible that the RPC ports are not open at the firewall.

Christoper United States
March 3, 2015 21:40 CST

Have you ever considered about including a little bit more than just your articles? I mean, what you say is important and all. But just imagine if you added some great graphics or videos to give your posts more, "pop"! Your content is excellent but with pics and clips, this website could definitely be one of the best in its niche. Wonderful blog!

Stan Czerno
March 13, 2015 14:07 CST

Possibly, Remote Management may not be enabled. I think the command for that is winrm quickconfig.

You can also refer to this article: http://support.microsoft.com/en-us/kb/2260600

Shane
March 20, 2015 08:37 CST

I am getting this error when checking a service that is stuck in a starting state, is there a timeout that can be set?

WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...
WARNING: Waiting for service 'Windows Event Log (eventlog)' to finish starting...

Greg
April 9, 2015 21:07 CST

Love this script but don't want to have multiple Zones at this point what can I rem out so it works for my default zone?

Peter
April 24, 2015 02:59 CST

I have my helath script in vb as

Drive,Free Space,IMA,XML,SMA,XTE,CPM,Spooler,UPH Clean,Last Reboot and i want to add ICA listener, RDP Status also but vbscript i am not finding anything.SO please anybody share powershellscript with all this.I am new to powershell.i Just started to write.powershell but not able to finished yet.I taking my sever names from text file.

Thanks,
Peter








Jesse
June 3, 2015 05:09 CST

Would this work for XenDesktop/XenApp 7.6?

Jesse
June 3, 2015 05:11 CST

Also what about getting the ICA counters for the connected users? I have a script that will pull this information, I would love for it to be added to your output file
Here is what I have

function Get-XALatencyLastRecorded
{
    [CmdletBinding()]
    [OutputType([int])]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        $Server
    )

    Begin
    {
    }
    Process
    {
    get-counter "\\$Server\ICA Session(*)\Latency - Last Recorded" | select -ExpandProperty countersamples | select InstanceName,@{Expression={$_.cookedvalue};N="ICA Latency"} | sort "ICA Latency" -Descending  | Format-Table -AutoSize
    }
    End
    {
    }
}

rajneesh
July 22, 2015 02:45 CST

HI All,
Is there any script which does the same work on citrix metaframe servers..

Adrian Wallis
November 6, 2015 05:02 CST

Hi,

The RPC test can be improved to use RPCPing for the test instead of a WMI based test. At the moment, if the WMI test fails then the RPC test will fail even though RPC may be working.

New Function:

#==============================================================================================
# This function will check RPC using RPCPing.
#==============================================================================================
Function CheckRPCReal()
{  
  Param ($hostname)
  $startInfo = New-Object System.Diagnostics.ProcessStartInfo
  $startInfo.FileName = "rpcping.exe"
  $startInfo.Arguments = "-s", $hostname
  $startInfo.RedirectStandardOutput = $true
  $startInfo.UseShellExecute = $false
  $startInfo.CreateNoWindow = $false
  $process = New-Object System.Diagnostics.Process
  $process.StartInfo = $startInfo
  $process.Start() | Out-Null
  $standardOut = $process.StandardOutput.ReadLine()
  $process.WaitForExit()
  if ($standardOut.contains("Completed"))    
    {return 1}
  else
    {return 0}
}

Changes to the RPC Test section

  #Check RPC
        if (checkrpcreal $server)
            {$tests.RPC = "SUCCESS", "Success"; "RPC responded" | LogMe -Display  }
            else { $tests.RPC = "ERROR", "No response from RPC"; "RPC failed" | LogMe -error }

Cheers
Adrian

Stan Czerno
November 6, 2015 06:06 CST

Excellent idea, thanks!

GP
January 4, 2016 19:26 CST

Hi Stan - Good Noon!!!

First wish you a happy new year...

I've used the above script and successfully monitoring all the servers without any issues...
Today, I was trying to get the "Application Virtualization Service" in the same script.

But, I couldn't.  Appreciate if you help on this...

Max
January 8, 2016 01:08 CST

Hi Stan,

I am unable get output file .htm however i am reeving an email for errors detected please help.

I am running xenapp 6.X script please advice if any additional rights are required, I want to receive report file on share network location.

Rgrads,
Max

Avadhoot
January 11, 2016 13:48 CST

Is there any way to check the servers only under specific folder in farm?

kitaab
January 25, 2016 01:53 CST

Thank you for the Script.

I implemented this script and it works fine , except for the fact that it keeps sending me the emails for the same Warnings every time the script runs (15 Minutes)

I had set the $EmailAlertsLagTime = "3600"


In addition : it keep looking for XML service on Session Host Servers and reports error as it cannot find Citrix XML server ( We use XA6.5)
How can i avoid the script not check for XML on session host server

Jorge
January 31, 2016 17:39 CST

Hi Stan,
i tried add comment but it keep of disappearing. anyway, i would like to thank you and the script is working great. also i would like to know how to save the report as a CSV file.

thanks
Jorge

Jorge
February 1, 2016 11:42 CST

Hi anybody can help me to export the report as csv file i want to be like this
Server,ping,logons,etc....
Srv1,success,enabled,etc....
Hope to get response thanks

Kyle
February 4, 2016 09:33 CST

I have the report running on 6.5 and it works great.  Is there an easy way to save one of these files a day for historical reasons?

GP
February 8, 2016 02:34 CST

Hi Stan,

Is there way to add the "qfarm /load" details in the above script?
If yes, could you please help me on this.

GP
February 16, 2016 02:17 CST

Friends,

Can anyone please help to write the same xenapp health check for Citrix Presentation Server 4.0 and Windows XPE environment...
Appreciate your help if anyone help me...

Wackernie
March 7, 2016 21:23 CST

Hello

HI
I have an error on the licensing function it does not find the service or license rights issue have an idea

thank you

Function CheckLicense()
{
  if(!$LicenseServer) { "Aucune licence Nom du serveur pas défini" | LogMe -Error; $LicenseResult = " Error; Check Detailed Logs "; return $LicenseResult }
  if(!$LicenseTypes) { "Non et type de licence pas défini" | LogMe -Error; $LicenseResult = " Error; Check Detailed Logs "; return $LicenseResult }
  
  # Déclaration des variables de capture et de calculer l'utilisation des licences
  [int]$TotalLicense = 0; [int]$InUseLicense = 0; [int]$PercentageLS = 0; $LicenseResult = " "
  
  # Gestion des erreurs si les serveurs ne sont pas accessibles pour les détails de la licence ou des problèmes WMI
  Try
  {   if(Get-Service -Display "Citrix Licensing" -ComputerName $LicenseServer -ErrorAction Stop) { "Citrix Licensing service is available." | LogMe -Display }
    else { "Citrix Licensing' service is NOT available." | LogMe -Error; Return "Error; Check Logs" }
    Try {   if($licensePool = gwmi -class "Citrix_GT_License_Pool" -Namespace "ROOT\CitrixLicensing" -comp $LicenseServer -ErrorAction Stop)
        {  "License Server WMI Class file found" | LogMe -Display
          $LicensePool | ForEach-Object{
            foreach ($Ltype in $LicenseTypes)
            {   if ($_.PLD -match $Ltype) { $TotalLicense = $TotalLicense + $_.count; $InUseLicense = $InUseLicense + $_.InUseCount } } }
  
        "The total number of licenses available: $TotalLicense " | LogMe -Display
        "The number of licenses are in use: $InUseLicense " | LogMe -Display
        if(!(($InUseLicense -eq 0) -or ($TotalLicense -eq 0 ))) { $PercentageLS = (($InUseLicense / $TotalLicense ) * 100); $PercentageLS = "{0:N2}" -f $PercentageLS }
        
        if($PercentageLS -gt 90) { "The License usage is $PercentageLS % " | LogMe -Error }
        elseif($PercentageLS -gt 80) { "The License usage is $PercentageLS % " | LogMe -Warning }
        else { "The License usage is $PercentageLS % " | LogMe -Display }
  
        $LicenseResult = "$InUseLicense [ $PercentageLS % ]"; return $LicenseResult
      }
    } Catch {
                $ErrorMessage = $_.Exception.Message
                $FailedItem = $_.Exception.ItemName
                "License Server fichier WMI classe a échoué. Une erreur est survenue lors de la capture des informations de licence " | LogMe -Error
                "Vous devrez peut-être désinstaller votre serveur de licences et réinstaller " | LogMe -Error
                "Il y a des problèmes connus  faire une mise à niveau du service de licence." | LogMe -Error
          $LicenseResult = " Erreur; Consultez les journaux détaillés "; return $LicenseResult }
  } Catch { "Erreur renvoyée lors de la vérification du service de licences. Server peut être en panne ou un problème d'autorisation" | LogMe -error; return "Error; Check Detailed Logs" }
}

GP
March 9, 2016 23:47 CST

Wackernie,

I've ran the script and I don't face any issue...
have you updated the below lines...? in your script?

=======================================================
# License Server Name for license usage.
$LicenseServer = "SERVERNAME.domain.local"

# License Type to be defined
# Example: @("MPS_PLT_CCU", "MPS_ENT_CCU", "XDT_ENT_UD")
#$LicenseTypes = @("MPS_ENT_CCU")
$LicenseTypes = @("XDT_ENT_UD")
=======================================================

If you didn't updated the above mentioned lines, please update and run.

invalid
March 8, 2016 01:53 CST

Same here, anyone there to publish such a script for PS 4.5/5.0 ???!

roy
May 4, 2016 06:13 CST

Stan,

Sometimes we have issues with our domain controllers which causes the logins for citrix to slow down to a crawl 15+minutes.  So people blame citrix naturally but its actually some kind of either kerberus ldap issue for terminal services.
Is there some kind of additional check you can add in to this script to verify ldap authentication?
We are looking to see whats going on with the domain controllers but it would be nice if this didnt just test citrix ports etc, but also the terminal services and ldap aspect of the login process.
just a thought.
thanks

roy
May 4, 2016 06:42 CST

Also do you think there is any way to make this retain historical, maybe by naming the html file with date/time, and turning it into a variable thats updated when the email is sent out, that way i can go back to a certain date for any issues on that day?
i know html is only sent out when theres an issue, so maybe turning the default.html into a list of the .html with errors? and the link in the email can be for that specific date error.

Jens
May 19, 2016 03:07 CST

Hi @ ALL!

Very nice work!!!

yesterday i tried to download ist for the original page, but the downlod is not available any more Frown

The script here (v2) is not able to find my Servers in the farm... Frown

can anyone help?

CitrixQuery
November 21, 2017 06:19 CST

Hi everyone

Great monitoring overview I use all the time

I have added FolderName to the report how can you order a column in the output HTML file?
Servers are in silos and would be good if the silo servers are grouped together for easy reading
The report currently orders by server name

Many Thanks

Comments are closed