Using Invoke-WebRequest with the Cisco PowerShell Agent

I’ve had a major initiative at the Day Job to overhaul some of our existing Cisco UCS Director workflows and try to squeeze more efficiency and reduce the potential critical stopping points in them, as we’ve continued to evolve our technical processes.  I decided that while Cisco UCS Director has some great visual tools for mapping out workflows, sometimes the tasks within are very rigid and the way task flow happens tends to lend a single task focus.  This doesn’t bode well when trying to reduce the over all execution times of the workflow, as you end up having to work in a pattern in which tasks can’t be executed independently from each other.  As an example, to execute the fourth task, which has no dependency upon tasks one through three, you have to wait for the execution of task one through three.  In my opinion, as long as I understand how my workflow is going to function, this is highly ineffecient.

To try to curb this issue, I decided to research some more into the idea of parallel processing with UCS Director.  There are some examples using the native JavaScript implementation of the tool (UCSD Parallel Workflow Execution Example), but I was much more interesting in flexing my muscle with PowerShell, as that’s my language of choice.  Cisco ships a tool for remote execution of PowerShell code in the form of an agent that can be installed on a Windows device that is added to the configuration of Cisco UCS Director.  From there, you can specify the account information and the script/code block you wish to execute.  A return response is sent back to UCS Director and you can use some XML parsing techniques, which can be very handy if you need variables back for other parts of workflows.

To make this happen, I realized that we would need to execute some of Cisco UCS Director’s REST APIs to be able to launch workflows within my script.  In PowerShell, this usually means pulling out the Invoke-WebRequest cmdlet.  In the case of this cmdlet and Cisco UCS Director, you will typically need three things to make calls to some of the REST APIs:  the URI, the header (including your X-Cloupia-Request-Key name/value pair in the form of a hashtable), and the method type.

Unfortunately, this didn’t exactly work as easily advertised.  When starting to trace exactly what the Cisco PowerShell Agent does, I found that the service really does nothing more than create a remote PowerShell session to the target you specify.  In my case, I tend to redirect the PSA to itself, as I have my modules and scripts easily accessible from this device.  When trying to execute an Invoke-WebRequest cmdlet through this created session, I receive the following error:

screen-shot-2017-01-18-at-2-28-30-pm

When looking through the Cisco PowerShell Agent log file we find that an error 3 is a pretty generic error.  Any sort of PowerShell error will trigger the PSA to report this back.  The log file includes some of the error message, so I was able to find that the specific error was a “Object reference not set to an instance of an object.”  Anyone who’s done enough PowerShell authoring knows this response well.  Typically, one of your arguments is either null or of the wrong error type.  So, I decided to try a couple of troubleshooting techniques to see what the issue was with Invoke-WebRequest.  I first tried to nest this in a try..catch sequence.  This way, I could potentially get a look at the error in question.  Unfortunately, the same problem occurred, but I was not presented with any sort of error.

I felt this was very odd, as this meant that something was happening at the level of the Cisco PSA called remote PowerShell session.  Armed with the idea that the error message being reported meant something might be up with my arguments to the cmdlet, I decided to look into some of the Invoke-WebRequest parameters.  I found the –UseBasicParsing parameter and decided to give that a whirl.  As you can see by the results below, it worked.

screen-shot-2017-01-18-at-2-32-26-pm

Now, UseBasicParsing isn’t a required parameter of the cmdlet.  Now, I wanted to test to make sure that I was potentially going to catch an error message within this remote PowerShell session, so I found another parameter in –Proxy and fed a dummy domain name and port to it.  This was the response.

screen-shot-2017-01-18-at-2-34-30-pm

Now that’s more like it!  That’s the type of error object I was expecting.  For this test, I only fed the Proxy parameter and did not apply the UseBasicParsing parameter.  At this point, I’m really starting to think there is something going on with the Cisco PSA and my cmdlet here.  To rule out any sort of remote PowerShell session issues, I wrote a quick script (script below) that created a new remote PowerShell session (to the same server) and tried launching it through the Cisco PSA.  Also, I did not use the UseBasicParsing parameter on the cmdlet.

Script:


$username = "*username*"
$the_password = ConvertTo-SecureString -String "*password*" -AsPlainText -Force
$the_cred = New-object -TypeName System.Management.Automation.PSCredential -ArgumentList $username, $the_password
$the_session = New-PSSession -ComputerName *PSA IP/FQDN* -Credential $the_cred
$response = Invoke-Command -Session $the_session -ScriptBlock { invoke-webrequest -Uri *HTTP/HTTPS URI*}
$the_session | Disconnect-PSSession | Remove-PSSession
return $response 

Result:

 

screen-shot-2017-01-18-at-2-40-00-pm

From the response, I got what I need.  I have a Content property, along with the properties of the remote PSSession that was created to get this response.

I have this information in to the Cisco UCS Director people and (long story) once I get my support contract renewed, I may run this through Cisco TAC to see if this can be logged as a potential defect (due to my belief that Invoke-WebRequest isn’t being handled correctly by the PSA).

So, forewarning for those trying to use PowerShell and Invoke-WebRequest (and to some degree Invoke-RestMethod), be wary of some weird issues with the session and remember to potentially use the UseBasicParsing parameter on the cmdlet OR resort to nesting remote PowerShell sessions.  In my case, I stuck with the remote PowerShell session nesting.  I’ll provide an update when/if I get this case to TAC.

Advertisements

About snoopj

vExpert 2014/2015/2016, Cisco Champion 2015/2016. Virtualization and data center enthusiast. Working too long and too hard in the technology field since college graduation in 2000.
This entry was posted in Technical and tagged , , , , . Bookmark the permalink.

2 Responses to Using Invoke-WebRequest with the Cisco PowerShell Agent

  1. Pingback: Cisco UCS Director and the PowerShell Agent – Part 1 | snoopj's Blog

  2. Pingback: Cisco UCS Director and the PowerShell Agent – Part 5 | snoopj's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s