Infrastructure at your Service

Ten monthes ago, when I started to work for DBI at a customer site, I had to work on groups managing the server accesses. The information can be queried via a simple web site:

  1. enter a server and it provides a list of groups
  2. enter a group and it provides the list of servers in it


I initially thought I will parse the returned HTML. Then, with my favorite browser and its powerful developer mode, I saw that result is actually XML.
I first made a Perl script. This was quickly developed, but it was not the most convenient for the Windows integration and for graphical capabilities on my customer laptop. So, with advice from my colleague, I moved to PowerShell.
This script is now 70kbytes which contains lots of tricks and ease that make me liked PowerShell very much. I will share one important aspect in this blog.

WebService

First thing, I needed was to actually read data from the URL with the right format. For this, Invoke-WebRequest Cmdlet looked to be perfect for the job.
The first issue encountered are the credentials, especially if it is possible for user to enter his credentials each time a call to the WebServervice is need. The parameter is “-UseDefaultCredentials”.
As laptop is integrated in a Windows domain and Web service uses SSO (Single Sign On), parameter will automatically pass currently logged user credentials transparently.
Lastly, “-Uri” is the most important parameter as it is the location of the service.
Command will finally look like:

$Response = Invoke-WebRequest -UseDefaultCredentials -Uri 'https://ServiceFQDN/server.cgi'

$Response variable is of type HtmlWebResponseObject which compose of the following members:

   TypeName: Microsoft.PowerShell.Commands.HtmlWebResponseObject
 
Name              MemberType Definition
----              ---------- ----------
Dispose           Method     void Dispose(), void IDisposable.Dispose()
Equals            Method     bool Equals(System.Object obj)
GetHashCode       Method     int GetHashCode()
GetType           Method     type GetType()
ToString          Method     string ToString()
AllElements       Property   Microsoft.PowerShell.Commands.WebCmdletElementCollection AllElements {get;}
BaseResponse      Property   System.Net.WebResponse BaseResponse {get;set;}
Content           Property   string Content {get;}
Forms             Property   Microsoft.PowerShell.Commands.FormObjectCollection Forms {get;}
Headers           Property   System.Collections.Generic.Dictionary[string,string] Headers {get;}
Images            Property   Microsoft.PowerShell.Commands.WebCmdletElementCollection Images {get;}
InputFields       Property   Microsoft.PowerShell.Commands.WebCmdletElementCollection InputFields {get;}
Links             Property   Microsoft.PowerShell.Commands.WebCmdletElementCollection Links {get;}
ParsedHtml        Property   mshtml.IHTMLDocument2 ParsedHtml {get;}
RawContent        Property   string RawContent {get;set;}
RawContentLength  Property   long RawContentLength {get;}
RawContentStream  Property   System.IO.MemoryStream RawContentStream {get;}
Scripts           Property   Microsoft.PowerShell.Commands.WebCmdletElementCollection Scripts {get;}
StatusCode        Property   int StatusCode {get;}
StatusDescription Property   string StatusDescription {get;}

The two interesting fields are:

  1. StatusCode which will contain the http status. I expect to be equal to 200
  2. Content which is the actual result of the service. In our case, it will be xml text.

If WebService does not behave well, Invoke-WebRequest might raise a System.Net.WebException. To manage this, I used the typical Try/Catch block.

Final code block will look like:

Try {
$Response = Invoke-WebRequest -UseDefaultCredentials -Uri 'https://ServiceFQDN/server.cgi'
} Catch [System.Net.WebException] {
$exception = $_.Exception
Write-Host $exception.Exception.GetType().FullName + ': ' + $exception.Exception.Message
}

It is possible to get the HTTP status code and manage this differently depending on it. To access the value:
$exception.Response.StatusCode

Going through content result

When request complete properly, I simply get the content and cast this to the xml type:

 $xmlContent = $Response.Content

To go through the data, we can use ForEach loop:

ForEach ($element in $xmlContent.element) {
Write-Host 'Working on $element'
(... do the needed ...)
}

On another WebService, it is even possible to choose result in xml of json. “-contentType” parameter can be used to specify result format.

Conclusion

While browsing customer intranet, I found some other WebService to manage user. As it is part of my day to day activity to add users to multiple groups, scripting that will also make me and my team gains lots of time.
On my next blogs on PowerShell, I will share what difficulties I found especially while moving from a simple script to a powerful tool with a graphical interface with many cool features:

  1. Create and automatically fill an email
  2. Create an Excel document and fill it

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Olivier Spiesser
Olivier Spiesser

Consultant