Finding Offline Citrix XenApp Servers Using Microsoft PowerShell Part 2 of 4

May 21, 2011

PowerShell, XenApp

May 21, 2011: I found a bug in the script where it did not work under all conditions for XenApp5 and XenApp 6.  I have changed the script to a version that, so far, has worked in all conditions tested.

In Part 2 of this 4 Part series, a PowerShell script was created to list all the offline Citrix XenApp servers in a XenApp farm.  While the script works and gives the desired output, there is no way to restrict the output to just a single Zone in a farm.  In this article, the script will be converted into a function that allows the output to be restricted to a single Zone.

The current script:

$AllXAServers = Get-XAServer | Sort-Object ServerName
$XAServers = @()
ForEach( $XAServer in $AllXAServers )
{
   $XAServers += $XAServer.ServerName
}

$OnlineXAServers = Get-XAzone | Get-XAServer -OnlineOnly | Sort-Object ServerName
$OnlineServers = @()
ForEach( $OnlineServer in $OnlineXAServers )
{
   $OnlineServers += $OnlineServer.ServerName
}

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

Write-Output $OfflineServers

Creating a simple function in PowerShell is easy.

Function Name
{
   #PowerShell statements go here
}

The first thing needed is a name for the function.  The purpose of the function is to Get XenApp Offline Servers.  Following the naming convention used by Citrix, Get-XANoun, the name could be Get-XAOfflineServer.  Why XAOfflineServer and not XAOfflineServers?  PowerShell convention is to use singular and not plural.

Function Get-XAOfflineServer
{
   #PowerShell statements
}

Adding in the original script to the new function.

Function Get-XAOfflineServer
{
   $AllXAServers = Get-XAServer | Sort-Object ServerName
   $XAServers = @()
   ForEach( $XAServer in $AllXAServers )
   {
     $XAServers += $XAServer.ServerName
   }

   $OnlineXAServers = Get-XAZone | Get-XAServer -OnlineOnly | Sort-Object ServerName
   $OnlineServers = @()
   ForEach( $OnlineServer in $OnlineXAServers )
   {
     $OnlineServers += $OnlineServer.ServerName
   }

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

   Write-Output $OfflineServers
}

Running this produces the original output.

PS Z:\> Get-XAOfflineserver
XENAPP2
XENAPP3
PS Z:\>

Now that the function has been verified to work properly, how to allow the output to be restricted to one Zone?  Adding a parameter to allow a Zone name to be passed is the answer.  Get-XAServer uses –ZoneName as a parameter.  To be consistent, that is the same parameter this function will use.

Function Get-XAOfflineServer
{
   Param( [string]$ZoneName = '' )
   <snip>
}

This allows the function to be called with a specific Zone name:

Get-XAOfflineServer --ZoneName NAZone

The function needs to be changed to work when a Zone name is passed.  First, the function needs to work if no Zone name is given, just as the original script.

If( $ZoneName -eq '' )
{
   $XAServers = @()
   ForEach( $XAServer in $AllXAServers )
   {
     $XAServers += $XAServer.ServerName
   }

   $OnlineXAServers = Get-XAZone | Get-XAServer -OnlineOnly | Sort-Object ServerName
   $OnlineServers = @()
   ForEach( $OnlineServer in $OnlineXAServers )
   {
     $OnlineServers += $OnlineServer.ServerName
   }

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

If a Zone name is passed, two lines need to be changed.

All servers need to be retrieved only for the Zone specified.

$AllXAServers = Get-XAServer -ZoneName $ZoneName | Sort-Object ServerName

Get-XAZone is no longer needed as online servers can be retrieved for the Zone specified.

$OnlineXAServers = Get-XAServer -ZoneName $ZoneName -OnlineOnly | Sort-Object ServerName

The updated function with the new statements.

Function Get-XAOfflineServer
{
   Param( [string]$ZoneName = '' )

   If( $ZoneName -eq '' )
   {
     <snip>
   }
   Else
   {
     $AllXAServers = Get-XAServer -ZoneName $ZoneName | Sort-Object ServerName
     $XAServers = @()
     ForEach( $XAServer in $AllXAServers )
     {
        $XAServers += $XAServer.ServerName
     }

     $OnlineXAServers = Get-XAServer -ZoneName $ZoneName -OnlineOnly | Sort-Object ServerName
     $OnlineServers = @()
     ForEach( $OnlineServer in $OnlineXAServers )
     {
        $OnlineServers += $OnlineServer.ServerName
     }

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

   Write-Output $OfflineServers
}

Running the function with no Zone specified produces the following (Figure 1).

Figure 1

Running the function with a Zone specified produces the following (Figure 2).

Figure 2

Running the function using the –ZoneName parameter produces the following (Figure 3).

Figure 3

Great!  The functions works with no Zone specified and Zone name specified with and without using –ZoneName.  Or does it?  What happens if an invalid Zone name is used (Figure 4)?

Figure 4

OOPS!  An IMAException error was returned because the Zone GoTitans doesn’t exist in the Farm.  How should that be handled?  The function needs to have error handling, and more, added.  That will be covered in Part 3.

Here is the complete function code with redundant code moved to before the Write-Output:

Function Get-XAOfflineServer
{
   Param( [string]$ZoneName = '' )

   If( $ZoneName -eq '' )
   {
     $AllXAServers = Get-XAServer | Sort-Object ServerName
     $OnlineXAServers = Get-XAZone | Get-XAServer -OnlineOnly | Sort-Object ServerName
   }
   Else
   {
     $AllXAServers = Get-XAServer -ZoneName $ZoneName | Sort-Object ServerName
     $OnlineXAServers = Get-XAServer -ZoneName $ZoneName -OnlineOnly | Sort-Object ServerName
   }

   $XAServers = @()
   ForEach( $XAServer in $AllXAServers )
   {
     $XAServers += $XAServer.ServerName
   }

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

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

   Write-Output $OfflineServers
}
, ,

About Carl Webster

Webster is a Sr. Solutions Architect for Choice Solutions, LLC and specializes in Citrix, Active Directory and Technical Documentation. Webster has been working with Citrix products for many years starting with Multi-User OS/2 in 1990.

View all posts by Carl Webster

No comments yet.

Leave a Reply