| Shane 的个人资料Knowledge Is Power(shell...照片日志列表 | 帮助 |
|
3月13日 Powershell REST ClientThe past couple of days I have been working on a Powershell based client for our REST web services. While the client is specific to our business the core logic behind the client should apply to just about all REST based web services. I have tried to generalize(read: remove company stuff) the code so hopefully everything still makes sense. In our implementation of REST, we allow a person to either submit a GET request with query string parameters or attach some XML to the request and submit as a POST. Our response will always be some xml. We handle it with 3 xml root types. Success, Error, and Data. Success just lets the user know a particular POST was successful. Error will give the user back an error code with a description. Data will return an xml document with whatever data the user requested. Eventually a Success I would think will also return the changes made but hey, this is version 1. The core of each GET request is just making the request with the query strings defined. The declaration of the core function with the parameters section is: function Invoke-APICall {
1: #Create a URI instance since the HttpWebRequest.Create Method will escape the URL by default. 2: $URI = New-Object System.Uri($URL,$true) 3: 4: #Create a request object using the URI 5: $request = [System.Net.HttpWebRequest]::Create($URI) 6: 7: #Build up a nice User Agent 8: $request.UserAgent = $(9: "{0} (PowerShell {1}; .NET CLR {2}; {3})" -f $UserAgent, 10: $(if($Host.Version){$Host.Version}else{"1.0"}), 11: [Environment]::Version,12: [Environment]::OSVersion.ToString().Replace("Microsoft Windows ", "Win") 13: ) 14: 15: #Establish the credentials for the request 16: $creds = New-Object System.Net.NetworkCredential($Username,$Password) 17: $request.Credentials = $creds 18: 19: $response = $request.GetResponse() 20: 21: $reader = [IO.StreamReader] $response.GetResponseStream() 22: 23: #Our response will always be xml except in 404/401 case so cast as such 24: [xml]$responseXML = $reader.ReadToEnd() 25: 26: $reader.Close() 27: 28: #Let others down the pipeline have fun with our xml object 29: Write-Output $responseXML 30: 31: $response.Close()
To decide if this is a POST I use the following: if($XMLObject){ Do the POST stuff}else{Do the GET stuff} And now the POST specific code. 1: $creds = New-Object System.Net.NetworkCredential($Username,$Password) 2: $request.Credentials = $creds 3: 4: #Since this is a POST we need to set the method type 5: $request.Method = "POST" 6: 7: #Set the Content Type as text/xml since the content will be a block of xml. 8: $request.ContentType = "text/xml" 9: 10: #Create a new stream writer to write the xml to the request stream. 11: $stream = New-Object IO.StreamWriter $request.GetRequestStream() 12: $stream.AutoFlush = $True 13: $stream.Write($($XMLObject.psbase.OuterXML),0,$($XMLObject.psbase.OuterXml.Length)) 14: $stream.Close() 15: 16: #Make the request and get the response 17: $response = $request.GetResponse() 18: 19: #Create a stream reader to read the response stream. 20: $reader = New-Object IO.StreamReader $response.GetResponseStream() 21: 22: #Read the response and cast the response to XML 23: [xml]$responseXML = $reader.ReadToEnd() 24: 25: #Dump the XML out to the pipeline for others to consume 26: Write-Output $responseXML 27: 28: $response.Close()
There was one thing in the POST that I had trouble with at first. When trying to execute the $stream.Write method, if I had set the $request.ContentLength property with $request.ContentLength = $$XMLObject.psbase.OuterXML.Length, it would fail stating the bytes being written were longer than the bytes specified. So I removed the code to set the $request.ContentLength and everything seemed to work fine. Not sure how Joel Bennett got that to work but it drove me nuts for a while. So that just leaves the calling functions. Here is a GET 1: function Invoke-APIGetStuffInGroup { 2: param( 3: [string]$Group, 4: [string]$Username, 5: [string]$Password, 6: [string]$UserAgent = "Powershell API Client" 7: ) 8: 9: 10: $Group = [System.Web.HttpUtility]::UrlEncode($Group)11: $URL = "https://api.website.com/api/1.0/Groups/GetStuff?group=$Group" 12: Invoke-APICall -URL $URL -Username $Username -Password $Password -UserAgent $UserAgent 13: 14: }
And a POST 1: function Invoke-APIAddStuffToGroups { 2: param( 3: [string]$Username, 4: [string]$Password, 5: [string]$UserAgent = "Powershell API Client" 6: ) 7: $xml = #Create your XML Document here 8: 9: $URL = "https://api.website.com/api/1.0/Groups/AddStuff" 10: 11: Invoke-APICall -URL $URL -XMLObject $xml -Username $Username -Password $Password -UserAgent $UserAgent 12: } 13:
One change I might make at some point is to require a SecureString for the password since clear text can be bad. Hope this helps someone! -Shane 引用通告此日志的引用通告 URL 是: http://shanepowser.spaces.live.com/blog/cns!CBEC59A3683A2168!205.trak 引用此项的网络日志
|
|
|