- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
on ‎03-24-2017 10:56 AM
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:
- Create a PowerShell script
- Create a custom activity using the Activity Designer
- 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.
-
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
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>
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.
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.
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.
When you run this workflow, assuming it is successful, hover over the activity you created to see the Databus output:
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:
So, there you have it. Passing an object from PowerShell to the workflow, then parsing the data.
- 8,621 Views
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
I was searching for a resource like this. Very useful! Thank You...
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Very useful!!!
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Chad - This is a very useful share. Thank you for the detailed steps.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Very helpful, thank you
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
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
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
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'
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
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!!
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
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.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
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.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
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.