Note: The scripts in this article should work for XenApp 6 and XenApp 5 for Windows Server 2008 and XenApp 5 for Windows Server 2003.



Similar documents
Microsoft Windows PowerShell v2 For Administrators

POWERSHELL (& SHAREPOINT) This ain t your momma s command line!

SUNGARD SUMMIT 2007 sungardsummit.com 1. Microsoft PowerShell. Presented by: Jeff Modzel. March 22, 2007 Course ID 453. A Community of Learning

PowerShell for Exchange Admins

How to Import PST Files into Mailboxes with Exchange 2010 SP1

Windows PowerShell Fundamentals

Forefront Management Shell PowerShell Management of Forefront Server Products

Jeffrey Snover Distinguished Engineer & Lead Architect Jason Helmick Senior Technologist, Concentrated Technology

Microsoft. Jump Start. M3: Managing Windows Server 2012 by Using Windows PowerShell 3.0

Dotnet Agent Installation with Remote Management - Powershell Extension Advanced Options

Automating. Administration. Microsoft SharePoint with Windows. PowerShell 2.0. Gary Lapointe Shannon Bray. Wiley Publishing, Inc.

Exploring PowerShell. Using Windows PowerShell

Using the Citrix Service Provider License Reporting Tool

Windows PowerShell Essentials

Lab Answer Key for Module 1: Installing and Configuring Windows Server Table of Contents Lab 1: Configuring Windows Server

User Experience Reference Design

Web Development using PHP (WD_PHP) Duration 1.5 months

SPHOL205: Introduction to Backup & Restore in SharePoint Hands-On Lab. Lab Manual

Track User Password Expiration using Active Directory

Executive Summary: Cost Savings with ShutdownPlus Rolling Restart

Lesson Plans Configuring Exchange Server 2007

Using SQL Database Mirroring to Improve Citrix XenApp Server Farm Disaster Recovery Capabilities

LAB 2: Identity Management

Installation Manager Administrator s Guide

Microsoft Office Web Apps Server 2013 Integration with SharePoint 2013 Setting up Load Balanced Office Web Apps Farm with SSL (HTTPS)

Understanding Native Applications, Tools, Mobility, and Remote Management and Assistance

WolfTech Active Directory: PowerShell

Table of Contents. KB Group Suite KB Bulk Mail version 1.0 Page 2 of 36 Copyright KB Group (UK) Ltd

Project Server 2010 Migration

Acknowledgments Finding Your Way Around Windows PowerShell p. 1 Getting Started with Windows PowerShell p. 3 Installing Windows PowerShell p.

Lync Server Patching Guide

XenDesktop 5 Database Sizing and Mirroring Best Practices

SharePoint 2016 [PREVIEW] Site Template ID List

Citrix Systems, Inc.

Not Just for Scheduling: Doing More with SAS Enterprise Guide Automation Chris Hemedinger, SAS Institute Inc, Cary, NC

Understanding Native Applications, Tools, Mobility, and Remote Management and Assistance. Lesson 3

Moodle and Office 365 Step-by-Step Guide: Federation using Active Directory Federation Services

Migrating from SharePoint 2007 to SharePoint

Accounting Manager. User Guide A31003-P1030-U

PowerShell for Dummies

Facebook Twitter YouTube Google Plus Website

Quick Start Guide. Contents. Quick Start Guide Version 1.0 webcrm November 09

Unidesk 3.0 Script to Increase UEP Size for Persistent Desktops

Working with forms in PHP

System Requirements for Microsoft Dynamics GP 2013

Windows PowerShell. 3.0 Step by Step. Ed Wilson

XenDesktop 5 (SP1) Broker Event Log Messages. This article contains information on XenDesktop 5 (SP1) Broker Event Log Messages.

AUTOMATED DISASTER RECOVERY SOLUTION USING AZURE SITE RECOVERY FOR FILE SHARES HOSTED ON STORSIMPLE

Citrix EdgeSight for Load Testing Installation Guide. Citrix EdgeSight for Load Testing 3.8

Component Details Notes Tested. The virtualization host is a windows 2008 R2 Hyper-V server. Yes

CDP-H210 Introduction to Azure Active Directory

Creating Database Tables in Microsoft SQL Server

Citrix XenApp 6.5 Advanced Administration (CXA-301)

Configuring the Basic Settings of an ESXi Host with PowerCLI

LT Auditor Windows Assessment SP1 Installation & Configuration Guide

NetIQ. How to guides: AppManager v7.04 Initial Setup for a trial. Haf Saba Attachmate NetIQ. Prepared by. Haf Saba. Senior Technical Consultant

Deploying Remote Desktop Connection Broker with High Availability Step-by-Step Guide

DEPLOYMENT GUIDE DEPLOYING F5 AUTOMATED NETWORK PROVISIONING FOR VMWARE INFRASTRUCTURE

Windows Server 2008 R2: Server Management and PowerShell V2

Windows PowerShell Cookbook

What s New in Centrify Server Suite 2014

Citrix EdgeSight Active Application Monitoring Installation Guide

LAB 1: Installing Active Directory Federation Services

The steps will take about 4 hours to fully execute, with only about 60 minutes of user intervention. Each of the steps is discussed below.

Hands-On Lab. Client Workflow. Lab version: Last updated: 2/23/2011

A guide to https and Secure Sockets Layer in SharePoint Release 1.0

WINDOWS AZURE SQL DATA SYNC

NetIQ Advanced Authentication Framework - Administrative Tools. Installation Guide. Version 5.1.0

Windows Command-line Automation Techniques for Dell EqualLogic PS Series Arrays

The Exchange Management Shell

Copyright Texthelp Limited All rights reserved. No part of this publication may be reproduced, transmitted, transcribed, stored in a retrieval

STATISTICA VERSION 9 STATISTICA ENTERPRISE INSTALLATION INSTRUCTIONS FOR USE WITH TERMINAL SERVER

Core Essentials. Outlook Module 1. Diocese of St. Petersburg Office of Training

DEPLOYMENT GUIDE Version 1.1. Deploying the BIG-IP LTM v10 with Citrix Presentation Server 4.5

Preparing an IIS Server for EmpowerID installation

Project Server 2003 Install on SBS 2003 Courtesy of Chris Jones All rights reserved by the Author

Buffalo Technology: Migrating your data to Windows Storage Server 2012 R2

WHITE PAPER POWERSHELL FOR DUMMIES HOW TO KEEP TRACK OF

Getting Started with the Ed-Fi ODS and Ed-Fi ODS API

WHITE PAPER BT Sync, the alternative for DirSync during Migrations

PoSHServer Documentation AUTHOR: YUSUF OZTURK (MVP)

Contents. Introduction. Chapter 1 Some Hot Tips to Get You Started. Chapter 2 Tips on Working with Strings and Arrays..

DocAve 6 SDK and Management Shell

VMware View Backup Best Practices

Chapter 5 - Ethernet Setup

Platform support for UNIT4 Milestone 4

VMware vsphere PowerCLI User's Guide

HOUR 3 Creating Our First ASP.NET Web Page

VPS Hosting. The Guide to Bet Angel VPS. Getting started with Bet Angel VPS. Revised August Page 1

DocuSign for SharePoint

DEPLOYMENT GUIDE DEPLOYING THE BIG-IP LTM SYSTEM WITH CITRIX PRESENTATION SERVER 3.0 AND 4.5

Administration Guide. . All right reserved. For more information about Specops Gpupdate and other Specops products, visit

Implementing Microsoft Windows Server Failover Clustering (WSFC) and SQL Server 2012 AlwaysOn Availability Groups in the AWS Cloud

Windows Server 2003 Service Pack 1 (SP1) or later service packs Enhanced version of Ntdsutil.exe

Microsoft Expression Web Quickstart Guide

Implementation notes on Integration of Avaya Aura Application Enablement Services with Microsoft Lync 2010 Server.

Transcription:

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 http://tinyurl.com/xa6pssdk (Figure 1). Figure 1 To use PowerShell with XenApp 5, you will need the XenApp Commands Technology Preview (v3) available from http://tinyurl.com/xa5ctpv3 (MyCitrix login required) (Figure 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 2003. 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

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

$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):

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

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.

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. 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

$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 End $OfflineServers = @() ForEach( $Server in $XAServers ) If( $OnLineServers -notcontains $Server ) $OfflineServers += $Server 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. 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)

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

Figure 10 Since $obj is an array, Michael also wanted the members of the first element of the $obj array (Figure 5). $obj[0] get-member Note: PowerShell arrays start at 0. Figure 11

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.