1 Recently I was asked how to use PowerShell to get a list of offline Citrix XenApp servers. Being new to PowerShell, this gave me an opportunity to use some of my new knowledge. At the time this article is being written, I have been working with PowerShell for less than one month. Feel free to offer suggestions for how to improve the script in this four part article series. To use PowerShell with XenApp 6, you will need the XenApp 6 PowerShell SDK (Software Development Kit) available from (Figure 1). Figure 1 To use PowerShell with XenApp 5, you will need the XenApp Commands Technology Preview (v3) available from (MyCitrix login required) (Figure 2).
2 Figure 2 Note: The scripts in this article should work for XenApp 6 and XenApp 5 for Windows Server 2008 and XenApp 5 for Windows Server To develop and test this script, my lab setup includes three servers running Citrix XenApp 6 for Microsoft Windows Server 2008 R2 SP1. The XenApp server names are XenApp1, XenApp2 and XenApp3. Only XenApp1 is powered on. This gives two offline servers to test the script against. In their PowerShell cmdlets (pronounced CommandLets), Citrix does not have a specific cmdlet that returns a list of offline servers. There are only two Citrix cmdlets that are needed in order to generate this list. The first cmdlet is Get-XAServer which returns a list of all XenApp servers (Online and Offline) in a XenApp farm (Figure 3). Figure 3 Note: Get-XAServer returns 21 properties, of which only one is used by this script: ServerName. The PowerShell command line in Figure 3 takes the results of Get-XAServer, selects just the ServerName
3 property, sorts the results in alphabetical order by ServerName and then displays the results in a formatted table displaying only the ServerName property. The second cmdlet needed is Get-XAZone. This cmdlet returns a list of all the Zones in a XenApp farm. The reason this cmdlet is needed is that the Get-XAServer cmdlet has a switch OnlineOnly that, believe it or not, returns a list of XenApp servers that are online. But, that switch requires the ZoneName parameter. Combining Get-XAZone piped to Get-XAServer with the OnlineOnly switch will return a list of online servers for every Zone in a XenApp farm (Figure 4). Figure 4 Didn t I just say the Get-XAServer cmdlet with the OnlineOnly switch required the ZoneName parameter? Yes I did. One of the many smart things that PowerShell handles under the covers is seeing that both Get-XAZone and Get-XAServer have the ZoneName parameter in common. How does Get- XAServer automatically handle this? To find out, I typed Get-Help Get-XAServer full and scrolled down to ZoneName (Figure 5). I saw that ZoneName accepts pipeline input by property name. Figure 5 Note: I learned this from Don Jones, PowerShell MVP at The Experts Conference 2011 in his preconference PowerShell Deep-Dive Workshop. This is part of the magic of PowerShell, handling stuff under the covers to make working in PowerShell less complicated. Since Citrix does not provide, at this time, an OfflineOnly switch, I have what is needed to build a list of offline servers. I have a list of all servers in the farm and a list of servers that are online. Any server that is in the all servers list but not in the online servers list is an offline server. This is fairly easy to do in PowerShell. First, get the list of all servers in the farm sorted by ServerName. $AllXAServers = Get-XAServer Sort-Object ServerName
4 $XAServers ForEach( $XAServer in $AllXAServers ) $XAServers += $XAServer.ServerName Next, get all the online servers, also sorted by ServerName. $OnlineXAServers = Get-XAZone Get-XAServer OnlineOnly Sort-Object ServerName $OnlineServers ForEach( $OnlineServer in $OnlineXAServers ) $OnlineServers += $OnlineServer.ServerName Create an array to hold the offline servers. $OfflineServers Compare the array of online servers to the array of all servers. If a server is not in the online array, then it is offline. ForEach( $Server in $XAServers ) If( $OnLineServers -notcontains $Server ) $OfflineServers += $Server Display the list of offline servers. Write-Output $OfflineServers The entire script being run in my lab: $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 Which produces the following output (Figure 6):
5 Figure 6 As it stands, the script is fully functional, works and produces the desired output a list of offline servers in the XenApp farm. But, the script is not really as good as it could be and could create a Resume Generating Event if run on a large XenApp farm with zones spanning countries or continents. The script can be a lot better. 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
6 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 Else $OfflineServers ForEach( $Server in $XAServers ) If( $OnLineServers -notcontains $Server ) $OfflineServers += $Server If a Zone name is passed, two lines need to be changed.
7 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
8 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. The current script (PowerShell uses the ` character for line continuation): 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
9 $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
10 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
11 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)
13 $OfflineServers = $null This script has been tested with XenApp 5 for Server 2003 both 32-bit and 64-bit, XenApp 5 for Server bit and XenApp 6. There is still one more way to get a list of offline servers. The original question was could PowerShell be used to get a list of offline servers. The answer is yes. But, there is another way. At The Experts Conference in June 2011, I took a PowerShell class given by Don Jones. One of the questions he asked was how would you map a drive letter using PowerShell? The answer? Net use d: \\Server\Share How do you find offline XenApp servers using PowerShell? Qfarm /offline (Figure 1) Figure 7 Being fairly new to PowerShell, I thought I could just run qfarm /offline convertto-html and my job would be done. But it was not that easy. Fortunately, my friend and Exchange MVP Michael B. Smith is also a PowerShell guru and helped me walk through the learning process. What follows is how Michael helped me generate HTML output. What did I get from running the commands? qfarm /offline convertto-html Garbage! (Figure 2)
14 Figure 8 The first thing Michael had me do was determine the type of output being generated by running: $obj = qfarm /offline $obj.gettype() This assigns the results of qfarm /offline to a variable $obj. Then the type of the variable is retrieved (Figure 3). Figure 9 Next, find the type of the members of $obj (Figure 4) by using $obj get-member
15 Figure 10 Since $obj is an array, Michael also wanted the members of the first element of the $obj array (Figure 5). $obj get-member Note: PowerShell arrays start at 0. Figure 11
16 Michael then had me run the following code (results shown in Figure 6): $obj.count for( $i=0; $i -lt $obj.count; $i++ ) $obj[$i].gettype().fullname; $obj[$i].length Figure 12 Does the output look familiar? Compare Figure 6 to Figure 2. Michael then showed me how to get formatted HTML output similar to the qfarm /offline output (Figure 7). $str = $obj = qfarm /offline for( $i=0 ; $i lt $obj.count ; $i++ ) $str += $obj[ $i ] + <br/> ; ConvertTo-HTML body $str > C:\test.html Invoke-Item c:\test.html $str = $null $obj = $null Figure 13 If you know how to create and use a CSS file, the ConvertTo-HTML cmdlet allows one to be used to format the output more precisely. With PowerShell, there are usually several ways to accomplish a given task. If there is a command line utility available, use it. There is no need to reinvent the wheel.
HOUR 3 Creating Our First ASP.NET Web Page In the last two hours, we ve spent quite a bit of time talking in very highlevel terms about ASP.NET Web pages and the ASP.NET programming model. We ve looked
BACKUPS FAQ Why Backup? Backup Location Net Connections Programs Schedule Procedures Frequently Asked Questions I do a backup once a week and sometimes longer, is this sufficient? In most cases, I would
8 Backing Up and Recovering Your Server In this chapter, you will learn to: Understand Backup and Recovery (Pages 254 262) 33n Understand Backup and Recovery Terminology (Page 255) n Use Backup and Recovery
TECHNICAL PAPER Synchronizing databases with the SQL Comparison SDK By Doug Reilly In the wired world, our data can be almost anywhere. The problem is often getting it from here to there. A common problem,
TechNet Home > Products & Technologies > Windows NT Server > Maintain Windows NT Backup Software Topics on this Page TBU Advantages and Disadvantages Backup and Restore User Accounts Starting the TBU GUI
by Rick Peterson Dale Weber Richard Odell Greg Leibfried AS/400 System Performance IBM Rochester Lab May 2000 Page 1 Table of Contents Introduction... Page 4 What is the Database Monitor for AS/400 tool?...
ACTi Knowledge Base Category: Installation & Configuration Note Sub-category: Application Model: All Firmware: N/A Software: N/A Author: Ando.Meritee Published: 2010/11/19 Reviewed: 2011/03/02 How to Use
Ready Reference Guide Customizing an Output Style September 2008 Customizing an Output Style Table of Contents Overview Page 3 Getting Started Page 4 Modifying an Output Style Page 6 Sharing a Style With
Enterprise Vault Users Guide Enterprise Vault Email Archiving System What is Enterprise Vault? Enterprise Vault (or EV) is a Symantec archiving solution that DII is rolling out for all users of the Enterprise
Departmental IT Staff (CatNet OU Admin) Guide to Exchange 2010 Submitted to: University of Arizona Prepared by: Table of Contents Active Directory... 4 Overview and Terminology... 4 CatNet Architecture...
Mascot Search Results FAQ 1 We had a presentation with this same title at our 2005 user meeting. So much has changed in the last 6 years that it seemed like a good idea to re-visit the topic. Just about
Performance Troubleshooting Guide for Microsoft Business Solutions Navision PERFORMANCE TROUBLESHOOTING GUIDE FOR MICROSOFT BUSINESS SOLUTIONS NAVISION DISCLAIMER This material is for informational purposes
SMART MARKETING: UNLOCKING THE POWER OF AUTOMATION A Q&A Session with WhatCounts TABLE OF CONTENTS Introduction 4 Welcome to the Email Automation Q&A 5 What is Smart Marketing? 5 What is email automation?
IDEP FOR WINDOWS USER MANUAL Version 2011 BE National Accounts Institute National Bank of Belgium External statistics Boulevard de Berlaimont 14 B-1000 Brussels Table of contents 1 INTRODUCTION.... 1 1.1
Getting Started Guide WebSite Tonight Getting Your Personal Website Online in One Night Getting Started Guide Page 1 Getting Started Guide: WebSite Tonight A Wedding Website Version 1.0 (03.08.10) Copyright
Guide DonorPerfect Online SofterWare, Inc. DonorPerfect Online September 2010 Table of Contents Table of Contents INTRODUCTION...3 Choosing Email and/or Letter Receipting... 3 Workflow... 3 Regenerating
Outline Introduction to Mimosa Archive... 1 What to expect... 2 Why are we using this program?... 2 Webmail... 2 Search methods... 3 Quick Search... 3 Browse... 4 View messages... 6 Restore messages...
CHAPTER Managing Outlook Folders In this chapter Understanding How Outlook Stores Information 40 Using the Navigation Pane and Folder List 44 Using and Managing Folders 52 Understanding Folder Properties
Chapter 5 MCTS/MCITP Exam 648 Maintaining an Active Directory Environment Exam objectives in this chapter: Backup and Recovery Offline Maintenance Monitoring Active Directory Exam objectives review: Summary
NovaBACKUP User Manual NovaStor / May 2014 2014 NovaStor, all rights reserved. All trademarks are the property of their respective owners. Features and specifications are subject to change without notice.
28 Crystal Reports with Visual Studio.NET Although most agree that it got off to a slower-than-anticipated start, Microsoft s Visual Studio.NET development environment appears to be gaining ground as the
4. Client-Level Administration Introduction to Client Usage The Client Home Page Overview Managing Your Client Account o Editing Your Client Record View Account Status Report Domain Administration Page
Microsoft IT Academy E-Learning Central Getting Started Guide This guide provides an overview of the Microsoft IT Academy E-Learning Central site for Administrators, Instructors and Students 1 Table of