Blog posts tagged with 'powershell'
Introduction
In this article I shall demonstrate the new XenServer PowerShell snap-in, using the simple example of "chained" VM starts: waiting for one VM to finish booting before starting the next.
In this example, we are using the XenServer Tools to detect when booting is complete: once they advertise the VM's IP address, we assume that the VM is ready. Of course, you may want to make this more sophisticated, for example waiting for a domain controller to start before moving on. I'll leave this to your imagination!
In the first screenshot, I've got XenCenter 5.0 talking to a XenServer 5.0 pool, XS-PS started afresh, and the script that runs this example, Start-VM.Wait.ps1. The PowerShell install is out-of-the-box, though I've already set the ExecutionPolicy to RemoteSigned.
Namespaces and Initialize-XenServer:Aliases
Firstly, a quick word about how we handle namespaces in XS-PS.
A lot of the Xen-API's names are very generic; a cmdlet called "Create-Message" could clash with any number of things. With this in mind, XenServer's cmdlets are named within a XenServer namespace, something like this:
Create-XenServer:VM Destroy-XenServer:VM Get-XenServer:VM Get-XenServer:VM.NameLabel Set-XenServer:VM.NameLabel Invoke-XenServer:VM.Start
This is great for people who want to use XS-PS in a mixed environment, but it's obviously a bit verbose for quick scripting, so we've added the ability to alias these full names to something shorter. In Start-VM.Wait's process block, you can see the following call:
Initialize-XenServer:Aliases Start
This introduces a full set of aliases, so that we can now use names such as
Create-VM Destroy-VM Get-VM Get-VM.NameLabel Set-VM.NameLabel Start-VM
These aliases are scoped within this script, so they won't pollute the user's environment. If you want, you can pass it a -Scope parameter, and have them put into an outer or global scope instead.
Initialize-XenServer:Aliases actually supports three styles of alias, so you can choose the style that best suits your environment, or you can stick with the full names if you prefer.
PS C:\Users\Ewan Mellor> Initialize-XenServer:Aliases Invoke-Xen = Get-Xen:VM / Invoke-Xen:VM.Start Invoke = Get-VM / Invoke-VM.Start Start = Get-VM / Start-VM
Start-VM.Wait
Start-VM.Wait takes its VMs from the pipeline. It then processes them one at a time, like this:
- If the VM record represents the control domain, or a template, then silently skip it.
- If the VM is unstartable (because it's already running, say), then log the fact, and skip it.
- Otherwise, call Start-VM. This will block until the VM boot process begins.
- Next, wait for up to five minutes for the VM to boot. We wait for the VM.guest_metrics field to be populated, and for an entry to appear in VM_guest_metrics.networks. Once there's an entry here, we know that the XenServer Tools are ready, and the VM has an IP address configured (from DHCP, for example).
- If polling this field fails after 5 minutes, then warn, and just move on to the next VM.
function Start-VM.Wait
{
begin
{
$timeout = 5 * 60 * 1000
Initialize-XenServer:Aliases Start
}
process
{
if ($_.is_a_template -or $_.is_control_domain)
{
return
}
if ($_.allowed_operations -notcontains "start")
{
Write-Warning("{0} cannot be started" -f $_.name_label)
return
}
Write-Verbose("Starting {0}..." -f $_.name_label)
Start-VM $_
for ($count = 0; $count -le $timeout / 500; $count += 1)
{
$metrics = Get-VM.GuestMetrics $_
if ($metrics -ne $null -and $metrics.networks.Count -gt 0)
{
Write-Verbose("VM {0} started" -f $_.name_label)
return
}
Start-Sleep -m 500
}
Write-Warning("Timeout starting {0}" -f $_.name_label)
}
}
Using it
Using this script is now very simple:
- Dot-source the script, to load the function.
- Set $VerbosePreference to "Continue", just for this demo.
- Connect to your master server.
- Choose the VM's that you want to start (in the example, all those tagged as "Production").
- Pipe those VM's into Start-VM.Wait.
- Watch the magic!
- Log out from your server afterwards.
PS> . .\Start-VM.Wait.ps1 PS> $VerbosePreference = "Continue" PS> Connect-XenServer -url https://<servername> PS> Get-XenServer:VM -Tags Production | Start-VM.Wait ... PS> Disconnect-XenServer
This is a simple example, and no doubt you would want to tweak it to match your deployment, but I hope that it's enough of an example for you to get started.
Downloads
The Citrix Desktop Delivery Controller PowerShell SDK provides a snap-in, XDCommands, for the Microsoft PowerShell v1.0 framework. The SDK consists of a number of "cmdlets" that allow you to script many of the administrative tasks you may need to perform on a regular basis.
Step by Step setting up your PowerShell / XenDesktop environment
- Install PowerShell 1.0 on the DDC (Desktop Delivery Controller)
- Download and Install Microsoft .NET Framework 3.5
- The PowerShell SDK is located on the XenDesktop 2.1 CD in the ...\Support\DdcSdk folder. Run the installer XenDesktop_2_0_DDC_Powershell_SDK.msi
Installing the SDK registers the XdCommands snap-in assembly with the Microsoft PowerShell framework. The snap-in makes a number of new classes and "cmdlets" available to PowerShell scripts or interactive shell sessions.
To run scripts you may need to use the built-in "Set-ExecutionPolicy" cmdlet to adjust the PowerShell execution policy to a value such as "RemoteSigned"
- Start Powershell and set the Excecution Policy. Set-ExecutionPolicy RemoteSigned
- Change to the folder where the SDK is installed cd \Program Files\Citrix\Desktop Delivery Controller\Powershell
- Load the snap-in into the PowerShell Add-PSSnapin XdCommands
Alternatively, use the installed PowerShell console file, XdCommands.psc1, to start an interactive PowerShell shell session with the XdCommands snap-in pre-loaded. Citrix provides a shortcut on the Start menu to start such a session. This shortcut also runs the "XdAliases.ps1" PowerShell script that sets up aliases for most of the SDK cmdlets. This shortcut will not function properly until the PowerShell execution policy, as described above, is set appropriately.
Help
Online help is available for all Desktop Delivery Controller SDK cmdlets. To obtain a list of cmdlets offered by the snap-in, run the built-in "Get-Command" cmdlet, as follows: Get-Command -psSnapin XdCommands
Online help for individual cmdlets is available using the built-in "Get-Help" cmdlet. For example, to view the online help for the "Get-XdDesktopGroup" cmdlet, run the following command: Get-Help Get-XdDesktopGroup
For an overview of all cmdlets provided by the SDK, view the "about_XdCommands" help topic. To view this information, run the following command: Get-Help about_XdCommands
Samples
Creating a new VM-based desktop group
This command creates a new VM-based desktop group, "testgrp", containing three machines, and published to all domain users. $usr = New-XdUser 'domain users' -group $cred = Get-Credential 'root' $hs = New-XdHostingServer 'XDS01' $cred $machineName= 'machine1','machine2','machine3' #find all the VM machines in the pool $allvms = Get-XdHostedMachine $hs #Find the workers and set the AD identity to the correct machine $dsk = $machineName | foreach { $vm=$_; $allvms | where {$_.HostingName -match $vm } | foreach { $_.Name = $vm; $_ }} $hgs = New-XdGroupHostingSettings $hs $ng = New-XdDesktopGroup -pub 'testgrp' -desk $dsk -user $usr -hosting $hgs
Adding a virtual desktop to an existing VM-based desktop group
This command adds a new virtual desktop, hosted by a VM, to an existing VM-based desktop group. Before adding a VM to the group, you must create a mapping between the VMs host ID and Active Directory ID. To do this, run the Get-XdHostedMachine cmdlet to obtain a list of host IDs for VMs and assign Active Directory IDs to those VMs.
# get all the groups whose name starts with 'test' (should be just one) $grp = Get-XdDesktopGroup test* # get all the workers whose friendly names have 'machine3' in them (should be just one) $dsk= Get-XdHostedMachine $grp.HostingSettings.HostingServer -name *machine3* # Set up the mapping to the AD name for the new Virtual Desktop machine $dsk.Name = 'machine3' $grp.Desktops.Add($dsk) Set-XdDesktopGroup $grp
If host ID to Active Directory ID mappings have been created previously, run the following command:
Get-XdDesktopGroup test* | *%* { \[void\]$\_.Desktops.Add($(Get-XdHostedMachine $\_.HostingSettings.HostingServer \-name \*machine3\*)); $\_ }| Set-XdDesktopGroup
Logging off a user from all current sessions, after sending a warning message
This command displays a warning message to all users whose names start with "christian" before logging them off. Note that in this example there is specified time period (10 seconds) before logoff occurs.
# get sessions for all users whose names start with 'christian'
$sess = Get-XdSession -user christian*
# warn the user
Send-XdSessionMessage $sess 'Forced log off in 10 seconds'
Start-Sleep 10
#Then go ahead with the logoff
Stop-XdSession $sess
Adding a user to an existing desktop group
This command adds users in all groups whose names match "GroupName" to an existing desktop group.
# get all the groups whose name matches 'GroupName' (should be just one)
# Note could also be written as:
# $grp = Get-XdDesktopGroup GroupName
$grp = Get-XdDesktopGroup | ? {$_.Name -match "GroupName" }
$Usr = New-XdUser "UserName"
$grp.Users.Add($Usr)
Set-XdDesktopGroup $grp
Now that XenServer and XenCenter 5.0 have been released, we turn our attention to other things. One of those new projects is a PowerShell SnapIn for XenServer, which I'm pleased to announce today.
The new SnapIn is with private beta testers now, and will be available through this site very soon.
Here are a few basic examples. Over the next few days, I'll post some increasingly interesting examples, to help you get a feel for the new SnapIn.
PS> Get-Credential | Connect-XenServer -url https://<servername>
PS> Get-XenServer:VM -name Debian | Format-Table uuid,name_label,is_a_template,power_state
uuid name_label is_a_template power_state
---- ---------- ------------- -----------
2b676031-29b0-35... Debian Sarge 3.1 True Halted
b20f5359-1c5a-7b... Debian Etch 4.0 True Halted
9b14ee57-47fd-af... Debian Sarge 3.1... False Halted
04738c85-0bb7-ce... Debian Sarge 3.1 False Suspended
4b76320b-404b-0c... Debian Etch 4.0 (1) False Running
3e0982ed-0cfe-1e... Debian Sarge 3.1 False Suspended
PS> Get-XenServer:VM -name Debian -properties @{ is_a_template="false" } |
>> Format-Table uuid,name_label,power_state
uuid name_label power_state
---- ---------- -----------
9b14ee57-47fd-afc6-e057... Debian Sarge 3.1 (1) Halted
04738c85-0bb7-ce5a-40bc... Debian Sarge 3.1 Suspended
4b76320b-404b-0cdf-1583... Debian Etch 4.0 (1) Running
3e0982ed-0cfe-1ef5-7e5c... Debian Sarge 3.1 Suspended
PS> Invoke-XenServer:VM.start -vm "Debian Sarge 3.1 (1)"
PS> Get-XenServer:VM -name Debian -properties @{ is_a_template="false" } |
>> Format-Table uuid,name_label,power_state
uuid name_label power_state
---- ---------- -----------
9b14ee57-47fd-afc6-e057... Debian Sarge 3.1 (1) Running
04738c85-0bb7-ce5a-40bc... Debian Sarge 3.1 Suspended
4b76320b-404b-0cdf-1583... Debian Etch 4.0 (1) Running
3e0982ed-0cfe-1ef5-7e5c... Debian Sarge 3.1 Suspended
PS> Disconnect-XenServer -url https://<servername>
In my last blog I have started with the Introduction of PowerShell and MFCom. Today we'll provide you more information's about MFCom Objects and how to use them with PowerShell.
Check Session State
To retrieve the session state for each session within the Citrix farm you have to query IMetaFrameSession.SessionState. If the returned state of the session is MFSessionStateStale, no further attempt to read other session properties should be made. This state indicates that the session may no longer exist.
The following PowerShell script displays all active sessions within the farm and adds additional session information to the output. To check other session's states you only have to replace the session state type in the last line of the code.
#Type Definitions
$MetaFrameWinFarmObject = 1
$MFSessionStateUnknown = 0 #Unknown state
$MFSessionStateActive = 1 #User logged on
$MFSessionStateConnected = 2 #Connected to client
$MFSessionStateConnecting = 3 #Connecting to client
$MFSessionStateShadowing = 4 #Shadowing another session
$MFSessionStateDisconnected = 5 #Logged on but no client
$MFSessionStateIdle = 6 #Waiting for connection
$MFSessionStateListening = 7 #Listening for connection
$MFSessionStateResetting = 8 #Reset in progress
$MFSessionStateDown = 9 #Down due to error
$MFSessionStateInit = 10 #Initializing
$MFSessionStateStale = 11 #Stale session object
#Main
$farm = new-Object -com "MetaframeCOM.MetaframeFarm"
$farm.Initialize($MetaFrameWinFarmObject)
$farm.FarmName
$farm.Sessions | Where-Object { $_.SessionState -eq $MFSessionStateActive {color:black}}| Format-table Username,SessionName,AppName,ServerName,SessionState
Find disabled Application
Finding disabled applications is mostly useful in your production or test environment where you have to handle with many published applications. This property IMetaFrameApplication.EnableApp enables or disables the application.
- When you publish an application, it is enabled by default. Enabled applications are available to the users specified when the application was published. Disabled applications are not available to users.
- The application can become disabled internally if its server list becomes empty, or if its user list becomes empty and the application is not configured to accept anonymous connections.
- A disabled application is not available to clients.
#Type Definitions
$MetaFrameWinFarmObject = 1
#Main
$farm = new-Object -com "MetaFrameCOM.MetaframeFarm"
$farm.Initialize($MetaFrameWinFarmObject)
$farm.FarmName
$app = $farm.Applications
$app | foreach { $_ | ? { $_.EnableApp -eq 0 }}|Format-Table DistinguishedName
When you build a workflow using some of the PowerShell tasks you may come across a need for the special variable "$_". This variable represents the current pipeline object in PowerShell and is used in workflow tasks to refer to the passed in 'Input' object. One case where this comes up often is with the "Where-Object" task. When using this object your "Filter Script" property will typically contain something that looks like this:
$_.Status -eq "Running"
The above means to return all items from the Input object where the Status field is "Running"
I found this site that does a great job of explaining the special variables in PowerShell if you want to explore further:
http://www.computerperformance.co.uk/powershell/powershell_variables.htm
That site has a lot of tutorial pages on PowerShell covering the escape character I talked about in my previous post as well as a good summary of PowerShell syntax. I find myself on that site often from searching for PowerShell topics and often find answers there.
There was a question on the forums about calling the XenApp task Connect To Farm when using a domain user name. Since we are using PowerShell heavily under the covers the string passed in to this task for the username needs to use the PowerShell escape character whenever a reserved character for PowerShell is in the string. I searched Microsoft's site, but couldn't find much detail out there on this so I wanted to clarify here:
The escape character for PowerShell is the grave-accent character "`" (which on US keyboards should be in the upper-left of the keyboard to the left of the number 1.
I haven't been able to find much posted on reserved characters on Microsoft's site, but here is a good article that highlights what is in the PowerShell help documentation:
http://www.microsoft.com/technet/scriptcenter/resources/qanda/jan08/hey0117.mspx
Here is the list of characters from that article:
$
( )
*
+
.
[ ]
?
\
/
^
{ }
|
If you need to use any of those characters in a string then you will need to escape it with the ` character. For example, to pass in a domain username to Connect to Farm in XenApp then you will need to pass in "domain`/user" instead of just typing "domain/user".
If you haven't read my post on whether we should have more customizable dialogs in Workflow Studio please check it out (here) and respond to the poll so I know what you think. In that post I mentioned that you could get custom dialogs today in Workflow Studio by leveraging PowerShell. Building Custom dialogs in PowerShell is not easy right now, but there are some projects out there to automate the process using the Visual Studio designer so it is getting easier. I'm not going to cover the specifics of how to create dialogs with PowerShell, but have a look at this Microsoft article for an introduction and then I will show you how to use this concept in Workflow Studio:
http://www.microsoft.com/technet/scriptcenter/resources/pstips/feb08/pstip0208.mspx
As I said, the process of building the dialog in PowerShell is tedious, but fortunately getting it into Workflow Studio is not so hard. Workflow Studio has a task called "PowerShell script" that can execute PowerShell script directly:

Just drag this task onto your workflow and paste the code from the above article into the "PowerShell Script" property. Now when you run your workflow you will get the dialog to appear. Pretty cool...
If you left all the defaults on your PowerShell Command task then you will also have the results of $x (the input string) in your $Output variable and you can use that in subsequent tasks.
In future articles I will look at how you can use this concept to create more complex dialogs and pass more complex objects out, but try it out and let me know what you think.
Microsoft Windows PowerShell command line shell and scripting language helps IT professionals achieve greater control and productivity. Using a new admin-focused scripting language, more than 130 standard command line tools, and consistent syntax and utilities, Windows PowerShell allows IT professionals to control system administration and accelerate automation more easily
With PowerShell, Citrix Administrators can script MFCom Objects to manage and administer the XenApp Farm. The secret of using COM objects starts with the command: New-Object -COM.
The following PowerShell example creates a new MetaFrame object (do not get confused with the COM Object naming), initializes the Farm and prints out the farmname:
$farm = new-Object -com "MetaframeCOM.MetaframeFarm"
$farm.Initialize(1)
$farm.FarmName
It's not going to be a spectacular script. But look at the following little code enhancement:
$farm = new-Object -com "MetaframeCOM.MetaframeFarm"
$farm.Initialize(1)
$farm.FarmName
$farm.sessions | Format-Table UserName,ClientAddress
Just adding one more lines of code and you will get all sessions within the farm displaying the Username and IP Address.
Setting up your PowerShell / MFCom environment
Beginning with PowerShell / MFCom Scripting you should install Microsoft Powershell on a Citrix Presentation / XenApp Server in your lab. I recommend downloading the PowerShell Graphical Helpfile which also provides great information's about VBScript to PowerShell conversion.
For creating and editing your PowerShell scripts I suggest downloading the free PowerGui graphical user interface and script editor. Its easy to use and works well with COM Objects.
PowerShell
http://www.microsoft.com/windowsserver2003/technologies/management/powershell/download.mspx
PowerShell Graphical Help File
http://www.microsoft.com/downloads/details.aspx?FamilyId=3B3F7CE4-43EA-4A21-90CC-966A7FC6C6E8&displaylang=en
PowerGui - Graphical user interface and script editor
http://www.powergui.org

Displaying apps in your farm
To give you some basic ideas where PowerShell leverages your daily administrative tasks, I've created the following script:
$farm = new-Object -com "MetaframeCOM.MetaframeFarm"
$farm.Initialize(1)
$farm.FarmName
$farm.applications| where {$_.BrowserName -like "Winword*" {color:black}} | select DistinguishedName
The script above enumerates each application published in the farm and selects all applications where Winword* is contained in the BrowserName.
PowerShell Examples provided by CDN
PowerShell and other scripting examples can be found on the Citrix Developer Network:
In a previous post about use cases for IT Process Automation and Workflow Studio I mentioned building a workflow to facilitate a "Green Data Center". Workflow Studio can help with this by managing the workloads on your servers and turning servers off when they are not needed. In this post I will show you 2 ways that you can shutdown a windows server from a workflow (these are native to Windows, if you are using 3rd party tools let me know in the comments.)
- "Launch Process" Task - Windows has a built-in utility (shutdown.exe) that can shutdown computers on your network remotely. Using the Workflow Studio "Launch Process" task allows you to call the shutdown command and pass it the arguments you want for your needs. You can see all the arguments by typing "shutdown /?" at your command line and there are several detailed write-ups on Microsoft's site (here and here for example).
- "PowerShell Script" Task - WMI has a class (Win32_OperatingSystem) that can be used to shutdown computers as well. Workflow Studio has a task called "Get WMI Info" that is designed to query WMI classes, but unfortunately it cannot call methods on the WMI classes. We will need to leverage a scripting environment like PowerShell to be able to call the method (or you could use VBScript.) Fortunately, in PowerShell we only need one line of code to achieve this:
(Get-WmiObject -Class Win32_OperatingSystem -ComputerName <computer name>).shutdown()
Add that line of code to your "PowerShell Script" task and replace the <computer name> with the name of the computer you would like to shutdown.
In this post I looked at shutting down a Windows Server, but in future posts I will expand this and look at how to use Wake On LAN to power machines back on, how you can manage power on a XenServer host machine, and how you can integrate this with logic to monitor when to shut down and start up your servers.
Power management is an area that we are working diligently on internally to build out a robust set of tasks for you. Have you tried automating server shutdown processes in your data center? What issues do you face? What kinds of inputs do you want to be able to leverage to determine when to shutdown a server?
The PowerScripting podcast including the interview with myself on Workflow Studio and PowerShell has been posted:
http://powerscripting.wordpress.com/2008/07/07/episode-32-citrix-does-powershell/
The interview with me starts at 15:30 in.
Enjoy!
Page: 1 2 3 Next >>