Automation–Orchestrator Integration Pack for PowerShell Script Execution–Version 1.2!

Automation–Orchestrator Integration Pack for PowerShell Script Execution–Version 1.2!

  • Comments 16
  • Likes

Hello Readers/Viewers!

Remember back in January of this year when I published the Automation–Orchestrator Integration Pack for PowerShell Script Execution post over here on the Building Clouds Blog? It was a re-introduction of the content I originally posted many moons ago on my old Blog D’Joy TechNet Blog (I will not expect you to remember that far back!) ;)

Either way, an update to this Integration Pack has been a long time in the making. In fact when I posted about it earlier this year, I had some really great feedback (thank you Greg Bray!) on how to improve and add some really great functionality to something that has already been installed many, many times. I have now taken that feedback, plus one additional “feature” and am proud to release the Orchestrator Integration Pack for PowerShell Script Execution 1.2!

So, this blog post will be a short recap of what is already in the updated documentation (available in the new download) – but first…


…the Download!

The download includes the following (2) files:

  • ExecutePS_1.2.oip (System Center 2012 SP1 – Orchestrator Integration Pack)
  • Integration Pack for PowerShell Script Execution 1.2 - User Guide.docx (updated documentation)

Download the Orchestrator Integration Pack for PowerShell Script Execution 1.2 from TechNet Gallery here:

BC-DLButtonDark


What’s New in Version 1.2?

The following list outlines the three main updates for version 1.2 of the Orchestrator Integration Pack for PowerShell Script Execution.

  1. New IP Connection - Authentication Method - CredSSP
    For more information about CredSSP, please review the following:
  2. New IP Global Connection / Activity Functionality - Get Host Name from Activity
    This requirement came directly from comments/suggestions in the original blog post here: Automation–Orchestrator Integration Pack for PowerShell Script Execution

    IMPORTANT: Because the existing Global Configuration field for “Host Name” changed to “Host Name from Global Config”, existing configurations will need to be updated before their respective activities will function as expected.

  3. New IP Activity Execution Option - Execute Asynchronously
    While investigating Timeout Configuration for the IP, I came across yet another option for the execution of scripts within the runspace(s) created during exection. This option is now offered during design time (default is set to “False”, which imitates existing functionality pre-option). The options pertain to the following Methods:

NOTE: Each of the new features/enhancements are detailed within the updated documentation available in the new download.


System Requirements

  • System Center 2012 Orchestrator (SP1+)
  • System Center 2012 Orchestrator Integration Toolkit (SP1)
  • Microsoft .NET 3.0 Framework
  • PowerShell 2.0+
  • winrm quickconfig command executed on local and target machines where PS Scripts will be executed
  • Enable-WSManCredSSP for Client and Server roles as needed if CredSSP functionality is desired

Upgrading (from Version 1.1)

Via the Orchestrator Deployment Manager…

  1. Uninstall the existing Integration Pack (version 1.1) from any and all machines where it has been installed (both Runbook Designer and Runbook Server machines)
  2. Unregister the existing Integration Pack (version 1.1)
  3. Register the new Integration Pack (version 1.2 - ExecutePS_1.2.oip)
  4. Deploy/Install the new Integration Pack (version 1.2 - ExecutePS_1.2.oip) to any and all machines where it is needed (both Runbook Designer and Runbook Server machines)

Pre-System Center 2012 SP1 – Orchestrator Notes

As you likely know, a new version of the Orchestrator Integration Toolkit (OIT) shipped with SP1. This new Integration Pack was created with this new OIT, and likely will not be compatible with older versions of Orchestrator (due to Microsoft.SystemCenter.Orchestrator.Integration.dll changes).

If you will not be installing/using System Center 2012 SP1 Orchestrator and would like an older copy of the DLL for this IP that will work for older deployments, please find it here: http://sdrv.ms/10dEvfQ and reference the comments in the original blog post here: Automation–Orchestrator Integration Pack for PowerShell Script Execution


That’s it - thanks for checking it out!

And for more information, tips/tricks, and example solutions for Orchestrator, be sure to watch for future blog posts in the Automation Track!

enJOY!


Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • very nice, can't wait to try it out!

  • Awesome! Keep up the great work!

  • Does this IP solve any of the issues with running Powershell 3.0 + cmdlets in Orchestrator?  I am struggling to get Azure Powershell cmdlets to work correctly in Orchestrator through the "Run .Net Script" activity.  The Azure IP doesn't provide doesn't provide the control that I need.  

    I don't really understand what problem the "ExecutePS_1.2 IP solves.

  • @Andy - This release was about a couple things. First, it was a set of updates requested in the previous version (see comments from here: blogs.technet.com/.../automation-orchestrator-integration-pack-for-powershell-script-execution.aspx). Second, it was an update to System Center 2012 Orchestrator SP1+.

    Now, to the question of whether it allows for PS 3.0+ functionality - I just tested (verified) that against a host (as this IP is all about PS Remoting) with PS 3.0 installed, it will execute PS Workflows. I believe (though I wasn't using/testing PS Workflows back then) the older version allowed for this type of functionality. This is how it was able to get around the 32-bit/64-bit issues.

    I hope this helps.

    -Charles

  • Charles,

     I have had GREAT experiences with this OIP. Thank you VERY much!

     However, I am experiencing an issue where the Activity is returning success (When is should be returning warning/fail) and it is passing no results downstream to activities connected with an arrow. I have tried many different variations of settings and have had no luck. I set a Platform Notification to subscribe to Activity Status, Results, Results with Write-host and only the status is coming through in the notification.

  • @Dave - Thanks for your kind words! :)

    The issue may be that the activity is actually "completing", failure or not.

    Best option with this IP is to leverage $error (just put it at the end of the script). Then you can evaluate based on anything in there that may actually be causing the failure. Are you leveraging any try...catch...throw logic?

    Either way, first step is to see what is wrong, use $error to dig a bit deeper, and hopefully it will be easy to move forward.

    -Charles

  • Charles,

    Here is the PS code:

    [string]$pass='\`d.T.~Ed/{73A5A849-CCA6-405A-8D80-AD499E05644C}.SendOpalisEvent.Summary\`d.T.~Ed/'

    [string]$errorstring="";

    [bool]$badpass=$false;

    [bool]$check=$false;

    If ($pass.length -lt 8)

     {

      $errorstring+="Password is not long enough. ";

      $badpass=$true

      }

    $check=$pass -match "[0-9]";

    if ($check -ne $true)

     {

      $errorstring+="Password does not contain a number. ";

      $badpass=$true

      }

    $check=$pass -match "[a-z]";

    if ($check -ne $true)

     {

      $errorstring+="Password does not contain a lower case letter. ";

      $badpass=$true

      }

    $check=$pass -match "[A-Z]";

    if ($check -ne $true)

     {

      $errorstring+="Password does not contain a upper case letter. ";

      $badpass=$true

      }

    $check=$pass -match "[\^\x20_\!\#\$\&\(\)\*\,\.\/\:\?\@\\\{\}\'\-\+\=]";

    if ($check -ne $true)

     {

      $errorstring+="Password does not contain a special character. ";

      $badpass=$true

      }

    if ($badpass -eq $true)

      {

      $errorstring+="`nError Loge:`n";

      $errorstring+=$error | out-string;

      write-host ("Error: $errorstring");

      write-error ("Error: $errorstring") -erroraction stop

      } else

      {

      $errorstring="Password is Valid";

      write-host("Status: $errorstring");

      return $errorstring

      }

    Right now the data being fed too it upstream is "1234567" which should trigger the write-error sequence.

    I am subscribing to Results, Results with Write-host, Data Output and count and all come back blank. Activity Status comes back as success, but no other published data is coming through.

    Any ideas?

    Dave M

  • @Dave - I did a bit of digging...

    If you take out this line:

    $check=$pass -match "[\^\x20_\!\#\$\&\(\)\*\,\.\/\:\?\@\\\{\}\'\-\+\=]";

    It works as you would expect...

    I then did more digging (wanting to know which character kills output for my IP). I tested and it looks like it is the single quote that causes the problem.

    Use this line instead:

    $check=$pass -match "[\^\x20_\!\#\$\&\(\)\*\,\.\/\:\?\@\\\{\}\-\+\=]";

    it should work as expected.

    The only problem is, if the password contains a " ' ", then it fails password validation, as it is not in the checked list. I am not sure how big of an issue that is, but if you avoid usage of " ' ", probably all the better. Unless you can find a way to successfully escape that character from within the IP. I do not have any more time to test... let me know what you find.

    Good luck, and have a great weekend!

    -Charles

  • @Charles

    You are a GENIUS!

    BTW, 0x27 works in its place.

    Thanks again for making this and thank you so much for fixing this issue.

    Dave M

  • @Charles

     Sorry, ran into another snag and I can't make heads or tails of it.

    Here is the code:

    function Send-JTCPRequest{

    [CmdletBinding()]

    param(

    [String]

    $ComputerName,

    [switch]

    $Test,

    [int]

    $Port=80,

    [switch]

    $UseSSL,

    [string]

    $InputObject,

    [int]

    $Delay=100

    )

    Set-StrictMode -Version Latest

    [string]$SCRIPT:output=$null

    $currentInput=$inputObject

    if(-not $currentInput)

    {$currentInput=@($input)}

    $scriptedMode=([bool]$currentInput) -or $test

    function Main

    {

    if(-not$scriptedMode)

    {write-host "Connecting to $computerName on port $port"}

    try

    {$socket=New-Object Net.Sockets.TcpClient($computerName,$port)}

    catch

    {if($test){$false} else{Write-Error "Could not connect to remote computer:$_"}

    return

    }

    if($test) {$true;return}

    if(-not $scriptedMode) {write-host "Connected. Press ^D followed by [ENTER] to exit.`n"}

    $stream=$socket.GetStream()

    if($UseSSL)

    {

    $sslStream=New-Object System.Net.Security.SslStream $stream,$false

    $sslStream.AuthenticateAsClient($computerName)

    $stream=$sslStream

    }

    $writer=new-object System.IO.StreamWriter $stream

    while($true)

    {

    $SCRIPT:output+=GetOutput

    if($scriptedMode)

    {

    foreach($line in $currentInput)

    {

    $writer.WriteLine($line)

    $writer.Flush()

    Start-Sleep -m $Delay

    $SCRIPT:output+=GetOutput

    }

    break

    }

    else

    {

    if($output)

    {

    foreach($line in $output.Split("`n"))

    {

    write-host $line

    }

    $SCRIPT:output=$null

    }

    $command=read-host

    if($command -eq ([char]4)) {break;}

    $writer.WriteLine($command)

    $writer.Flush()

    }

    }

    $writer.Close()

    $stream.Close()

    if($scriptedMode) {$output}

    }

    function GetOutput

    {

    $buffer=new-object System.Byte[] 1024

    $encoding=new-object System.Text.AsciiEncoding

    $outputBuffer=$null

    $foundMore=$false

    do

    {

    start-sleep -s 1

    $foundmore=$false

    $stream.ReadTimeout=1000

    do

    {

    try

    {

    $read=$stream.Read($buffer,0,1024)

    if($read -gt 0)

    {

    $foundmore=$true

    $outputBuffer+=($encoding.GetString($buffer,0,$read))

    }

    } catch {$foundMore=$false;$read=0}

    } while($read -gt 0)

    } while($foundmore)

    $outputBuffer

    }

    . Main

    }

    $httpGET="HEAD / HTTP/1.1`nAccept: */*`nAccept-Language: en-us`nUser-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729)`nAccept-Encoding: gzip,deflate`nHost: kdc.uas.aol.com`nConnection: Keep-Alive`n`n`n"

    $httpReturn=Send-JTCPRequest -ComputerName kdc.uas.aol.com -Port 443 -UseSSL -InputObject $httpGet

    $success=$?

    if ($success -eq $true) {write-host($httpReturn)}

    else {$errorstring=$error | out-string

    write-host($errorstring)

    write-error($errorstring)}

     It works if I do it from the powershell console on the same machine it executes from. And works from a remote session into the machine the OIP is requesting.

     The OIP is doing the same thing where it always succeeds, but produces no output. any ideas?

  • Found another issue. It reports success, but returns no results: function Send-JTCPRequest { param( [String] $ComputerName, [switch] $Test, [int] $Port=80, [switch] $UseSSL, [string] $InputObject, [int] $Delay=100 ) Set-StrictMode -Version Latest [string]$SCRIPT:output=$null $currentInput=$inputObject if(-not $currentInput) {$currentInput=@($input)} $scriptedMode=([bool]$currentInput) -or $test function Main { if(-not $scriptedMode) {write-host "Connecting to $computerName on port $port"} try {$socket=New-Object Net.Sockets.TcpClient($computerName, $port)} catch {if($test) { $false } else {Write-Error "Could not connect to remote computer: $_"} return } if($test) {$true; return} if(-not $scriptedMode) {write-host "Connected. Press ^D followed by [ENTER] to exit.`n"} $stream=$socket.GetStream() if($UseSSL) { $sslStream=New-Object System.Net.Security.SslStream $stream,$false $sslStream.AuthenticateAsClient($computerName) $stream=$sslStream } $writer=new-object System.IO.StreamWriter $stream while($true) { $SCRIPT:output +=GetOutput if($scriptedMode) { foreach($line in $currentInput) { $writer.WriteLine($line) $writer.Flush() Start-Sleep -m $Delay $SCRIPT:output +=GetOutput } break } else { if($output) { foreach($line in $output.Split("`n")) { write-host $line } $SCRIPT:output=$null } $command=read-host if($command -eq ([char] 4)) {break;} $writer.WriteLine($command) $writer.Flush() } } $writer.Close() $stream.Close() if($scriptedMode) {$output} } function GetOutput { $buffer=new-object System.Byte[] 1024 $encoding=new-object System.Text.AsciiEncoding $outputBuffer=$null $foundMore=$false do { start-sleep -s 1 $foundmore=$false $stream.ReadTimeout=1000 do { try { $read=$stream.Read($buffer, 0, 1024) if($read -gt 0) { $foundmore=$true $outputBuffer +=($encoding.GetString($buffer, 0, $read)) } } catch {$foundMore=$false; $read=0} } while($read -gt 0) } while($foundmore) $outputBuffer } . Main } $httpGET="HEAD / HTTP/1.1`nAccept: */*`nAccept-Language: en-us`nUser-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729)`nAccept-Encoding: gzip, deflate`nHost: kdc.uas.aol.com`nConnection: Keep-Alive`n`n`n" $httpReturn=Send-JTCPRequest -ComputerName kdc.uas.aol.com -Port 443 -UseSSL -InputObject $httpGet $success=$? if ($success -eq $true) {write-host($httpReturn)} else { $errorstring=$error | out-string write-host($errorstring) write-error($errorstring) }

  • @DaveM - Unfortunately all my Orchestrator instances are on machines which are down for maintenance at the moment. I did take some time to look at the PowerShell you provided and found nothing that would indicate why the activity would not produce data. Is there a reason you are using the ExecutePS IP activity for this specific script? Does it need to run remotely? If not, it looks like this script can be easily executed from the out-of-the-box Run .Net Script activity. At the very least, it is worth a try to see if anything else comes up. I also see that you are doing a if/else for success/failure. I would still put $error at the very end to see what might be wrong with the script inside the IP. BTW - The Write-Host functionality was really in there for folks who had existing scripts with Write-Host commands…I wouldn’t necessarily leverage it for new scripts. The IP does just fine outputting without Write-Host, for example, executing Get-Process will produce results without any extra effort. It may be worth attempting the script without the Write-* calls. From there, the troubleshooting for things like this is really about taking it back to a state where you know it was working. There is quite a bit of complexity (loops, conditions, etc.) in the script, it is hard to pinpoint where the IP activity may be failing...as this is likely not a PowerShell specific issue - more a PowerShell + Orchestrator + this IP issue. Either way, once my test environment is out of maintenance, I will attempt the script to see what I can see. I will report back once I know more. -Charles

  • Hi Charles, Thanks for the contribution. I have not been able to run the Execute PS Script (Global or non-Global) from the Runbook server against a remote machine without powershell installed. Typically we would use a gwmi command like this: $computer="server123" $processes = gwmi -Class win32_process -computername $computer | select name This works in Powershell ISE, but fails to return any results using the Powershell IP in Orchestrator. In the Runbook tester we see "PS Execution 01 Result Count" = 0 I'm sure this must be something simple. Any ideas? Thanks, Sean

  • @Sean - The only thing I can think of is that the commands are not actually executing. The IP relies 100% on PowerShell Remoting. Have you attempted to connect to the remote machine (that has not PS installed) via ISE, using "New Remote PowerShell Tab..." (Ctrl+Shift+R) - I am not even sure it would work against machines without PS installed. Your commands may simply be remote WMI commands? Either way, I never tested this IP against remote machines without PS installed. That said, you can put a $Error at the end of the script you are testing, to see if you get any more information from the Error Stream. In any case, if you want to run remote WMI commands, you may want to check out this post: http://blogs.technet.com/b/privatecloud/archive/2013/01/24/automation-orchestrator-integration-pack-for-windows-tasks.aspx

  • Thanks for this great plugin. Works like a charm.

    There's one thing I would like to do, that I believe this IP will not allow. To get variables back from the remote executed script, so you can base further actions based on this. I can add variables TO the scripts, but not retrieve anything based on the execution of the script. I do not know if this is possible at all, as it's not executed on the local machine, but it would certainly be a very handy function.

    For the normal "Run .Net Script", you have the Published Data options. If this was added to your IP, all sorts of stuff could be possible. But as I said, I have little knowledge of how the remote execution works, so this might be entirely impossible?

    Any of you have any idea of how this could be done? Is there some function in the IP, that I'm not aware of, or are there other ways of doing this?