PowerShell Utility V2 - execute Powershell scripts directly from your instance

conmic
Mega Guru

Introduction

So I was working on a new, supposedly simple challenge: Grab Lenovo Warranty Information to update the CMDB warranty expiration. Unfortunately Lenovo doesn't provide a web service API, so I had to use a workaround via Powershell.

Now I was already confronted a while back with such a challenge and I solved it by executing a workflow and running the Powershell script from there. I did something similar with the challenge above; I created a UI action script that started a specified workflow on the CI. The workflow executes the Powershell script and updates the said CI.

But as I have a bit more experience now, I was asking myself if it wouldn't be possible to run a Powershell script directly from your instance, via script... running REST or SOAP messages via script is also possible, so why couldn't I find anything about Powershell? I can only guess the answer, but I think it's because you're tied to a MID server and perhaps there is a good reason why ServiceNow doesn't want to make these functionalities accessible outside the workflow environment.

Luckily I found the following article from John J. Andersen, who was probably confronted with the same struggles. He did a really great job, even with an UI Interface and everything you need: PowerShell Probe and Utility for ServiceNow-John Andersen

Unfortunately his script is pretty outdated... It is still using package calls and is not supporting the Eureka features like executing a MID Server Script File....

So I decided to update his work and here we go!

Pre-Requisites

They are still the same as described by John:

You must have a MID Server installed on a Microsoft Windows machine with PowerShell v. 2.0 setup. Also, if you have Enhanced Windows Security enabled, you must unblock the Powershell modules in the MID Server. See this link: Unblocking the MID Server Powershell Modules

You must also set "Powershell" as a capability on the MID Server.

For remote powershell execution (executing powershell scripts on a Windows computer that is NOT the one hosting the MID Server) you will need to have the Runbook Automation product from ServiceNow and set up the credentials for the remote device.

 

Additionally:

I did update the provided records of John J Andersen. If you are already using his update set, then any of your personal changes will be overwritten.

Make sure that the script files you want to execute are properly synchronized to the MID server.

PowershellProbe Library

Some public functions have been updated, but most of them remain the same. There has only been a noticable change on the Class Constructor (a new variable has been added) and the function "setScript(script)". Additionally a new public function has been introduced. I have highlighted the important changes in red.

The Update Set provided here will create a Script Include called "PowershellProbe". This library allows you to quickly and easily generate PowerShell commands through the MID Server.

PowerShellProbe( midserver, psServer ,midScriptfileSysId)
The Class Constructor

  • midserver (optional) — The name of the MID Server that will process the command
  • psServer (optional) — The IP Address of the computer that the Powershell Script will execute against. The localhost ip address (127.0.0.1) indicates that the Powershell script will run on the same machine as the MID Server. If you have Runbook Automation enabled on your instance, you can execute the powershell script on a remote computer. The remote computer must be a Windows devices in the domain that trusts the Windows box hosting the MID Server. Runbook Automation allows you to store Windows Credentials that can be used to authenticate against the remote machine to execute the desired script.
  • midScriptfileSysId (optional) — The sys_id of the script file from the table ecc_agent_script_file   that should be executed. If you don't specify this variable you need to provide a Powershell script with the function "setScript(script)".

setPSServer( psServer )
Sets the PowerShell device IP Address. This is typically used if you did not specify the address in the constructor when you instantiated the class.

  • psServer — The IP Address to the windows device that will execute the Powershell Script

setMidServer( midserver )
Sets the name of the MID Server that will process the Powershell Request. This method is typically used if you do not specify the MID Server in the constructor when you instantiated the class.

  • midserver — Name of the MID Server (eg. WinMid1)

setMidScript( midServer )
Sets the sys_id of the MID Script File that should be executed. This method is typically used if you do not specify the MID Script File in the constructor when you instantiated the class.

  • midScript — Sys_id of the MID Script File from the table ecc_agent_script_file

setScript( script )
Stores the PowerShell script that will be executed remotel. OR if a script file is specified it stores the additional parameters in a JSON format, similar to the "Run Powershell" activity on a workflow.

  • script — The script or json-parameters string

setMaxWait( seconds )
Set the maximum number of seconds that you will wait for a response from the MID Server on this request before you move on. If you don't call this method, the default max wait time is 60 seconds.

  • seconds — Maximum number of seconds to wait for a response from the MID Server on this request (if you choose to wait at all).

execute( waitForResponse )
Sends the request to the ECC Queue for processing. If you choose to wait for the reponse, the method will return an object that contains an "output" variable and and "error" variable. The output variable will contain the text from the Stdout buffer. The error variable will contain the text from the StdErr buffer.

  • waitForResponse (boolean) — Optional. The value of true will hold the script until the MID Server has responded, or until the maxWait period has expired.
 

Code Example

Here is a snippet of code that we can use to test our setup:

 

var pb = new PowershellProbe("EC2WINMID1", "127.0.0.1",""); //midScript is an empty string

var script = "$myVarName = 'John Andersen'\n" + "Write-Host $myVarName\n";

pb.setScript(script);

var response = pb.execute(true);

gs.log("OUTPUT: " + response.output);

gs.log("ERROR: " + response.error);

 

When executed, we get the following response:

*** Script: OUTPUT: John Andersen

*** Script: ERROR: null

 

And if you want to use a Script File from the "ecc_agent_script_file" table:

var pb = new PowershellProbe("EC2WINMID1", "127.0.0.1","964e71ca6f620a00c1587afede3ee422"); //PowershellUtility-DemoScript.ps1

var script = "{\"mandatorytext\":\"mandatory Hello World\",\"optionaltext\":\"optional Hello World\"}"

pb.setScript(script);

var response = pb.execute(true);

gs.log("OUTPUT: " + response.output);

gs.log("ERROR: " + response.error);

 

When executed, we get the following response:

*** Script: OUTPUT: mandatory Hello World optional Hello World

*** Script: ERROR: null

The Powershell Utility

Sometimes we need to test out our PowerShell scripts before we actually put them into code. Additionally, it is often common that the person developing the ServiceNow scripts does not have easy access to the Windows device that will be executing the commands. This update set provides a GUI Utility that allows you to experiment with Powershell scripts against the target machine from within your ServiceNow instance.

To get to the utility, simply browse to: "MID Server->PowerShell Utility".

 

Capture_psutility2.PNG

Once you get there, you will be present with the GUI PowerShell utility. Enter in a valid, running, MID Server. Then type in the remote Windows device IP Address that will execute your PowerShell script. The IP Address of 127.0.0.1 tells the MID Server to execute the script on the same box that is hosting the MID Server.

 

This first example shows how to execute a PowerShell script

Capture_psutility_exec1.png

This second example shows how to execute the demo MID Script file with the paramets

Capture_psutility_exec2.png

Once you click the "Submit" button. The utility will wait for the response to complete and then it will pop up a dialog box with the result and any errors.

Capture_psutility_resp.PNG

The default Max Wait time for the utility remains at the default time for the PowershellProbe library. However, you can change the default max wait time by setting the following System Property: com.snc.integration.powershellprobe.maxWaitTime

Provide an integer value that represents the maximum number of seconds that the probe will wait for a response from the MID Server.

 

Message was edited by: Michel Conter - v2.1 has been published with a bug fix: -->In some cases the PowerShell Utility UI did not show the returned error message from the script that was send to the MID server. The UI only showed the black dialog box with nothing in or appending it.

Message was edited by: Michel Conter - v2.1 was published, see my comment below for details

Message was edited by: Michel Conter - V2.2 has a little bug fix to support Geneva, otherwise you might get the error message: "null is not recognized as an internal or external command,operable program or batch file"

44 REPLIES 44

Can you please describe what you're trying to do? Do use use a MID Server script or are you just trying to pass the script directly through the script field?



It seems I forgot to mention how to troubleshoot your script output in case of failure, I have to update the article or even the script:




Navigate to the ECC queue (ECC -> Queue) and search the INPUT queue record for the command that you passed. The topic should be "Powershell" and there should also be an OUTPUT queue record for when you send the command to the MID server.



Now in the INPUT ECC record you should find an XML payload. If there was no error while processing your script it should return an "output" parameter which one should have been displayed in the black dialog window.



However if the XML payload of your INPUT ECC record has an "error" parameter instead of the "output" parameter, it means that something went wrong while processing your powershell script. Just read the message that comes along with the "error" parameter. [I will check if I can correct the black output window to also display error messages in order to simplify this.]



My educated guesses on what's wrong:


As you're using a MID server to execute your script on a remote computer it might be that both computers (MID server and remote server) are not trusted, especially when they are not in the same domain and/or forest.



Some commands such as "invoke-command" cannot be passed through the MID server. To keep it simple: the script you're sending to the MID server gets basically already invoked aka remote executed.


here is the simple test script which works fine from the mid server and I get the expected output



$pass = get-content D:\pwd.txt | convertto-securestring


$credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist "myazureaccount",$pass


Connect-MsolService -Credential $credentials


Get-MsolUser -UserPrincipalName testuserabc



I hope to execute the same script from ecc   input message and get an output message with xml



a more simple test for 'dir' command from powershell utility gives me listing from "C:\ServiceNow\agent" on my midserver


Have you checked what error message is returned? As explained: check the ECC queue an tell me what error you get.


conmic
Mega Guru

I published Version 2.1. Please find it attached to the original post.



Bug fix


In some cases the PowerShell Utility UI did not show the returned error message from the script that was send to the MID server. The UI only showed the black dialog box with nothing in or appending it.



Big thanks to Slava, without him I would have been stuck on this bug.


icreate
Kilo Contributor

Hi Michel,



I am using orchestration AD workflow and using "Run Powershell" activity to execute my powershell commands.


I am in need to get a response back from powershell code (like if else statements) and manage my further flow based on the output returned.



I am executing the query but i am not receiving any response back on using the write-host commands.



Can you suggest a way forward to achieve this ?



Thanks,
Ishan Parikh