Calling PowerShell Modules with REST / ODATA API

For a long time now, Windows Server has come with a feature called the “Management OData IIS Server Extension”.  As technology increasingly moves toward cloud computing and Microsoft technology is congealing around PowerShell, the power of this little known feature could hardly be overstated.  Built-in to Windows is the ability to run any PowerShell module remotely via a REST / ODATA API call. 

This means that any legacy application that can be run and configured by PowerShell, can be retrofitted with a REST interface.  Message Queue applications could be invoked via REST.  It also means that it is possible for any organisation to create & use a PowerShell module based Orchestration system for free.  The opportunities presented by using core Windows technology are quite stunning.

Setting up the Server

With my lab I’ve been using Windows Server 2012 R2 and Microsoft’s published “Windows Powershell role-based OData Web Service sample”.  The linked zip file can be downloaded to a server 2012 R2 machine with IIS and the Management OData IIS Server Extension installed.  The instructions within the example for creating the website are quite straightforward & I was able to use Visual Studio 2013 Community Edition to compile the c# project.  The sample project and installer can be obtained from:

https://code.msdn.microsoft.com/windowsdesktop/PswsRoleBasedPlugins-9c79b75a

The example requires to local user accounts (localAdmin, localNonAdmin) to be created on the server hosting IIS & the OData extension.

Testing the Server

The server setup should be relatively straightforward – the installer even opens firewall ports for the new website to work correctly.  Before going any further, you should test that service is up and running correctly.  This can be achieved by copying the URI into a web browser.

http://YourServerName:7000/MODataSvc/Microsoft.Management.Odata.svc/

Getting a login prompt is a good sign.  By using the credentials you created for the localadmin account, you should get an xml response displaying the default workspace for the server as shown below.

Customising the Configuration

All the configuration changes required to use the example are within the XML file RBACConfiguration.xml which will have been installed in the Modata folder off the MODataSvc website.

The file contains three elements.  It:

  • establishes two groups – one called “AdminGroup”, the second called “Non-AdminGroup”
  • lists the user accounts that may access the service & links those accounts to groups
  • lists modules that may be referenced via the service
  • lists the commands that may be run from within the specified PowerShell modules

An image of the default configuration is below

Depending on what PowerShell modules you wish to run, there are customisations that you will need to do.  You may want to run modules that need administrative credentials on the server – such as restarting services or querying elements of the system that are restricted for ordinary users.  If so, you’ll probably need to add a domain account with appropriate rights into the users section of the configuration file.

You will certainly want to add in your on PowerShell modules and allowable cmdlets.  To identify which modules your commands are part of, you’ll need to search through the default PowerShell modules folder: C:\Windows\System32\WindowsPowerShell\v1.0\Modules

For any customisations to take effect, you’ll need to stop and restart the web server.

*** Note there is a quirky behaviour as to specifying Cmdlet elements.  With my testing, when the module "Microsoft.PowerShell.Utility" is inluded within the RBACConfiguration, other modules automatically make their Cmdlets available for use as the module is listed within the Modules section of the RBACConfiguration.xml configuration file - this is for Admin users anyway.  In those situations, specifically adding the cmdlet name into the configuration file (and restarting the server) would cause the entire site to fail.  My guess is that the flexibility & lack of rigidity around requirements for writing modules & PSD files is probably to blame.  Not to mention that Microsoft provided the Odata code as an example - not as an official product!   With "Microsoft.PowerShell.Utility" included as well as "Microsoft.PowerShell.Management", new PowerShell modules and their cmdlets become available as soon as the the RBACConfiguration.xml file is updated - without any need to restart the server or website.

After adding in a new module, test if your desired Cmdlets are available before explicitly adding them to the RBACConfiguration.xml file.  The easiest way to test is by launching a new browser session to http://:7000/MODataSvc/Microsoft.Management.Odata.svc/CommandDescriptions and searching for the cmdlet name.

Using PowerShell with the exposed OData API

This example will use the newly created OData interface to query the process ID and Handle details from the targeted server.  It will run the PowerShell command:

"Get-Process -Name svchost | select-object -property ID,Handles"

There are two PowerShell cmdlets referenced in the command I want to use. 

I know from text searching in the “C:\Windows\System32\WindowsPowerShell\v1.0\Modules\” folder that

 Get-Process is provided by Microsoft.PowerShell.Management.psd1 &

Select-Object is provided by the definition Microsoft.PowerShell.Utility.psd1

As I’ve already customised the servers RBACConfiguration.xml file to include these modules and allow the Get-Process and Select-Object cmdlets to be called by members of the AdminGroup

The PowerShell code to invoke the command via OData is:

$server = "smaserver.domain.com"
$cred = New-Object System.Management.Automation.PSCredential `
          ("localadmin",(ConvertTo-SecureString "Password1234" -AsPlainText -Force))

# Create the Request
$Headers = @{“Accept” = “application/atom+xml,application/xml”}
$body = @{
    "OutputFormat" = "json";
    "Command" =  "Get-Process -Name svchost | select-object -property ID,Handles";
    "WaitMsec"=  7000
}

$JSON = $body | convertto-json 

#Submit the Request
[xml]$invocation = Invoke-RestMethod "http://$($server):7000/MODataSvc/Microsoft.Management.Odata.svc/CommandInvocations" `
                     -Method 'POST' -Headers $headers -Body $JSON -ContentType "application/json"  –Credential $cred 

#A properly formed request will return a unique URI for the submitted request
$invocation.entry.id 

#The returned URI can be used to query the current status of the request, and the result of running the module cmdlet
[xml]$result = Invoke-RestMethod $invocation.entry.id  –Credential $cred

$result.entry.content.properties.Status
$result.entry.content.properties.Output 

 

The script (assuming the result is completed) returns

In this Series:

Calling PowerShell Modules with the REST / ODATA IIS Server extension
Calling PowerShell Modules with the REST / ODATA IIS Server extension (Example 2 - SSH)
Calling PowerShell Modules with the REST / ODATA IIS Server extension (Example 3 - WinRM)

Tags