If you’re reading this, chances are you’ve probably read about the ways of putting scripts in the Content Editor ribbon or Context Menu. Those are some simple and quick ways of extending the Sitecore UI to do quick actions accessible for your users without them having to even know about the existence of PowerShell in your system. Up until now however we’ve not been very vocal about the fact that those does not really have to be quick one-off actions but they can indeed form a broader solution to your problem through the use of persistent, named sessions. In fact Sitecore PowerShell Extensions (SPE) allow you to manage sessions and decide that it should stay in memory after the script have executed. In fact SPE does quite a bit of session maintenance itself that you might want to be aware of.
What do I really need to know about script sessions?
ScriptSession is an object that encapsulates a PowerShell Runspace. Whenever you decide to run a script 2 things will happen:
- a ScriptSession is requested from the SessionManager (which either creates a new session or recovers an existing named session)
- after which it’s being used to execute your script in either the current thread or a new Sitecore Job is being instantiated and the Script session is passed to it for execution.
This is decided internally based on what you’re using a Session for unless you’re instantiating it directly (like described in this post) in which case you’re responsible for disposing it.
After the script is executed and the Job has ended the session is discarded unless your script has a Persistent Session ID which I will show you how to define in just a moment.
Great so there are sessions… but what are they good for?
Let’s see how this works based on 2 scripts I’ve added to SPE some time ago that allow you to copy Layout data from one item to another. You can find those scripts in the Content Editor/Context Menu/Layout/ library:
If you open the Copy Renderings script you can see that it’s extremely simple and it’s not quite apparent what it does on its own until you understand that it’s a part of a bigger solution that spans across 2 scripts. I’ve added some comments to make it more understandable for the purpose of this post:
#get the item for which the script was executed $sourceItem = get-item . #assign rendering to a variable - we will need it in the other script $renderings = $sourceItem.__Renderings; #remember the path of this item just for reporting purposes in the second script $sourceName = $sourceItem.ProviderPath; #write a status to the script output that we've copied the layout write-host "Rendering copied from $($sourceName)"
Now this script does nothing other than copy the layout information from the current item into a $renderings variable. The secret sauce is in the script settings. If you open the runtime settings of the script:
You will see that the script has a Persistent Session ID set on it. Which make the session that’s running it stay resident upon script termination:
Another cool thing that I wanted you to notice in the above screenshot is the Enable rules field which (in this case) will show the script as disabled if the item you’ve tried to execute it for has no layout. This setting is available for both scripts and script library items (that contain other scripts). So the following can be result of properly using those:
While Enable rules field allows you to disable a menu item the Show rules field allows you to hide them altogether to avoid clutter in the Scripts context menu if you’re having a lot of them.
The above setting of the Persistent Session ID will cause the PowerShell Runspace to be kept for future reuse whenever a script with the same Persistent Session ID will be executed. Such consecutive script will have access to all the previously set variables. Let’s look at the Paste renderings script then to see how this would be used:
#get the item to which we want to paste the renderings from the source item $targetItem = get-item . #get the item path for printing it later $targetName = $targetItem.ProviderPath; #assign the renderings that we've recorded in the previous script $targetItem.__Renderings = $renderings; #Write what you've done write-host "Renderings pasted from '$($sourceName)' to '$($targetName)'"
You can see that the $renderings variable is not initialized anywhere in this script. That’s not necessary because we did this in the previous script and it indeed persisted! Let’s look at this script runtime settings then to see how you can achieve this…
You can see that the Persistent Session ID is the same as in the previous script therefore it will get executed in the same runspace and thus we’ll get access to the previous script variables. More than that though – you see that the script Enable rule requires that a session with our selected Persistent Session ID already exist for the menu item to be enabled in the context menu. Which is desirable as if you haven’t copied anything at first – the required $renderings variable would not be initialized yet and the script would not be able to perform its job. That is why in the above context menu screenshot the Paste Renderings item was disabled. Once we execute the Copy renderings script from the menu the session with the renderingCopySession ID will be present in SessionManager and this script will become enabled:
SPE comes with a few rules that allow you for rich definition of when items are enabled or disabled:
The first rule on the above list will be explained in one of the upcoming posts, the second we’ve just used. Now the third rule on the above list is going a bit further then the second one. It checks not only whether the session with a specific Persistent Session ID exists but also that it has a specifically named variable within the session defined. This way you can steer whether some options appear or not in the menu from your scripts by defining variables in your scripts.
How else a session can become persistent?
There is one built-in scenario when a session needs to become persistent – that is when you use the PowerShell Console:
This is because the Console enables you to keep continuity between the commands you execute and in fact is handled completely differently than the other interactions – through a web service.
How do I keep them sessions in moderation?
With the sessions potentially staying in memory how do we keep it under control?
Well the good news is that every persistent Runspace/ScriptSession will be removed from memory automatically within half an hour after it’s been last used. They will expire and get removed after that time. The Console again is a special case – if you keep the window open it will ping the server to keep the session alive as long as the windows is on, the session will be collected after half an hour of closing the Console window to give you a chance to re-connect to it if it was closed by mistake.
If you want to see which sessions are alive you can run the PowerShell Background Session Manager available in the PowerShell Toolbox in the Sitecore menu:
Which will allow you to kill sessions and connect to them.
If you connect to an existing session you can have access to all the variables to e.g. debug a named session or diagnose their variable values. For example I can connect to the session with our renderingCopySession ID and check the value of the Runspace variables:
As you can see above it even retained and printed the output for me when I opened it and when I typed $renderings it shown me the value of the variable.
Do you have any other example of persistent session usage?
You might want to check out the Packaging scripts which are another OOTB Example of Persistent Sessions usage.
What should I be mindful of?
An important thing to remember is that whatever is stored in variables in the session you’re keeping in memory is staying in memory for the duration of the session. Therefore it’s best practice to keep as little in them as possible. This means that if you’re using global PS variables you might consider clearing those by assigning $null to those that are not needed between the calls to a persistent session.
The sessions with persistent ID do not mix between different user sessions. If you’ll login to a different browser it will not retain your state from the other browser as the sitecore session is part of the internally used session key.
You can still see all users sessions and all your sessions from different browser in the Session Manager. You can also connect to all of them, so probably storing a sensitive user data in them is not a good idea.
That is all really that is to it – now with those session management basics laid out we will be able to move into using them to create more exciting scenarios with them in the following posts.
This entry (Permalink) was posted on Sunday, October 26th, 2014 at 9:02 pm and is filed under .Net Framework, Best Practices, Code Samples, PowerShell, Sitecore, Software Development, Solution, Web applications. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response , or trackback from your own site.