Skip to main content

How to make an HTTP request with PowerShell

If you are making an HTTP request to a RESTful web service, you can use the PowerShell Invoke-RestMethod cmdlet. This provides a very simple HTTP REST interface, and will also format the result into a PowerShell object.

If you would like to use your own functions, you can follow the instructions below.

This is a helper function to format (indent) an XML response from a web service.
function Format-XML {
  Param ([string]$xml)

  $out = New-Object System.IO.StringWriter
  $Doc=New-Object system.xml.xmlDataDocument 
  $doc.LoadXml($xml) 
  $writer=New-Object system.xml.xmltextwriter($out) 
  $writer.Formatting = [System.xml.formatting]::Indented 
  $doc.WriteContentTo($writer) 
  $writer.Flush()
  $out.flush()
  Write-Output $out.ToString()
}


Here is the function to make the http call. It dumps the response data on the terminal and also returns it as a string to the caller. If there is an error it will dump the HTTP status code and comment on the terminal and return the response StatusDescription. Remove or comment out the Write-Host lines if you don't want it to write anything to the terminal.
function Http-Web-Request([string]$method,[string]$encoding,[string]$server,[string]$path,$headers,[string]$postData)
{
    ## Compose the URL and create the request
    $url = "$server/$path"
    [System.Net.HttpWebRequest] $request = [System.Net.HttpWebRequest] [System.Net.WebRequest]::Create($url)

    ## Add the method (GET, POST, etc.)
    $request.Method = $method
    ## Add an headers to the request
    foreach($key in $headers.keys)
    {
        $request.Headers.Add($key, $headers[$key])
    }
    ## We are using $encoding for the request as well as the expected response
    $request.Accept = $encoding
    ## Send a custom user agent if you want
    $request.UserAgent = "PowerShell script"

    ## Create the request body if the verb accepts it (NOTE: utf-8 is assumed here)
    if ($method -eq "POST" -or $method -eq "PUT") {
        $bytes = [System.Text.Encoding]::UTF8.GetBytes($postData) 
        $request.ContentType = $encoding
        $request.ContentLength = $bytes.Length
        
        [System.IO.Stream] $outputStream = [System.IO.Stream]$request.GetRequestStream()
        $outputStream.Write($bytes,0,$bytes.Length)  
        $outputStream.Close()
    }

    ## This is where we actually make the call.  
    try
    {
        [System.Net.HttpWebResponse] $response = [System.Net.HttpWebResponse] $request.GetResponse()     
        $sr = New-Object System.IO.StreamReader($response.GetResponseStream())       
        $txt = $sr.ReadToEnd() 
        ## NOTE: comment out the next line if you don't want this function to print to the terminal
        Write-Host "CONTENT-TYPE: " $response.ContentType
        ## NOTE: comment out the next line if you don't want this function to print to the terminal
        Write-Host "RAW RESPONSE DATA:" . $txt
        ## If we have XML content, print out a pretty version of it
        if ($response.ContentType.StartsWith("text/xml"))
        {
            ## NOTE: comment out the next line if you don't want this function to print to the terminal
            Format-XML($txt)
        }
        ## Return the response body to the caller
        return $txt
    }
    ## This catches errors from the server (404, 500, 501, etc.)
    catch [Net.WebException] { 
        [System.Net.HttpWebResponse] $resp = [System.Net.HttpWebResponse] $_.Exception.Response  
        ## NOTE: comment out the next line if you don't want this function to print to the terminal
        Write-Host $resp.StatusCode -ForegroundColor Red -BackgroundColor Yellow
        ## NOTE: comment out the next line if you don't want this function to print to the terminal
        Write-Host $resp.StatusDescription -ForegroundColor Red -BackgroundColor Yellow
        ## Return the error to the caller
        return $resp.StatusDescription
    }
}

This is how the function is called.
## Define any custom headers in a Hashtable
$headers = @{ 
    apikey = "your authentication key"
}

## Sample GET request that returns a random list of numbers
$result = Http-Web-Request "GET" "text/xml" "http://www.random.org" "/integers/?num=10&min=1&max=6&col=1&base=10&format=plain&rnd=new" $headers ""

## Sample POST request
$utf8PostData = @"

    Put your XML, JSON, name-value pairs, etc. here
"@

$result = Http-Web-Request "POST" 'text/xml' "http://example.com" "/web/service/endpoint" $headers $postData

## Sample POST request with JSON Data
$utf8PostData = @"
{
    key1: 'value1',
    key2: 'value2',
    number1: 1
}
"@

$result = Http-Web-Request "POST" 'application/json' "http://example.com" "/posts" $headers $postData

You can also send any other HTTP verbs (DELETE, PUT, etc).

Comments

  1. I copied your function and did a simple get and it worked first time. Saved me a lot of time, Thanks

    ReplyDelete
  2. Hey Aaron, how a JSON would look like inside the postData?

    ReplyDelete
  3. Just stumbled on this. Very nice explanation and examples. I wish more people would copy your style and thoroughness.

    ReplyDelete

Post a Comment

Popular posts from this blog

Running PowerShell commands from Linux

There are several options for running PowerShell commands from Linux. Run the PowerShell script over a REST interface Unless you need a remote shell, the easiest option is to set up a REST interface for your PowerShell scripts. More information here . Using the winrm Ruby Gem https://github.com/WinRb/WinRM Using a WS-Management client on Linux Set up Windows for remote access: https://github.com/Openwsman/openwsman/wiki/winrm-over-openwsman-setup Install OpenWSMAN on Linux: http://openwsman.github.io/ Use Openwsman Command-Line Client: https://github.com/Openwsman/openwsman/wiki/openwsman-command-line-client OR - Use Ruby client bindings: http://users.suse.com/~kkaempf/openwsman/ Install an SSH server on Windows Install a Salt Minion on Windows Install Salt Master on Linux Install Python on Windows Install Salt Minion on Windows Open firewall on Windows for Salt access On Linux, run: # salt "winServer" cmd.run "powersh

A simple IIS HTTP module to log request headers and post data

This is a simple http module that hijacks the incoming request and logs it to a file. Using this module prevents the application from getting the post data because the input stream can only be read once. With .NET 4.0 the module could be much smaller, and could allow the application to read the data. To compile this, create a new "Class Library" application called PostDataLogger. Most of this class is pieced together from stolen code (stack overflow, etc.) using System; using System.IO; using System.Web; /// /// Dump PostDataLogger.DLL in your bin, and put this in your web.config inside of /// /// /// /// public class SimpleLogger : IHttpModule { private HttpApplication _ctx; public void Init(HttpApplication context) { _ctx = context; context.BeginRequest += new EventHandler(Context_BeginRequest); } void Context_BeginRequest(object sender, EventArgs e) { string GUID = Guid.NewGuid().ToString(); string filename = @"d:\temp\adeber