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

May 21, 2011

PowerShell, XenApp

In Part 2 of this 4 Part series, the PowerShell script from Part 1 was modified to list all the offline Citrix XenApp servers in a XenApp farm by Zone.  While the script works and gives the desired output, there is a bug in that an invalid Zone can be entered which causes the script to abruptly terminate. In this article, the script will be modified to validate the Zone name entered.

The current script:

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
}

A function in PowerShell can consist of up to three sections.

Function Name
{
   Begin {}
   Process {}
   End {}
}

The Begin {} section gets processed once at the beginning of the function.

The Process {} section gets processed for each object in the pipeline.  For this function, that is once.

The End {} section gets processed once at the end of the function.

We will use the Begin {} section to validate the Zone and the End {} section to handle output and cleanup.  The Process {} section will contain the bulk of the original function.

Using these three sections, the new function will look like this:

Function Get-XAOfflineServer
{

   Param( [string]$ZoneName = '' )

   Begin
   {
     #validate zone if one entered
   }

   Process
   {
     If( $ZoneName -eq '' )
     {
        #snip
     }
     Else
     {
        #snip
     }
   }

   End
   {
     Write-Output $OfflineServers
     $AllXAServers = $null
     $OnlineXAServers = $null
     $XAServers = $null
     $OnlineServers = $null
     $OfflineServers = $null
   }
}

To validate the Zone name entered, the following code is added to the Begin {} section:

Begin
{
   If($ZoneName -ne '')
   {
     $ValidZone = IsValidZoneName $ZoneName
     If(-not $ValidZone)
     {
        Write-Error "Invalid zone name $ZoneName entered"
        Break
     }
   }
}

IsValidZoneName is a “helper” function that needs to be added to the script before the Get-XAOfflineServer function.  The IsValidZoneName function needs to be declared before it can be used.  That means it has to appear in the script before it can be used.

We only need to test for a valid Zone name if a Zone name was passed to the Get-XAOfflineServer function.

The IsValidZoneName function:

Function IsValidZoneName
{

   Param( [string]$ZoneName )

   $ValidZone = $false
   $Zones = Get-XAZone -ErrorAction SilentlyContinue
   If( -not $? )
   {
     Write-Error "Zone information could not be retrieved"
     Return $ValidZone
   }

   ForEach($Zone in $Zones)
   {
     If($Zone.ZoneName -eq $ZoneName)
     {
        $ValidZone = $true
     }
   }

   $Zones = $null
   Return $ValidZone
}

This helper function retrieves a list of Zones in the XenApp farm if possible.  If the Zones cannot be retrieved, an error message is displayed and the function returns a False value.  If the Zones are retrieved, the Zone names are compared to the Zone name passed to the helper function.  If a match is found, the function returns True, else it returns False.  Since an object named $Zones was created, we clean up after ourselves and set the $Zones object to $null.

Returning to the example from the end of Part 2 that caused the script to abruptly end, the script now gives a descriptive error (shown in bold) and ends.

PS Z:\> Get-XAOfflineserver GoTitans
Get-XAOfflineServer : Invalid zone name GoTitans entered
At line:1 char:20
+ Get-XAOfflineserver <<<<  GoTitans
+ CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-XAOfflineServer
PS Z:\>

Running the script with no Zone name entered gives the original results.

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

Running the script with a valid zone name also gives the original results.

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

Just to make sure the script works, I powered on XenApp 2.

PS Z:\> Get-XAOfflineServer
XENAPP3
PS Z:\>

I then shut down XenApp2 and powered on XenApp3.

PS Z:\> Get-XAOfflineServer
XENAPP2
PS Z:\>

The finished script:

Function IsValidZoneName
{

   Param( [string]$ZoneName )

   $ValidZone = $false
   $Zones = Get-XAZone -ErrorAction SilentlyContinue
   If( -not $? )
   {
     Write-Error "Zone information could not be retrieved"
     Return $ValidZone
   }

   ForEach($Zone in $Zones)
   {
     If($Zone.ZoneName -eq $ZoneName)
     {
        $ValidZone = $true
     }
   }

   $Zones = $null
   Return $ValidZone
}

Function Get-XAOfflineServer
{

   Param( [string]$ZoneName = '' )

   Begin
   {
     If($ZoneName -ne '')
     {
        $ValidZone = IsValidZoneName $ZoneName
        If(-not $ValidZone)
        {
          Write-Error "Invalid zone name $ZoneName entered"
          Break
        }
     }
   }

   Process
   {
     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
        }
     }
   }

   End
   {
     Write-Output $OfflineServers
     $AllXAServers = $null
     $OnlineXAServers = $null
     $XAServers = $null
     $OnlineServers = $null
     $OfflineServers = $null
   }
}

This script has been tested with XenApp 5 for Server 2003 both 32-bit and 64-bit, XenApp 5 for Server 2008 32-bit and XenApp 6.

There is still one more way to get a list of offline servers and that will be covered in Part 4.

, ,

About Carl Webster

Webster is an independent consultant in the Nashville, TN area 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

Current day month ye@r *