A couple of weeks ago, Karl Prosser posted an interesting article on using PowerShell v3 with Orchestrator.And, while at MMS last week, I had an opportunity to sit down and run through one of the PowerShell v3 hands-on labs that were available. In that lab, I found out about the new capabilities around remoting and sessions that I thought would be really useful for Orchestrator runbooks.

The issue right now with running PowerShell in the Run .NET Script activity is that every time the activity runs, it creates a PowerShell runspace, runs the script (and creates / destroys a remoting session if you use one), and then closes the runspace. There isn’t any kind of runspace (let alone pipeline) spanning across multiple activities. This means you can’t pass PowerShell objects from one activity to the next and everything has to be returned to published data as strings. The PowerShell IP available on the Orchestrator CodePlex site addresses this issue with PowerShell 2.0 by creating a WCF service that runs in the background to maintain the session across multiple activities, and you just have a “Start Session” and “End Session” activity to manage the session. The only problem is that you now have to have this service always running in the background.

We get around this issue in the VMM and DPM Integration packs by having the runbook thread maintain runspace state across multiple activities, but that also has its limitations in that every time you branch from an activity (you have multiple outgoing links), the current thread stops and a new thread for each link starts up. So, even in the case of our own activities, we have to deal with having to recreate runspaces a lot.

The cool thing about PowerShell v3 is that we can now accomplish reusing runspaces and sessions natively in PowerShell without having to create and run a service. In PS v3, you can create a session, then disconnect and reconnect to it any number of times, and the remote machine maintains the runspace for you and can buffer any output that happens between connections. In this example, I’m going to show how to create and re-use a session across multiple activities using this process. First of all, here’s the sample runbook:

image

I don’t have to use a separate activity for creating or closing sessions, I’m just using it as an example. In fact, I don’t have to close a session at all. It will eventually time out if not used, but that’s not a good way to do things – you don’t want to leave sessions open when you don’t need them anymore because until they time out, they’re using up the session quota on the remote machine. Always be a “good citizen” and do your own cleanup.

Here are the contents of each Run .NET Script Activity:

Create Session

$retval = PowerShell {
$session = New-PSSession –ComputerName "{ServerName}" -Name "{RunbookID from “Initialize Data"}"
Get-PSSession
$null = Disconnect-PSSession -Name "{RunbookID from “Initialize Data"}"
}
$retval

Set Variable

$retval = PowerShell {
$session = Connect-PSSession –ComputerName "{ServerName}" -Name "{RunbookID from “Initialize Data"}"
Invoke-Command –Session $session –ScriptBlock {$var1 = “foo”; $var1}
$null = Disconnect-PSSession -Name "{RunbookID from “Initialize Data"}"
}
$retval

Get Variable

$retval = PowerShell {
$session = Connect-PSSession –ComputerName "{ServerName}" -Name "{RunbookID from “Initialize Data"}"
Invoke-Command –Session $session –ScriptBlock {$var1}
$null = Disconnect-PSSession -Name "{RunbookID from “Initialize Data"}"
}
$retval

Close Session

$retval = PowerShell {
$null = Remove-PSSession -Name "{RunbookID from “Initialize Data"}"
Get-PSSession

}
$retval

I also create a published data property on each activity called “Output” that’s linked to the $retval variable.

Here’s what I expect to happen:

  1. Create Session runs, “Output” contains “[PSSession]2860”. (since the session is an object, it returns what string representation it can).
  2. Set Variable Runs. “Output” contains “foo” (since I set the variable and then output it to the pipeline)
  3. Get Variable Runs. “Output” contains “foo” (showing that the variable is retained across the disconnected session)
  4. Close Session runs. “Output” contains nothing (the session should be closed).

Implementing this on your own

I wouldn’t expect to implement this process exactly in this way by replicating the script across activities like this. It’s a maintenance nightmare that way. If I wanted to make a change, I’d have to change every activity. It would be better to write a script that contained all of the necessary logic and simply call the script with parameters. You could then have parameter validation, good error handling, automatic setup of the sessions, and so on. I will work on an example of that method and post it soon. Until then, go download the PowerShell v3 beta and get started!