Nitro C# APIs for Command Center – Scripting with PowerShell

In my previous post on the Nitro APIs for NetScaler I shared some PowerShell examples for interacting with a NetScaler using the Nitro C# API SDK in PowerShell. I wanted to share some similar tips and samples for scripting with the Command Center APIs, which has quite a few more gotchas than the NetScaler APIs (in my opinion :).

Loading the Command Center version of the Nitro C# framework in PowerShell is about the same as the NetScaler. Just like on the NetScaler, the needed assemblies can be found at the ‘Downloads’ section on the Command Center web console:

Command Center Downloads

Download and extract the tarball to your scripting environment’s working directory. Next, add the Command Center Nitro .NET framework into your runspace using the Add-Type cmdlet:

Add-Type -Path .\newtonsoft.json.dll
Add-Type -Path .\cmdctr_nitro.dll

The last requirement, which is not needed with the NetScaler APIs, is to copy ccapi.xml to your $HOME directory:

Copy-Item -Path .\ccapi.xml -Destination $HOME

If you don’t have this file in your $HOME directory you’ll get an exception when attempting to connect to the server. To do so, use com.citrix.cmdctr.nitro.service.nitro_service.login(UserName, Password):

$Credentials = Get-Credential
$nitrosession = new-object com.citrix.cmdctr.nitro.service.nitro_service($ccserver,8443,"https")
$nitrosession.login($Credentials.GetNetworkCredential().UserName, $Credentials.GetNetworkCredential().Password)

Once logged in the class heirarchy is very similar to the NetScaler APIs. Let’s look at a couple of examples of what you can do from here with some code snips along the way.

The primary reason that I wanted to write a script against Command Center was to run batches of tasks against a list of NetScalers and variables. In the script I took two such csv lists as parameters loop on each to execute the tasks sequentially against each NetScaler in the list.In this example I’ll show you how to run a custom task and passing values to populate the task’s ‘UserInput’ variables.

First, create a custom task in Command Center, in this example we’ll add a user that’s passed as a variable $user$:

Command Center Custom Task

In your PowerShell runspace load the following cmdctr.nitro.resource.configuration objects; ns_task_execution_data to get the task’s UserInput values, an ns_task of the task that will be executed, and a scheduler_data to specify how it should be execute:

$taskname = "Test"
$user = "User1"
$nsip = "10.0.0.1"
$task = New-Object com.citrix.cmdctr.nitro.resource.configuration.ns_task_execution_data
$taskdetails = [com.citrix.cmdctr.nitro.resource.configuration.ns_task]::get($nitrosession, $taskname)
$taskschedule = New-Object com.citrix.cmdctr.nitro.resource.configuration.scheduler_data
$taskschedule.recurr_type = "no_reccur"

From here we’ll need to put the user variable into the $task.user_input_props property. To do this you’ll need to build an explicit Dictionary[System.String,System.String] object:

$userinputprops = New-Object "System.Collections.Generic.Dictionary``2[System.String,System.String]"

Next, assign the user name variable taskdetails.task_variable_list[0].name dictionary entry. Note that the format is very specific here, most notably explicit single quotes around $UserInput$ to make sure the $’s stay in the string:

$userinputprops['$UserInput$' + $taskdetails.task_variable_list[0].name] = $user)

Since there’s only one variable in this task, we can set the $task.user_input_props property using ns_taskexecution_data.set_user_input_props(), but would otherwise do a for loop on the $taskdetails.task_variable[] array to assign multiple variables:

$task.set_user_input_props($userinputprops)

Now fill out a few other task properties, including the user who ran the job, an annotation notating the computer it was executed from, the target NetScaler IP to run the task against

$task.task_name = $taskdetails.name
$task.executed_by = ($Credentials.UserName).Split('\')[1]
$task.scheduler_data = $taskschedule
$task.annotation = "Nitro automated task executed from $($env:COMPUTERNAME)"
$task.device_list = $nsip

Then execute the task using the execute() method of the ns_task_execution_data class, passing the $task object as the second parameter:

$task = [com.citrix.cmdctr.nitro.resource.configuration.ns_task_execution_data]::execute($nitrosession,$cctask)

This will start the task in Command Center, which can then be monitored by calling get() in ns_task_status:

$taskstatus = [com.citrix.cmdctr.nitro.resource.configuration.ns_task_status]::get($nitrosession, ($cctask.execution_ids)[0])

You can then do a while/start-sleep loop on $taskstatus.status to find out what happened:

Do { $taskstatus = [com.citrix.cmdctr.nitro.resource.configuration.ns_task_status]::get($nitrosession, ($cctask.execution_ids)[0])
Start-Sleep -Seconds 1 }
While ($taskstatus.status -match "Progress" -or $taskstatus.status -match "Queued")

Once the task is complete, check the status of what happened:

if ($taskstatus.status -eq "Success")
{ Write-Host "$($cctask.task_name) completed on $nsip" }

As always it’s a lot easier to deal with a success than a failure, here’s wait it takes to see what command failed, and what the error was, if the task faced a conflicting config:

if ($taskstatus.status -eq "Failed")
{	
 $ccfilter = New-Object com.citrix.cmdctr.nitro.util.filtervalue
 $ccfilter.properties.Add("id",$taskstatus.taskexecution_id + "")
 $errorlog = [com.citrix.cmdctr.nitro.resource.configuration.command_log]::get_filtered($nit rosession,$ccfilter)
 $failedcmd = ($errorlog.output.Split("`n")[2] -replace "`n|`r").Split(':')[1]
 $failedmsg = ($errorlog.output.Split("`n")[3] -replace "`n|`r").Split(':')[1] 
 Write-Host "$($cctask.task_name) failed at '$failedcmd', the error was '$failedmsg'"	
}

I hope this example was useful and that you enjoyed a second Nitro boost for your Citrix scripting repertoire!

10 comments

  1. Darius · August 31, 2015

    trying to use your powershell script to login to comman center, but i’m getting : “new-object : Exception calling “.ctor” with “3” argument(s): “Object reference not set to an instance of an object.””

    • Kenny Baldwin · August 31, 2015

      This sounds like what happens if ccapi.xml is missing from $HOME; can you run a ‘dir $HOME ccapi.xml’ to confirm?

      • Darius · September 1, 2015

        Started to work, when moved ccapi.xml to C:\windows\system32 folder

  2. Stan White · July 14, 2016

    Good afternoon, I was attempting to use your example to run a command center task that kicks off a “show vrid” for a list of netscalers. When I try to execute method on the task, it tells me that the SSH credentials are missing, but I cannot find where I would set those in your example or by browsing in visual studio… would you happen to know how I set those? they are required fields in command center, but on the task I don’t see a way to set them.

    • Kenny Baldwin · July 14, 2016

      The SSH credentials are defined in the Device Profile (under Citrix Network), which is then bound to the NetScalers in the Device Inventory.

      Did you already assign a device profile to the NetScalers that you’re running the custom task against?

      • Stan White · July 14, 2016

        Our admins do have a profile setup and when I look, I’m assuming that is the user credentials area of that profile… they have the username populated but not the password. I was hoping there was a way to pass in my network creds kind of like when I create the $nitrosession for the task, is that not possible? I do not believe they will change the profiles due to security reasons… Any other options? If not, I will try to bark up that tree… 😉

      • Kenny Baldwin · July 14, 2016

        Ah, in that case you’d likely need to create and bind a new device profile before executing the task; as far as I know the Device Profile is the only way to provide credentials for custom tasks.

      • Stan White · July 14, 2016

        thank you for the quick response.

      • Stan White · July 14, 2016

        One last question… is there a way to bind a profile to the netscaler via the NITRO API, or do I have to do it inside command center and then just call the task? I don’t see anything off the top of my head, but I’m fairly new to the NITRO piece.

      • Kenny Baldwin · July 14, 2016

        Adding a device profile is pretty easy; something like this at minimum:


        $newprofile = New-Object com.citrix.cmdctr.nitro.resource.discovery.device_profile
        $newprofiledetails = New-Object com.citrix.cmdctr.nitro.resource.discovery.device_profile_details

        $newprofiledetails.ssh_user_name = "nsroot"
        $newprofiledetails.ssh_password = "password"

        $newprofile.name = "Profile Name"
        $newprofile.device_family = "NS"
        $newprofile.prof_details = $newprofiledetails

        $addprofile = [com.citrix.cmdctr.nitro.resource.discovery.device_profile]::add($nitrosession, $newprofile)

        As far as assigning the profile to a device, I’m not too sure at first glance, as I’ve yet to find a way to get devices from the inventory using the API, let alone assign a device profile.

        That said, if anyone reading knows, please share; otherwise I’ll do the same if/when I figure it out.

Leave a reply to Stan White Cancel reply