Posts Tagged ‘APIs’

So, the Windows PowerShell 2.0 Software Development Kit is basically a collection of samples, and it has been released separately from the Windows Platform SDK for a change, making the download a tiny 2.35MB …

There are lots of examples in there in C# (no other languages), and honestly, some of them ought to make it into PSCX or some other project where people could grab pre-compiled versions ;)

  • A Template for creating PSProviders, and a sample PSProvider (for Access databases).
  • A sample of participating in Transactions (a set of “transacted comment” cmdlets for creating comments that go along with a transaction).
  • Example cmdlets: Select-Object, Select-String, Get-Process, Stop-Process
  • Dealing with issues with Serialization in PowerShell
  • PowerShell Eventing:
    • Deriving from ObjectEventRegistrationBase to create Register-FileSystemEvent
    • Receiving notifications from PowerShell Events on remote computers.
    • Hosting APIs, including (among others):
    • Restricted runspaces
    • Runspace pools
    • Remote runspaces (and remote runspace pools)
    • Running commands in parallel or sequentially
    • Calling Cmdlets and passing parameters
  • Reproducing the default PowerShell.exe output

Honestly, if you’re a developer that’s been wondering about learning to code cmdlets, or host PowerShell as a scripting engine, now’s the time.

Awhile back I wrote a Get-Web script, which I later converted to a compiled Get-Web cmdlet and module (pssnapin) ... adding support for POST forms. At the time, it seemed like GET and POST with some string variables pretty much covered what I’d ever want to do with web pages, however I found a few places where I needed to POST a file attachment, and then a couple of full-on REST APIs, which use not just GET and POST, but PUT and DELETE as well.

While I was playing with scripting the REST API for DekiWiki … I experimented with the MindTouch Dream SDK … and as a result, I’ve refactored the part of that module that actually does the HTTP work out into a little PowerShell 1.0 compatible script library. Of course, it depends on several dll’s (mindtouch.core.dll, mindtouch.dream.dll, and SgmlReaderDll.dll and log4net.dll) from the Dream SDK, which you can download from SourceForge.

Example Uses


## Retrieve Google search results:
function Get-Google {
  Invoke-Http GET http://www.google.com/search @{q=$args} |
    Receive-Http Xml "//h3[@class='r']/a" | Select href, InnerText
}

## Download a file from a web page
function Get-WebFile($url,$cred) {
  Invoke-Http GET $url -auth $cred | Receive-Http File  
}

## Upload a PowerShell script to PasteBin
function Send-Paste {
PARAM($PastebinURI="http://posh.jaykul.com/p/",[IO.FileInfo]$file)
PROCESS {
  if($_){[IO.FileInfo]$file=$_}

  if($file.Exists) {
    $ofs="`n"
    $result = Invoke-Http POST $PastebinURI @{
      format="posh"           # PowerShell
      expiry="d"              # (d)ay or (m)onth or (f)orever
      poster=$([Security.Principal.WindowsIdentity]::GetCurrent().Name.Split("\")[-1])
      code2="$((gc $file) -replace "http://","http``://")" # To get past the spam filter.
      paste="Send"
    } -Type FORM_URLENCODED -Wait
    $xml = $result.AsDocument().ToXml()
    write-output $xml.SelectSingleNode("//*[@class='highlight']/*").href
  } else { throw "File Not Found" }
}}
#########################################################

## Example, to download my PasswordRequired.dll:
$cred = new-object System.Management.Automation.PSCredential `
                   "test", $(ConvertTo-SecureString "password")
Get-WebFile http://huddledmasses.org/downloads/PasswordRequired.dll $cred

## Example, to upload a script called TestScript.ps1 to the Pastebin we use on IRC:
ls TestScript.ps1 | Send-Paste "http://posh.jaykul.com/p/"

 

There are basically two main functions: Invoke-Http and Receive-Http. There are also a few extra functions which are mostly just for use by these two functions, and then Set-HttpDefaultUrl and Set-HttpCredential which you can use to simplify your scripts. I intend to rewrite these as cmdlets in C# and contribute them to the PowerShell Community Extensions along with some of my other networking cmdlets (Get-DNS), so if you have any suggestions, I’d love to hear them!

Invoke-Http

Invokes HTTP verbs (like GET, POST, PUT, and DELETE) against a URL with optional parameters (eg: name = value), input, etc … and returns the output as a MindTouch.Dream.Result or (optionally) as a MindTouch.Dream.DreamMessage …

Syntax

Invoke-Http [-Verb] <String> [[-Path] <String>] [[-With] <Hashtable>] [[-Content] <Object>] [[-Type] <String>] [[-Authenticate] <String>] [-WaitForResponse]

Parameters

Verb

The HTTP verb you want to invoke. Defaults to GET, but can be anything your HTTP server supports.

Path

The URL you want to invoke against. Can be a partial URL, if you first call Set-HttpDefaultURL first. You can also specify this as an array or a hashtable. This is particularly useful if you’re specifying a partial URL, and your URL is built based on logic in your code. If you pass an array, the values in the array are joined with forward-slashes. If you pass a hashtable, the keys and values are appended joined with forward-slashes, but the values are double encoded (by UrlEncode), ie: $key/$(UrlEncode(UrlEncode($value))

With

The parameters to be passed with the verb call, as a hashtable. (these are particularly used for POST, etc). These are passed in the query as named parameters, with the values encoded.

Content

Anything you want to pass as content. In actuality, we really only handle three things: XML Documents, file paths (the file will be used as content), and everything else is passed as simple text. If you need other data types, the “DreamMessage” that the scripts depend on can handle all sorts of data types, so you’ll just need to add it around line 50 of the script.

Type

This is the type of content. We can automatically deduce this for XML or File objects, but if you want to force a type, you should use this parameter. For instance, to fake a web form submission, you need to specify the type as FORM or FORM_URLENCODED but you can also specify the type as any of: ATOM, BINARY, BMP, CSS, DREAM_EXCEPTION, FORM_URLENCODED, GIF, HTML, HTTP, JPEG, JS, JSON, MULTIPART_MIXED, NOTHING (mimetype -/-), ANY (mimetype */*), PDF, PHP, PNG, RDF, RELAXNG, SVG, ANY_TEXT (mimetype text/*), TEXT (mimetype text/plain, with the ISO-8859-1 encoding), TEXT_UTF8 (mimetype text/plain, with UTF8 encoding), TEXT_XML, TIFF, VCAL, VERSIT, XHTML, XML, XRDS.

Authenticate

You can pass either a boolean (in which case the HTTPRest scripts will use a default $global:HttpRestCredential which it will prompt for if you haven’t set it), or an actual PSCredential or NetworkCredential object. In any case, this causes the invoke to contain network credentials. Note that sometimes you may need to pre-authenticate before making calls to a web-service.

WaitForResponse

A switch parameter that causes the query to wait until the response completes downloading, and return a DreamResponse instead of returning an incomplete Result ... this is useful when you know the response is a simple XML file and you need to parse it to determine whether your call has succeeded. If you need to actually get the data out, or if you just need to know the method was invoked successfully, you shouldn’t pass this parameter.

Receive-Http

Receives the response or result from a Dream.Result or DreamMessage. as XML, XDoc, text, raw bytes, or even to file. This function is really only useful to receive the output of Invoke-Http when you need the response content.

Syntax

Receive-Http [[-Output] <string:[Xml|File|Text|Bytes]>] [[-Path] <string>] [[-InputObject] <MindTouch.Dream.Result<MindTouch.Dream.DreamMessage>>]

Receive-Http [[-Output] <string:[Xml|File|Text|Bytes]>] [[-Path] <string>] [[-InputObject] <MindTouch.Dream.DreamMessage>]

Parameters

Output

The TYPE of output you want:

  • Xml will return an XmlDocument — or XmlNode(s) if you pass a Path.
  • File will write to file — currently, you must pass a path, I didn’t make it guess it automatically.
  • Text will output text — in the case where the actual output is XML, this returns the InnerText.
  • Bytes returns an array of bytes…
  • XDoc returns a MindTouch.Dream.XDoc (not the .Net native class), which has a boatload of extra web-related methods and features you might find useful such as accepting XPath operators as indexers.

Path

A string containing the path for file output or XPath selector for XML, XDoc, and Text output

InputObject

The input must be either a Result<DreamMessage> or a DreamMessage itself. Values passed on the pipeline are accepted into this parameter.

Set-HttpDefaultUrl

This takes the passed URI and sets it as the base (default) URL for the Invoke-Http function (if you set this, any path passed to Invoke-Http is treated as relative to this path).

Set-HttpCredential

This takes a PSCredential or NetworkCredential and stores it as a PSCredential for use by the Invoke-Http function. Particularly useful when you want to script a bunch of authenticated methods without being re-prompted. Note that if you don’t pass a credential, you’ll be prompted for one the usual way, so calling just Set-HttpCredential is sufficient when working on the command-line.

Miscellaneous

There are other functions in here, a few should be considered “internal” functions (when this is a module, they would not be exported: Get-DreamMessage, Get-DreamPlug, Get-HttpCredential) and a few of which came out of my utilities functions (like Encode-Twice, and Join-Url, Get-FileName, Get-UtcTime, and Get-CredentialBetter)...

Code

You may not have noticed, but there are several wiki’s with PowerShell content in them, but generally speaking, they are the results of the effort of a single person (or very a small group) ... and none of them seems to have captured the attention of the general PowerShell community. Certainly, the PowerShell Community site has never had it’s own wiki.

I’ve been pushing for an unofficial community wiki for awhile, and recently, I had an opportunity to try out MindTouch DekiWiki at work, and I was so impressed, I decided to throw one up and take it upon myself to demo to Halr9000 and a few of the MVPs (and now … to all of you!) why I think we should set up a DekiWiki for our community :)

It’s really quite simple. On top of having some really awesome features like hierarchical pages, a WYSIWYG editor, and built-in lucene search and file attachments … it also has a REST api, and you can edit the pages in plain-old HTML (not really surprising considering the WYSIWYG interface). The combination of these two things, and the MindTouch Dream sdk (along with good examples of using it with the Deki REST API) make it so easy to work with in .Net and PowerShell, that I just felt compelled to share my scripts…

First is the conversion script, which is based on New-HtmlHelp, some excellent work by one of the VMWare PowerShell guys …

But then, the more interesting stuff, written on top of MindTouch Dream (you need to download Dream from SourceForge.net to use it, or just grab both my scripts and the dlls in a 7-zip archive), a series of cmdlets which abstract away some of the intricacies of the DekiWiki API. So far, I’ve only written a few … most notably: Set-DekiContent, which will allow you to write a little loop like this:


foreach($cmd in (gcm -type cmdlet | ? { $_.PsSnapin -like "Microsoft.PowerShell*" })) {
   Get-Help $cmd.Name -full -EA "SilentlyContinue" | ConvertTo-DekiContent Cmdlet_Help |
   %{ Set-DekiContent "Cmdlet_Help/$($cmd.PSSnapin)/$($cmd.Name)" $_ }
}

Which produces this PowerShell Cmdlet Help … pretty cool, right? Incidentally, feel free to contribute more, and/or comment on or edit the help for those cmdlets to improve upon it.

Without futher ado, here’s the script module:

Several people have blogged about using the Google charts api from PowerShell, but everyone seems to be using the “simple” numerical encoding, so I figured that as the first step of my own google chart api wrapper module I would start out by writing up a simple encoder. I’m not posting this to the script repository until I’m done with it — this is just the number encoding function.

But I figured I’d blog it here in case it will help anyone else write the full wrapper module “for” me before I get around to it :) In any case, remember this doesn’t encode numbers higher than 4095, so if you have a bunch of numbers and some of them might be larger than that, you’ll still need to normalize them so they are within that range. I’ll post the function to normalize a series of numbers later this evening, because for some reason I can’t find it right now, but I’m sure I already wrote it ;) .


## Google Chart API extended value encoding function
#########################################################################
function GoogleEncode {
BEGIN {
   ## Google's odydecody is a 64 character array
   $ody = "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q",
   "R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j",
   "k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2",
   "3","4","5","6","7","8","9","-","."

   ## The actual filter function
   filter encode {
      # we have a hard-coded "overflow" value
      if($_ -ge ($ody.Count * $ody.Count) ) { return "__" }
     
      $y = -1  # $y is a ref variable, so it has to be defined
      $x = [Math]::DivRem( $_, $ody.Count, [ref]$y )
      return "$($ody[$x])$($ody[$y])"
   }
   
   ## Handle numbers as parameters
   foreach($i in $args) {
      $i | encode
   }
}
## Or handle numbers from the pipeline. We don't care :-)
PROCESS {
   if($_ -ne $null) { $_ | encode }
}
}

That’s the whole thing … it’s really only about three lines of code (including the definition of $ody), but the rest is necessary to make it handle parameters or pipeline values. :D

Search My Content