Posts RSS Comments RSS 117 Posts and 170 Comments till now

Citrix Policies and Powershell (Double the Pleasure!)

I notice there was entry on Brian Madden forums about creating Citrix Policies. http://www.brianmadden.com/Forum/Topic/97139

I decided to spend a little time looking at this from a script perspective and here are some examples of dealing with Citrix Policies that I came up with.

Just a FYI
I hear tell there will be some Citrix CMDLets coming very soon that will make working with Citrix amazingly simple (which will include an import/export Citrix policy cmdlets.) I cannot tell you how revolutionary this will be for your typical Citrix Admin.

You can find the Citrix Enums here
http://bsonposh.com/modules/wordpress/?p=62

Script To Get Citrix Policy

  1. # Get-CitrixPolicy.ps1
  2. Param($Server,$PolicyName = ".*")
  3.  
  4. # Enums in Use
  5. $MetaFrameUnknownObject = 0
  6. $MetaFrameWinFarmObject = 1
  7.  
  8. # Getting Farm Object
  9. $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeFarm",$Server)
  10. $mfarm = [system.Activator]::CreateInstance($type)
  11. $mfarm.Initialize($MetaFrameWinFarmObject)
  12.  
  13. # Getting Policies that Match Name and Loading Data
  14. $pol = $mfarm.policies($MetaFrameUnknownObject) | ?{$_.Name -match $PolicyName}
  15. $pol | %{$_.LoadData($true)}
  16. $pol

Script To Create a New Citrix Policy

  1. # New-CitrixPolicy.ps1
  2. Param($Server,$PolicyName,$PolicyDescription)
  3. if(!$PolicyDescription){$PolicyDescription=$PolicyName)
  4. $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeFarm",$Server)
  5. $mfarm = [system.Activator]::CreateInstance($type)
  6. $mfarm.Initialize(1)
  7. $NewPolicy = $mfarm.CreatePolicy(19,$PolicyName,$PolicyDescription)

Script To Remove a Citrix Policy

  1. # Remove-CitrixPolicy.ps1
  2. Param($Server,$PolicyName = $(throw ‘$PolicyName is Required’),[switch]$whatif)
  3.  
  4. # Enums in Use
  5. $MetaFrameUnknownObject = 0
  6. $MetaFrameWinFarmObject = 1
  7.  
  8. # Getting Farm Object
  9. $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeFarm",$Server)
  10. $mfarm = [system.Activator]::CreateInstance($type)
  11. $mfarm.Initialize($MetaFrameWinFarmObject)
  12.  
  13. # Getting Policies that Match Name and Loading Data
  14. $policies = $mfarm.policies($MetaFrameUnknownObject) | ?{$_.Name -eq $PolicyName}
  15. foreach($pol in $policies)
  16. {
  17.     if($whatif){Write-Host " What if: Performing operation `"Delete`" on Target `"$($pol.Name)`". " -foreground yellow}
  18.     else{Write-Host " - Deleting $($pol.Name)";$pol.Delete()}
  19. }

An Interactive Case for Powershell (Yet more Citrix Fun!)

I was recently in a discussion on Brian Madden Forums about listing Citrix Information and exporting to CSV. It seemed like a
perfect fit for Powershell so I converted the VBScripts to Powershell (of course taking an 85 line script to 3 lines. Convert is
hardly the correct term.)

Here is the Forum Topic
http://www.brianmadden.com/Forum/Topic/95285

Here is my Code. There were three scripts, so I made three as well.

  1. # Apps by Server CTXApps_by_Server_w_Users
  2. $MF = (New-Object -com MetaFrameCOM.MetaFrameFarm)
  3. $MF.Initialize(1)
  4. $MF.Servers | Select-Object ServerName -expand Applications | Select-Object ServerName,AppName,DistinguishedName,
  5.        @{n=‘Users’;e={$_.Users | %{$_.UserName}}},
  6.        @{n=‘Groups’;e={$_.Groups | %{$_.GroupName}}} | export-Csv C:\AppsByServer.Csv -noType
  1. # Apps with Servers
  2. $MF = New-Object -com MetaFrameCOM.MetaFrameFarm
  3. $MF.Initialize(1)
  4. $MF.Applications | Select-Object AppName,DistinguishedName,
  5.       @{n="Servers";e={$_.Servers | foreach{$_.ServerName}}} | export-Csv C:\AppsWithServer.Csv -noType
  1. # Apps with Servers and Users CTXApps_w_Servers_w_Users
  2. $MF = New-Object -com MetaFrameCOM.MetaFrameFarm
  3. $MF.Initialize(1)
  4. $MF.Applications | Select-Object AppName,DistinguishedName,
  5.       @{n="Servers";e={$_.Servers | foreach{$_.ServerName}}},
  6.       @{n=‘Users’;e={$_.Users | %{$_.UserName}}},
  7.       @{n=‘Groups’;e={$_.Groups | %{$_.GroupName}}} | export-Csv C:\AppsWithServerandUsers.Csv -noType

If you notice in my three scripts they all start with the same two lines. Effectively these are one liners that could be used
interactively. I think this does a great job of showing Citrix Admins how nicely Powershell will fit in to their daily lives.
Things that use to take 100s of lines of script writing can now be done interactively at a shell.

Get-CitrixServerLoad (The power of objects in Citrix)

I watch the forums at BrianMadden.com because I use Powershell a lot for Citrix. This question was brought up.

Q: How could one:
- query “server load” on all servers part of the farm
- extract all server under a minimum server load
- apply an “Offline” load evaluator on the extracted servers (in order to make them unavailable on the farm)

I posted a script to do what they wanted, but then I got to thinking… while it did achieve the goal it wasn’t very Powershellish.

As I have said over and over. The glory of Powershell is the objects. So I decided to Post this entry showing what I would consider the Powershell way :)
Ideally you should just do this at the prompt

PS> Get-CitrixServers | where{$_.WinServerObject.Serverload -lt $load} | Set-CitrixLoadEvalutor “OffLine”

This is easy to achieve with the following scripts or even better make them functions!

Get-CitrixServers

  1. param($Server)
  2. $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeFarm",$Server)
  3. $mfarm = [system.Activator]::CreateInstance($type)
  4. $mfarm.Initialize(1)
  5. $mfarm.zones | foreach-Object{$_.OnlineServers}

Set-CitrixLoadEvalutor

  1. Param($server,$LoadEvaluator = "MFDefaultLE",[switch]$Verbose)
  2. #NOTE: This only work for 4.0 and 4.5
  3. if($verbose){$verbosepreference = "Continue"}
  4.  
  5. function Set-LE{
  6.     Param($mySrv)
  7.     # Getting Current LE
  8.     write-Verbose "   + Set-LE called : $($mySrv.ServerName)"
  9.     $le = $mfServer.AttachedLE
  10.     $le.LoadData(1)
  11.     Write-Verbose "     - Old Evaluator: $($le.LEName)"
  12.     Write-Verbose "     - Setting to $LoadEvaluator"
  13.  
  14.     # Assigning New LE
  15.     $mySrv.AttachLEByName($LoadEvaluator)
  16.  
  17.     # Checking LE
  18.     $le = $mySrv.AttachedLE
  19.     $le.LoadData(1)
  20.     Write-Verbose "     - Load Evaluator Set to $($le.LEName)"
  21.  
  22. }
  23.  
  24. if($Server)
  25. {
  26.     # Loading Server Object
  27.     Write-Verbose " + Processing $Server"
  28.     $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeServer",$Server)
  29.     $mfServer = [system.Activator]::CreateInstance($type)
  30.     $mfServer.Initialize(6,$Server)
  31.     Write-Verbose "   - Calling Set-LE"
  32.     Set-LE $mfServer
  33. }
  34.  
  35. if($list)
  36. {
  37.     foreach($Srv in (Get-Content $list))
  38.     {
  39.         Write-Verbose " + Processing $Srv"
  40.         # Loading Server Object
  41.         Write-Verbose "   - Getting Citrix Object"
  42.         $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeServer",$Srv)
  43.         $mfServer = [system.Activator]::CreateInstance($type)
  44.         $mfServer.Initialize(6,$Srv)
  45.         Write-Verbose "   - Calling Set-LE"
  46.         Set-LE $mfServer
  47.     }
  48. }
  49.  
  50. if($input)
  51. {
  52.     foreach($Srv in $input)
  53.     {
  54.         Write-Verbose     " + Processing $Srv"
  55.         if($Srv.ServerName)
  56.         {
  57.             Write-Verbose "   - Input is a Citrix Server: $Srv"
  58.             Write-Verbose "   - Calling Set-LE"
  59.             Set-LE $Srv
  60.         }
  61.         else
  62.         {
  63.             Write-Verbose "   - Input: $Srv"
  64.             # Loading Server Object
  65.             Write-Verbose "   - Getting Citrix Object"
  66.             $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeServer",$Srv)
  67.             $mfServer = [system.Activator]::CreateInstance($type)
  68.             $mfServer.Initialize(6,$Srv)
  69.             Write-Verbose "   - Calling Set-LE"
  70.             Set-LE $mfServer
  71.         }
  72.     }
  73. }

This was the all in one that I posted

  1. Param($Server,$minLoad = 1000,$LoadEval,[switch]$verbose)
  2. if($verbose){$verbosepreference = "continue"}
  3. function Get-CitrixFarm{
  4.     param($Srv)
  5.     $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeFarm",$Srv)
  6.     $mfarm = [system.Activator]::CreateInstance($type)
  7.     $mfarm.Initialize(1)
  8.     Write-Verbose "Loading Farm $($mFarm.FarmName)"
  9.     return $mFarm
  10. }
  11. function Set-CitrixLoadEvalutor{
  12.     Param($server,$LoadEvaluator = "MFDefaultLE")
  13.  
  14.     # Loading Server Object
  15.     $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeServer",$Server)
  16.     $mfServer = [system.Activator]::CreateInstance($type)
  17.     $mfServer.Initialize(6,$Server)
  18.  
  19.     # Getting Current LE
  20.     $le = $mfServer.AttachedLE
  21.     $le.LoadData(1)
  22.     Write-Verbose "Old Evaluator: $($le.LEName)"
  23.     Write-Verbose "Setting Load Evaluator on $server to $LoadEvaluator"
  24.  
  25.     # Assigning New LE
  26.     $mfServer.AttachLEByName($LoadEvaluator)
  27.  
  28.     # Checking LE
  29.     $le = $mfServer.AttachedLE
  30.     $le.LoadData(1)
  31.     Write-Verbose "Load Evaluator Set to $($le.LEName)"
  32. }
  33.  
  34. $farm = Get-CitrixFarm $Server
  35. foreach($ctxServer in $farm.Servers)
  36. {
  37.     $load = $ctxServer.WinServerObject.Serverload
  38.     Write-Host ("{0,-15} :: {1}" -f $ctxServer.ServerName,$load)
  39.     if($load -lt $minLoad)
  40.     {
  41.         Write-Verbose "Setting Offline Load Eval"
  42.         if($LoadEval){Set-CitrixLoadEvalutor $ctxServer.ServerName $LoadEval}
  43.     }
  44. }