chadlockwood
Kilo Sage

I wanted to pass an object from PowerShell to my workflow, instead of creating individual standard out tags that had to be individually parsed. This is a working process I found. You will need to:

  1. Create a PowerShell script
  2. Create a custom activity using the Activity Designer
  3. Add the custom activity to a workflow

Create the PowerShell script

PowerShell w/ JSON

PowerShell handles JSON data very well, either parsing JSON passed in or creating JSON to pass out I first created an object in PowerShell and added properties with the data I wanted in my workflow. This could be accomplished with any object but for demo purposes, I created my object manually:

$myOutput = @{}

$myOutput.name = "Chad" #Hi

$myOutput.age = 21 #oh to be young again

$myOutput.eye_color = "Brown" #sort of

$myOutput.car = "1965 Ford Mustang" #one of my all time favorites

To output the object, first it must be converted to JSON

$myData = $myOutput | ConvertTo-Json

Then write out the data. Notice that I am not using the standard out tags "%%output%%"

Write-Host $myData

PowerShell w/ XML

XML takes a little more effort to generate, but it is easy to read and may be more familiar to some. Using the same object as before, create the XML string with data included. This I found in the wiki

$data = @"

      <output>

              <name>$($myOutput.name)</name>

              <age>$($myOutput.age)</age>

              <eye_color>$($myOutput.eye_color)</eye_color>

              <car>$($myOutput.car)</car>

      </output>

"@

Then write out the data. Again, not using tags:

Write-Host $data

In the case of XML, you wouldn't necessarily need to create the $myOutput object first. You could simply create the $data string and include any data or variables that you needed.

The whole code should look something like this:

$myOutput = @{}

$myOutput.name = "Chad" #Hi

$myOutput.age = 21 #oh to be young again

$myOutput.eye_color = "Brown" #sort of

$myOutput.car = "1965 Ford Mustang" #one of my all time favorites

$myData = $myOutput | ConvertTo-Json

Write-Host $myData

-OR-

$myOutput = @{}

$myOutput.name = "Chad" #Hi

$myOutput.age = 21 #oh to be young again

$myOutput.eye_color = "Brown" #sort of

$myOutput.car = "1965 Ford Mustang" #one of my all time favorites

$data = @"

      <output>

              <name>$($myOutput.name)</name>

              <age>$($myOutput.age)</age>

              <eye_color>$($myOutput.eye_color)</eye_color>

              <car>$($myOutput.car)</car>

      </output>

"@

Write-Host $data

Create a new MID Server script file: MID Server > Script Files

Copy/paste your PowerShell code into the script field

Create the custom activity

Open the Workflow editor: Orchestration > Workflow Editor

Select the Custom tab and click the plus

Select Powershell

Enter a name for the activity and click Continue

For demonstration purposes, my custom activity does not have any input variables.

Click Continue

Under Execution Command, enter the following:

  • - Target host: 127.0.0.1
  • - Script type: MID Server script file
  • - MID Server script file: Select the PowerShell script file

Click Continue

Now, here comes the juicy part

Create output variable and map the values

At this point click Test Inputs. The activity will run your script and return results. Click output. You should see your resulting data object.

resp_json.png - resp_xml.png

Click Save for parsing rules. This will give you data to work with when creating parsing rules.

Click the plus to the right of {} Output

Enter a name for the output variable and change the type dropdown to Object

Press Enter and you will see another plus to the right of your new variable

Click that plus to create as many object attributes as necessary

var_json.pngvar_xml.png

For the demo, I created four; one for each attribute that I was passing from PowerShell

Hover your mouse over the name of the first attribute; your pointer will turn into a fist

Click and drag to the grey box under Parsing rules > Variable name

You will see the box populated with activityOutput.<your variable name>.<your attribute name>

A popup will appear titled Parsing rule for <objectName>.<property>

rules_json.pngrules_xml.png

Set the Parsing source to executionResult.output

Select the appropriate Parsing Type. For this demo either JSON or XML

To set the expression, hover over the Sample payload data and click the attribute you want to assign to this variable. You should see the data you wanted in the Parsing result field and the Expression field should be filled in with an appropriate value.

Click Submit

Once you have created parsing rules for all of your variables, click Continue.

rules.png

The final step for your activity is to create conditions. This will create the paths that your activity will be able to take in the workflow. For this demo I simply created an Always. For a production activity you would likely want to create a Success and a Failure path.

condition.png

Publish the activity and add it to a test workflow. I created a simple workflow on the Global table with the custom activity and a Run Script to show parsing the data.

wf.png

When you run this workflow, assuming it is successful, hover over the activity you created to see the Databus output:

databus.png

In the Run Script, I used workflow.info to write the data out to the workflow log:

workflow.info("****name: " + data.get(4).myData.name);

workflow.info("****age: " + data.get(4).myData.age);

workflow.info("****car: " + data.get(4).myData.car);

workflow.info("****eye color: " + data.get(4).myData.eye_color);

bsweetser explains how to get at the Databus variables

Hopefully, you see output like this in the Workflow Log:

wf_info.png

So, there you have it. Passing an object from PowerShell to the workflow, then parsing the data.

Comments
sahanabhat
Kilo Contributor

I was searching for a resource like this. Very useful! Thank You...


muthyala
Kilo Explorer

Very useful!!!


tiyasa
Giga Expert

Hi Chad - This is a very useful share. Thank you for the detailed steps.


scottdouglas
Kilo Explorer

Very helpful, thank you


Rahman4
Tera Guru

Hi,

I am following up your steps however the response I am getting is not returning the result from my ps1 file. It just returns this:

{
"hresult": null,
"output": "\n",
"errorMessages": null,
"debugMessages": null,
"credentialDebugInfo": "2019-03-23 09:18:02 Tried credential: MID service account, status=success\r\n",
"eccSysId": "abf664a64f1033002297417da310c7e1",
"tags": {
"__text__": "\n"
}
}

 

Somehow its not returning the JSON result from Powershell back. Is this something that is changed in London and not working anymore?

 

My PS1 file content is:

$services = (Get-Service | select name);

$output = @();

foreach($service in $services){
if($output -notcontains $service){
$output += $service;
}
}

$myData = $output | ConvertTo-Json

write-host $myData

 

Many thanks

 

 

chadlockwood
Kilo Sage

Raz,

At the end of you PS, do this:

Write-Host "%myOutput%"

Write-Host $myData

Write-Host "%%"

 

Then, see if the tags object in the output includes 'myOutput'

Rahman4
Tera Guru
Thank Chad, the solution was very simple and bit silly I guess. The Mid script file need to have a (.ps1) extension and mine didn't have. Ta.
garyminnick
Tera Contributor

Very good article.  I am new to ServiceNow and write a lot of PowerShell.  I tried the example in this article and it worked very well.  However when I tried to implement in a PS Activity I created I kept getting the error Invalid container object.  It turns out that if I have any text in my output that is not JSON it will error out.  But in my scripts I will output information for clarification and debugging.  I also will output custom return codes to handle errors.  Is there a way to parse the JSON formatted output when the output also has other outputs?

Example:

Write-Host "Starting script"

$myOutput = @{}

$myOutput.name = "Chad" #Hi

$myOutput.age = 21 #oh to be young again

$myOutput.eye_color = "Brown" #sort of

$myOutput.car = "1965 Ford Mustang" #one of my all time favorites

$myData = $myOutput | ConvertTo-Json

Write-Host $myData

 

This will cause the invalid container error because of the "Starting Script" text.  Is there a way to handle this?

Thanks!!

chadlockwood
Kilo Sage

Gary,

I don't think I've ever run into this issue before. However, a couple of things come to mind.

First, and I think I should go back and update the original post, at the end of the script you should output back to the activity this way:

Write-Host "%outputData%"
Write-Host $myData
Write-Host "%%"

You would then parse the data into an output variable using the tag outputData

You may just be parsing the entire output and I guess that would work as well.

As for outputting strings, I generally use Write-Verbose to see debugging information in the MID server logs. Alternatively, I will add a "message" attribute to $myOutput and write messages to that attribute that I can parse in the workflow.

$myData = @{
    success = $false
    message = ''
}

$myData.message += "\rNew added message"
$myData.success = $true

$outData = ConvertTo-JSON $myData

Write-Host "%outputData%"
Write-Host $outData
Write-Host "%%"

I wouldn't say I have never used Write-Host to output text, so I'm not sure why you're getting that error message. Hope this helps.

garyminnick
Tera Contributor

Thanks, I will give that a try.

 

I don't think the Write-Host is causing the issues.  What happens is that because I have data I am outputting along with JSON output the output looks like this.

 

Starting script
{
"car": "1965 Ford Mustang",
"name": "Chad",
"age": 21,
"eye_color": "Brown"
}

 

  And because the "Starting script" line is output with JSON, when ServicNow tries to parse it as JSON it fails.  I was hoping ServiceNow could distinguish the JSON format from other data.

garyminnick
Tera Contributor

I think I got it working.  I had tried something similar to what you suggested but was not sure how to parse it.  I tried it again and this is what I came up with using your suggestion

Execution Command

Write-Host "Starting script"
$myOutput = @{}
$myOutput.name = "Chad" #Hi
$myOutput.age = 21 #oh to be young again
$myOutput.eye_color = "Brown" #sort of
$myOutput.car = "1965 Ford Mustang" #one of my all time favorites

$myData = $myOutput | ConvertTo-Json

Write-Host "%%outputData%%"
Write-Host $myData
Write-Host "%%"

 

Then in Outputs I made a Local variable named JSON (activityLocal.JSON) that pulls from the executionResult.tags["outputData"] source.  Then I make an Output variable named JSON of type Object.  Under that I made a string variable named car and parsed it using source activityLocal.JSON with expression $.car and that created the variable activityOutput.JSON.car.

 

Thanks for pointing me in the right direction.  I was going to make a separate tag for each piece of information but this lets me pass the JSON format.

 

 

Version history
Last update:
‎03-24-2017 10:56 AM
Updated by: