PowerShellASP Applied: JSON Factory

Now that we can use PowerShellASP with SharePoint, what can we do with it? Well without master page or web part support, we can’t easily integrate PoShASP content directly into the SharePoint experience. Fortunately, we can leverage PowerShell in other ways. An easy example is generating JSON, perhaps from the PowerShell standby Get-Process:

<% $Response.ContentType = "application/json; charset=utf-8" %>
<% $Response.Cache.SetCacheability([System.Web.HttpCacheability]'NoCache') %>
<% $Response.Cache.SetExpires([DateTime]::MinValue) %>
<% if( !($n = $Request.QueryString["n"] -as [int]) ) { $n = 10 } %>
{"processes":[
  <% [string]::Join(",`n  ",
  (get-process | sort ws -desc | select -first $n | foreach {
  "{'ID':$($_.ID),'Name':'$($_.Name)','WS':$($_.ws)}" })) %>
]}

After we set the JSON ContentType and cache policy, we try to fetch an “n” query parameter. If n is missing or not a number, we default to 10. Now we can start building our JSON object. To build our array, we use System.String‘s static Join method (the backtick is PowerShell’s escape character, so `n is a newline). Join‘s string[] parameter is provided by a PowerShell pipeline that fetches our system processes, sorts by working set size, selects the top $n and then iterates through those process objects, returning a string of JSON with our desired properties. Note also that PoShASP seems to require an empty line at the end of the file, otherwise “]}” is ignored. Our output will look something like this:

{"processes":[
  {'ID':1672,'Name':'sqlservr','WS':506028032},
  {'ID':3296,'Name':'devenv','WS':230555648},
  {'ID':4720,'Name':'w3wp','WS':181100544},
  {'ID':376,'Name':'services','WS':121995264},
  {'ID':3372,'Name':'w3wp','WS':102522880}
]}

Let’s save our JSON endpoint as %12%\TEMPLATE\LAYOUTS\Get-Process.json.ps1x, which we can test by visiting http://server/_layouts/Get-Process.json.ps1x?n=5. Now it’s AJAX time! Since not everyone can use the ASP.NET AJAX Extensions, we’ll just do it the old-fashioned way. Starting with a Content Editor Web Part on a page of your choice, set the source to the following:

<div id="d_procs">
<img src="/_layouts/images/GEARS_AN.GIF"
  alt="Loading..." align="center" />
</div>
<script>
function getXmlHttpRequestObject() {
 if (window.XMLHttpRequest) {
  return new XMLHttpRequest();
 } else if(window.ActiveXObject) {
  return new ActiveXObject("Microsoft.XMLHTTP");
 } else {
  document.getElementById('d_procs').innerHTML =
  'Cound not create XmlHttpRequest Object.';
 }
}

var r = getXmlHttpRequestObject();
var c = 0;
var mTimer;

function getProcs() {
 if (r.readyState == 4 || r.readyState == 0) {
  r.open("GET", '/_layouts/Get-Process.json.ps1x?n=5', true);
  r.onreadystatechange = handleReceiveProcs;
  r.send(null);
 }
}

function handleReceiveProcs() {
 if (r.readyState == 4) {
  var d = document.getElementById('d_procs');
  var response = eval("(" + r.responseText + ")");
  var p = response.processes;
  var t = "<table width=\"100%\">";
  t += "<tr><th>ID</th><th>Name</th><th>WS(MB)</th></tr>";
  for(i=0;i < p.length; i++) {
   t += '<tr><td>'+p[i]['ID']+'</td>';
   t += '<td>'+p[i]['Name']+'</td/>';
   t += '<td align=\"right\">';
   t += (p[i]['WS']/(1024*1024.0)).toFixed(2);
   t += '</td/></tr>';
  }
  t += "</table><p>Refresh count: "+(++c)+"</p>";
  d.innerHTML = t;
  mTimer = setTimeout('getProcs();', 3000); // 3-sec refresh
 }
}

_spBodyOnLoadFunctionNames.push('getProcs');
</script>

I haven’t put much effort into cleaning up the code, but it does the job (in FF2 and IE7, at least):

With PowerShell’s ease of development and specialized adapters, this is just the tip of the iceberg. What other real-time data would you find useful?

4 Responses to “PowerShellASP Applied: JSON Factory”

  1. Peter Seale Says:

    This is impressive, and simultaneously heart attack-inducing. I use PowerShell as an ad-hoc scripting tool and prototyping environment, so the idea of running something like this is both a) awesome, b) scary.

    I do admit it’s awesome, just…don’t run it in production? I don’t even have PowerShell installed on our production farm, to prevent the tempation to use it for “quick fixes”.

  2. Keith Dahlby Says:

    I’m still trying to wrap my head around how I might actually use this for more than theorycraft. In my view, production-worthiness depends mostly on performance, and it would be hard for PowerShell to compete with precompiled “classic” ASP.NET in terms of raw performance. While JSON might be easy in PowerShell, I doubt it would hold up well under load. That said, I don’t think we should be dissuaded from using PowerShell(ASP) when convenience outweighs performance. Of course it’s not particularly convenient to have to run scripts out of _layouts, but I can definitely think of a few ways we might reasonably leverage the PowerShellASP engine, even in production, given sufficient SharePoint integration.

  3. PowerShell Coalesce and PowerShellASP Query String Parameters « Solutionizing .NET Says:

    […] The array subexpression @( … ) always returns an array, to which we append $null in case the array is empty. Taking the first element yields the desired result. I also define an alias (??) for an easily remembered shorthand, though the usage is different from the binary C# operator. With our new function, my original QueryString pattern: […]

  4. Lance Robinson Says:

    Now PowerShellToys.com has a PowerShellWebPart that works similarly to PowerShellASP.


Comments are closed.