An Administrator's guide to PowerShell

Friday, January 5, 2007

Powershelling Citrix (The Good, Bad, and The Code)

I would have to say that my first real experience with POSH was specifically with Citrix. As an Admin (one of many hats as a network engineer) of over 400 Citrix Servers and 3 Farms... I tend to script a alot. I am not a real fan of the CMC (Citrix Managment Console) and I much prefer anything that does not involve a GUI.

One of my biggest problems is that the three farms are isolated from each other. That makes what ever I do 3x the work. In this aspect... POSH has been a savior. I can write the script once... and then cut/paste. It's awesome.

The Good:

If there is one thing I like about Citrix (and thats about it) is the fact they wrote a series of COM interfaces for Metaframe. These are incredibly useful but until POSH you couldn't access these from the Command Shell. POSH lets you create COM objects on the fly so I use the Metafram COM interfaces exclusively.

The Bad:

As in all things Citrix... The COM interface is quirky (do I sound bitter?) I have run into a couple of little snags that if avoided will make your life alot easier.

1) Case Sensitive: I have found in my Citrix Use that for some reason. When you use MetaFrameCOM.MetaFrameServer and Initialize it... the Server Name must be in all CAPS. Not sure why (sorry) but I know if you don't .ToUpper the Server... it failes.

2) Initialize... Initialize... Initialize: Almost all of the MetaFrameCOM component's require you to Initialize... this would normally wouldn't be a problem, but the finding the Initialization codes was a bit a of a pain. (I posted them in the appendix.)

3) For none developers passing an object as a parameter (who'd of thunk it?): So... for you C# people this is normal, but for the rest u sof scripters... not so much. You can see example of this in my Publish-CitrixApplication Function at the line $mfApp.AddServer($mfAppBinding). You have to create an App Binding Object to Add the server.

The Code:

Name: Get-CitrixOnline
Purpose: Get All Citrix Servers Currently Online (not to be confused with published)
function Get-CitrixOnline {
Param([string]$zone)
$mfzone = New-Object -ComObject MetaFrameCOM.MetaFrameZone
$mfzone.Initialize("$zone")
$servers = $mfzone.OnlineServers
$servers sort ServerName Write-Output
}
Notes: Nothing special here, but make sure you know the zone name. You can get it from the CMC, but it should be the network of the first Citrix Server (i.e. 192.168.0.0)

Name: Get-CitrixApplications
Purpose: Get Citrix Apps published on Server
function Get-CitrixApplications {
Param([string]$server)
$Server = $Server.ToUpper() # Citrix requires Server in CAPS (how odd)
$mfsrv = New-Object -ComObject MetaFrameCOM.MetaFrameServer
$mfsrv.Initialize(6,"$Server")
Write-Host "SERVER $Server" -foregroundcolor Red
Write-Host "==================" -ForegroundColor Green
If($mfSrv.Applications.Count -gt 0) {
$mfSrv.Applications %{Write-Host "Published: $($_.AppName.ToUpper())"}
}
else {
Write-Host "No Applications Published for $Server" -foregroundcolor white
}
}
Notes: Very useful for getting quick idea at what apps a server has published.

Name: Publish-CitrixApplications
Purpose: Publish Citrix App on Server
function Publish-CitrixApplication {
Param([string]$Srv,[string]$myapp)
$Srv = $Srv.toUpper()
$mfSrv = New-Object -ComObject MetaFrameCOM.MetaFrameServer
$mfSrv.Initialize(6,"$Srv")
$mfApp = New-Object -ComObject MetaFrameCOM.MetaFrameApplication
$mfApp.Initialize(3,"Applications\$myapp")
$mfApp.LoadData($true)
$mfAppBinding = New-Object -ComObject MetaFrameCOM.MetaFrameAppSrvBinding
$mfAppBinding.Initialize(6,$Srv,"Applications\$app")
if($mfAppBinding) {
Write-Host "Publishing App[$myapp] on Server [$Srv]" -ForegroundColor Green
$mfApp.AddServer($mfAppBinding)
$mfApp.SaveData()
}
else {
Write-Host "Unable To Create App Binding" -ForegroundColor Red
}
}
Notes: Thing to be careful with this one is the $mfApp.Initialize(3,"Applications\$myapp") It is important to know that "Application\$myApp" needs to be the path you see in the CMC. If you created subfolders then you need to include them like $mfApp.Initialize(3,"Applications\Lab\$myapp").

Name: UnPublish-CitrixServer
Purpose: Remove All Citrix Apps from Server
function UnPublish-CitrixServer {
Param([string]$Server)
Write-Host
$Server = $Server.toUpper()
$mfSrv = New-Object -ComObject MetaFrameCOM.MetaFrameServer
$mfSrv.Initialize(6,"$Server")
If($mfSrv.Applications.Count -gt 0) {
Write-Host "Removing All Published Applications from $Server"
Write-Host "==================================================="
ForEach($app in $mfSrv.Applications) {
$myApp = $App.AppName
Write-Host "Removing App [$myApp] from Server [$Server]"
$app.RemoveServer($Server)
$app.SaveData()
}
}
else {
Write-Host "No Published Applications for $Server"
}
}
Notes: Pretty strait forward. Remember that it removes ALL apps from the server.

Name: Remove-CitrixApplication
Purpose: Removes Citrix App from Server
function Remove-CitrixApplication {
Param([string]$Srv,[string]$myapp)
Write-Host
$AppRemoved = $false
$Srv = $Srv.toUpper()
$mfSrv = New-Object -ComObject MetaFrameCOM.MetaFrameServer
$mfSrv.Initialize(6,"$Srv")
If($mfSrv.Applications.Count -gt 0) {
ForEach($app in $mfSrv.Applications) {
If($app.AppName -eq "$myapp") {
Write-Host "Removing App [$myApp] from Server [$Srv]"
$app.RemoveServer($Srv)
$app.SaveData()
$AppRemoved = $true
}
}
}
else {
Write-Host "No Applications Published for $Srv" -ForegroundColor Red
$AppRemoved = $true
}
If($AppRemoved -eq $false) {
Write-Host "This Application not Published for $Srv" -ForegroundColor Red
}
}
Notes: Only removes specified app.

Coming Soon: Should be posting more complex Citrix scripts to Add/Remove apps. Get some basic Stats, and such.

Appendix:
---------
Typical:
MetaFrameCOM.MetaFrameServer: (6,"SERVERNAME")
MetaFrameCOM.MetaFrameAppSrvBinding: (6,"SERVERNAME","AppPath\AppName")
MetaFrameCOM.MetaFrameApplication: (3,"AppPath\AppName")
MetaFrameCOM.MetaFrameZone: ("ZONE")
------ Will be adding headers soon -----

1 comment:

jv said...

Brandon

Excellent. One issue though... line wraps on cut/paste.

Try wrapping code in textarea or similar.

I use WIndows LiveWriter with a code plugin hat seems to help.

Ayway - I cut and pasted to notepad and fixed teh linefeeds.

Wish I had this a year ago. PS rellay does make this easier although vbscript works failrly well with the Citrix management objects.

About Me

Montclair, NJ, United States

technorati

Add to Technorati Favorites