Using the Flow Designer PowerShell Step
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
Hello all,
I have stumbled upon the PowerShell Step in Flow Designer. https://www.servicenow.com/docs/r/yokohama/build-workflows/workflow-studio/powershell-step-action-de... What I am really struggling with is the connection information. I do not need to execute on a particular midserver as far as I know, I just need A server to run the below code.
The below is my powershell script.
param(
[string]$ResponseBody,
[string]$EncryptedSecret,
[string]$ApiSecret = "",
[switch]$SelfTest
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
function Get-OpenSslKeyIvFromPassphrase {
param(
[Parameter(Mandatory = $true)]
[byte[]]$PassphraseBytes,
[Parameter(Mandatory = $true)]
[byte[]]$Salt,
[int]$KeyLengthBytes = 32,
[int]$IvLengthBytes = 16
)
$md5 = [System.Security.Cryptography.MD5]::Create()
try {
$derived = New-Object System.Collections.Generic.List[byte]
$prev = [byte[]]@()
while ($derived.Count -lt ($KeyLengthBytes + $IvLengthBytes)) {
$input = New-Object byte[] ($prev.Length + $PassphraseBytes.Length + $Salt.Length)
[Array]::Copy($prev, 0, $input, 0, $prev.Length)
[Array]::Copy($PassphraseBytes, 0, $input, $prev.Length, $PassphraseBytes.Length)
[Array]::Copy($Salt, 0, $input, $prev.Length + $PassphraseBytes.Length, $Salt.Length)
$prev = $md5.ComputeHash($input)
$derived.AddRange($prev)
}
$all = $derived.ToArray()
$key = New-Object byte[] $KeyLengthBytes
$iv = New-Object byte[] $IvLengthBytes
[Array]::Copy($all, 0, $key, 0, $KeyLengthBytes)
[Array]::Copy($all, $KeyLengthBytes, $iv, 0, $IvLengthBytes)
return @{ Key = $key; IV = $iv }
}
finally {
$md5.Dispose()
}
}
function Decrypt-CryptoJsAesPassphrase {
param(
[Parameter(Mandatory = $true)]
[string]$CipherTextBase64,
[Parameter(Mandatory = $true)]
[string]$Passphrase
)
$raw = [Convert]::FromBase64String($CipherTextBase64)
if ($raw.Length -lt 16) {
throw "Cipher text too short."
}
$header = [System.Text.Encoding]::ASCII.GetString($raw, 0, 8)
if ($header -ne "Salted__") {
throw "Unsupported format. Expected OpenSSL salted format that starts with Salted__."
}
$salt = New-Object byte[] 8
[Array]::Copy($raw, 8, $salt, 0, 8)
$cipherBytes = New-Object byte[] ($raw.Length - 16)
[Array]::Copy($raw, 16, $cipherBytes, 0, $cipherBytes.Length)
$passBytes = [System.Text.Encoding]::UTF8.GetBytes($Passphrase)
$derived = Get-OpenSslKeyIvFromPassphrase -PassphraseBytes $passBytes -Salt $salt
$aes = [System.Security.Cryptography.Aes]::Create()
try {
$aes.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
$aes.Key = $derived.Key
$aes.IV = $derived.IV
$decryptor = $aes.CreateDecryptor()
try {
$plainBytes = $decryptor.TransformFinalBlock($cipherBytes, 0, $cipherBytes.Length)
}
catch [System.Security.Cryptography.CryptographicException] {
throw "Decrypt failed (invalid padding). This usually means the encrypted value and ApiSecret do not match, or the value was not encrypted with CryptoJS passphrase mode."
}
return [System.Text.Encoding]::UTF8.GetString($plainBytes)
}
finally {
$aes.Dispose()
}
}
function Encrypt-CryptoJsAesPassphrase {
param(
[Parameter(Mandatory = $true)]
[string]$PlainText,
[Parameter(Mandatory = $true)]
[string]$Passphrase
)
$salt = New-Object byte[] 8
[System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($salt)
$passBytes = [System.Text.Encoding]::UTF8.GetBytes($Passphrase)
$derived = Get-OpenSslKeyIvFromPassphrase -PassphraseBytes $passBytes -Salt $salt
$aes = [System.Security.Cryptography.Aes]::Create()
try {
$aes.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
$aes.Key = $derived.Key
$aes.IV = $derived.IV
$encryptor = $aes.CreateEncryptor()
$plainBytes = [System.Text.Encoding]::UTF8.GetBytes($PlainText)
$cipherBytes = $encryptor.TransformFinalBlock($plainBytes, 0, $plainBytes.Length)
$prefix = [System.Text.Encoding]::ASCII.GetBytes("Salted__")
$combined = New-Object byte[] ($prefix.Length + $salt.Length + $cipherBytes.Length)
[Array]::Copy($prefix, 0, $combined, 0, $prefix.Length)
[Array]::Copy($salt, 0, $combined, $prefix.Length, $salt.Length)
[Array]::Copy($cipherBytes, 0, $combined, $prefix.Length + $salt.Length, $cipherBytes.Length)
return [Convert]::ToBase64String($combined)
}
finally {
$aes.Dispose()
}
}
if ($SelfTest) {
$expected = "my-test-secret"
$encrypted = Encrypt-CryptoJsAesPassphrase -PlainText $expected -Passphrase $ApiSecret
$response = @{ encryptedSecret = $encrypted } | ConvertTo-Json -Compress
$jsonData = $response | ConvertFrom-Json
$newencryptedSecret = $jsonData.encryptedSecret
$newSecret = Decrypt-CryptoJsAesPassphrase -CipherTextBase64 $newencryptedSecret -Passphrase $ApiSecret
if ($newSecret -ne $expected) {
throw "Self-test failed: decrypted value does not match expected."
}
$result = @{ decryptedSecret = $newSecret; message = "Self-test passed." } | ConvertTo-Json -Compress
Write-Host $result
return
}
if ([string]::IsNullOrWhiteSpace($EncryptedSecret)) {
if ([string]::IsNullOrWhiteSpace($ResponseBody)) {
throw "Provide -EncryptedSecret directly, -ResponseBody with JSON containing encryptedSecret, or run with -SelfTest."
}
$jsonData = $ResponseBody | ConvertFrom-Json
$newencryptedSecret = $jsonData.encryptedSecret
}
else {
$newencryptedSecret = $EncryptedSecret
}
$newSecret = Decrypt-CryptoJsAesPassphrase -CipherTextBase64 $newencryptedSecret -Passphrase $ApiSecret
$result = @{ decryptedSecret = $newSecret } | ConvertTo-Json -Compress
Write-Host $result
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2 weeks ago
@lonesoac01 Yes, you need a MID Server. Use any suitable Windows MID Server as the execution host, secure the secret in credentials, and avoid logging decrypted values.
The PowerShell step in Flow Designer does not run directly on the ServiceNow instance. It runs through a MID Server, so you need a Windows MID Server available to execute the script.
You do not need a specific target server unless the script must connect to one. In your case, since the script is only doing local encryption/decryption logic, any healthy Windows MID Server with PowerShell support should be enough.
Key points:
- Configure a Connection & Credential Alias for the PowerShell step.
- Select a Windows MID Server or MID Server capability that can execute PowerShell.
- Ensure the MID Server service account has permission to run PowerShell.
- Store
ApiSecretsecurely as a credential or flow input, not hardcoded. - Pass
ResponseBody,EncryptedSecret, andApiSecretas step inputs.
If you only need computation/decryption and no remote server interaction, the MID Server acts as the execution host.
Also, be careful returning decrypted secrets back into Flow outputs/logs, because Flow Designer execution logs may expose sensitive values.
✅ Issue resolved? → Mark as Correct
Found value? → Mark as Helpful
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2 weeks ago
Hi @lonesoac01
Refer:
https://www.youtube.com/watch?v=fuJc__pvVxQ
https://www.youtube.com/watch?v=ggdCADJlcF4
Regards
Tanushree Maiti
ServiceNow Technical Architect
LinkedIn: https://www.linkedin.com/in/tanushreemaiti