PoshCode Logo PowerShell Code Repository

HttpRest 1.0.1 (modification of post by Joel Bennett view diff)
View followups from Joel Bennett | diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/787"></script>download | new post

Added Get-WebPageContent to the initial implementation of the Http REST script functions (usable as a v1 script or as a module).

Documentation on this post on HuddledMasses

  1. ## Http Rest
  2. ####################################################################################################
  3. ## The first implementation of the HttpRest module, as a bunch of script functions
  4. ## Based on the REST api from MindTouch's Dream SDK
  5. ##
  6. ## INSTALL:
  7. ## You need log4net.dll mindtouch.core.dll mindtouch.dream.dll and SgmlReaderDll.dll from the SDK
  8. ## Download DREAM from http`://sourceforge.net/project/showfiles.php?group_id=173074
  9. ## Unpack it, and you can find these dlls in the "dist" folder.
  10. ## Make sure to put them in the folder with the module.
  11. ##
  12. ## For documentation of Dream:  http`://wiki.developer.mindtouch.com/Dream
  13. ####################################################################################################
  14. ## Version History
  15. ## 1.0   First Release
  16. ## 1.0.1 Added Get-WebPageContent
  17. ####################################################################################################
  18. ## Usage:
  19. ##   function Get-Google {
  20. ##     Invoke-Http GET http`://www.google.com/search @{q=$args} |
  21. ##       Receive-Http Xml "//h3[@class='r']/a" | Select href, InnerText
  22. ##   }
  23. ##   #########################################################################
  24. ##   function Get-WebFile($url,$cred) {
  25. ##     Invoke-Http GET $url -auth $cred | Receive-Http File
  26. ##   }
  27. ##   #########################################################################
  28. ##   function Send-Paste {
  29. ##   PARAM($PastebinURI="http`://posh.jaykul.com/p/",[IO.FileInfo]$file)
  30. ##   PROCESS {
  31. ##     if($_){[IO.FileInfo]$file=$_}
  32. ##
  33. ##     if($file.Exists) {
  34. ##       $ofs="`n"
  35. ##       $result = Invoke-Http POST $PastebinURI @{
  36. ##         format="posh"           # PowerShell
  37. ##         expiry="d"              # (d)ay or (m)onth or (f)orever
  38. ##         poster=$([Security.Principal.WindowsIdentity]::GetCurrent().Name.Split("\")[-1])
  39. ##         code2="$((gc $file) -replace "http`://","http``://")" # To get past the spam filter.
  40. ##         paste="Send"
  41. ##       } -Type FORM_URLENCODED -Wait
  42. ##       $xml = $result.AsDocument().ToXml()
  43. ##       write-output $xml.SelectSingleNode("//*[@class='highlight']/*").href
  44. ##     } else { throw "File Not Found" }
  45. ##   }}
  46. ##
  47. ####################################################################################################
  48. if(!$PSScriptRoot){
  49.    Write-Debug $($MyInvocation.MyCommand | out-string)
  50.    $PSScriptRoot=(Split-Path $MyInvocation.MyCommand.Path -Parent)
  51. }
  52. #  Write-Debug "Invocation: $($MyInvocation.MyCommand.Path)"
  53. #  Write-Debug "Invocation: $($MyInvocation.MyCommand)"
  54. #  Write-Debug "Invocation: $($MyInvocation)"
  55.  
  56. Write-Debug "PSScriptRoot: '$PSScriptRoot'"
  57.  
  58.  
  59. # This Module depends on MindTouch.Dream
  60. $null = [Reflection.Assembly]::LoadFrom( "$PSScriptRoot\mindtouch.dream.dll" )
  61. # MindTouch.Dream requires: mindtouch.dream.dll, mindtouch.core.dll, SgmlReaderDll.dll, and log4net.dll)
  62. # This Module also depends on utility functions from System.Web
  63. $null = [Reflection.Assembly]::LoadWithPartialName("System.Web")
  64.  
  65. ## Some utility functions are defined at the bottom
  66. [uri]$global:url = ""
  67. [System.Management.Automation.PSCredential]$global:HttpRestCredential = $null
  68.  
  69. function Get-DreamMessage($Content,$Type) {
  70.    if(!$Content) {
  71.       return [MindTouch.Dream.DreamMessage]::Ok()
  72.    }
  73.    if( $Content -is [System.Xml.XmlDocument]) {
  74.       return [MindTouch.Dream.DreamMessage]::Ok( $Content )
  75.    }
  76.    
  77.    if(Test-Path $Content -EA "SilentlyContinue") {
  78.       return [MindTouch.Dream.DreamMessage]::FromFile((Convert-Path (Resolve-Path $Content)));
  79.    }
  80.    if($Type -is [String]) {
  81.       $Type = [MindTouch.Dream.MimeType]::$Type
  82.    }
  83.    if($Type -is [MindTouch.Dream.DreamMessage]) {
  84.       return [MindTouch.Dream.DreamMessage]::Ok( $Type, $Content )
  85.    } else {  
  86.       return [MindTouch.Dream.DreamMessage]::Ok( $([MindTouch.Dream.MimeType]::TEXT), $Content )
  87.    }
  88. }
  89.  
  90. function Get-DreamPlug {
  91.    PARAM ( $Url, [hashtable]$With )
  92.    if($Url -is [array]) {
  93.       if($Url[0] -is [hashtable]) {
  94.          $plug = [MindTouch.Dream.Plug]::New($global:url)
  95.          foreach($param in $url.GetEnumerator()) {
  96.             if($param.Value) {
  97.                $plug = $plug.At($param.Key,"=$(Encode-Twice $param.Value)")
  98.             } else {
  99.                $plug = $plug.At($param.Key)
  100.             }
  101.          }
  102.       }
  103.       else
  104.       {
  105.          [URI]$uri = Join-Url $global:url $url
  106.          $plug = [MindTouch.Dream.Plug]::New($uri)
  107.       }
  108.    }
  109.    elseif($url -is [string])
  110.    {
  111.       [URI]$uri = $url
  112.       if(!$uri.IsAbsoluteUri) {
  113.          $uri = Join-Url $global:url $url
  114.       }
  115.       $plug = [MindTouch.Dream.Plug]::New($uri)
  116.    }
  117.    else {
  118.       $plug = [MindTouch.Dream.Plug]::New($global:url)
  119.    }
  120.    if($with) {
  121.       foreach($param in $with.GetEnumerator()) {
  122.          if($param.Value) {
  123.             $plug = $plug.With($param.Key,$param.Value)
  124.          }
  125.       }
  126.    }
  127.    return $plug
  128. }
  129.  
  130. #CMDLET Receive-Http {
  131. Function Receive-Http {
  132. PARAM(
  133.    #  [Parameter(Position=1, Mandatory=$false)]
  134.    #  [ValidateSet("Xml", "File", "Text","Bytes")]
  135.    #  [Alias("As")]
  136.    $Output = "Xml"
  137. ,
  138.    #  [Parameter(Position=2, Mandatory=$false)]
  139.    [string]$Path
  140. ,
  141.    #  [Parameter(Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="Result")]
  142.    #  [Alias("IO")]
  143.    #  [MindTouch.Dream.Result``1[[MindTouch.Dream.DreamMessage]]]
  144.    $InputObject
  145. #,
  146.    #  [Parameter(Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="Response")]
  147.    #  [MindTouch.Dream.DreamMessage]
  148.    #  $response
  149. )
  150. BEGIN {
  151.    if($InputObject) {
  152.       Write-Output $inputObject | Receive-Http $Output $Path
  153.    } # else they'd better pass it in on the pipeline ...
  154. }
  155. PROCESS {
  156.    $response = $null
  157.    if($_ -is [MindTouch.Dream.Result``1[[MindTouch.Dream.DreamMessage]]]) {
  158.       $response = $_.Wait()
  159.    } elseif($_ -is [MindTouch.Dream.DreamMessage]) {
  160.       $response = $_
  161.    } elseif($_) {
  162.       throw "We can only pipeline [MindTouch.Dream.DreamMessage] objects, or [MindTouch.Dream.Result`1[DreamMessage]] objects"
  163.    }
  164.    
  165.    if($response) {
  166.       Write-Debug $($response | Out-String)
  167.       if(!$response.IsSuccessful) {
  168.          Write-Error $($response | Out-String)
  169.          Write-Verbose $response.AsText()
  170.          throw "ERROR: '$($response.Status)' Response Status."
  171.       } else {  
  172.          switch($Output) {
  173.             "File" {
  174.                ## Joel's magic filename guesser ...
  175.                if(!$Path) {
  176.                   [string]$fileName = ([regex]'(?i)filename=(.*)$').Match( $response.Headers["Content-Disposition"] ).Groups[1].Value
  177.                   $Path = $fileName.trim("\/""'")
  178.                   if(!$Path) {
  179.                      $fileName = $response.ResponseUri.Segments[-1]
  180.                      $Path = $fileName.trim("\/")
  181.                      if(!([IO.FileInfo]$Path).Extension) {
  182.                         $Path = $Path + "." + $response.ContentType.Split(";")[0].Split("/")[1]
  183.                      }
  184.                   }
  185.                }
  186.                
  187.                $File = Get-FileName $Path
  188.                [StreamUtil]::CopyToFile( $response.AsStream(), $response.ContentLength, $File )
  189.                Get-ChildItem $File
  190.             }
  191.             "XDoc" {
  192.                if($Path) {
  193.                   $response.AsDocument()[$Path]
  194.                } else {
  195.                   $response.AsDocument()#.ToXml()
  196.                }
  197.             }
  198.             "Xml" {
  199.                if($Path) {
  200.                   $response.AsDocument().ToXml().SelectNodes($Path)
  201.                } else {
  202.                   $response.AsDocument().ToXml()
  203.                }
  204.             }
  205.             "Text" {
  206.                if($Path) {
  207.                   $response.AsDocument()[$Path] | % { $_.AsText }
  208.                } else {
  209.                   $response.AsText()
  210.                }
  211.             }
  212.             "Bytes" {
  213.                $response.AsBytes()
  214.             }
  215.          }
  216.       }
  217.    }
  218. }
  219. }
  220. ## http`://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
  221. ## Nobody actually uses HEAD or OPTIONS, right?
  222. ## And nobody's even heard of TRACE or CONNECT ;)
  223.  
  224. # CMDLET Invoke-Http {
  225. Function Invoke-Http {
  226. PARAM(
  227.    # [Parameter(Position=0, Mandatory=$false)]
  228.    # [ValidateSet("Post", "Get", "Put", "Delete", "Head", "Options")] ## There are other verbs, but we need a list to make sure you don't screw up
  229.    [string]$Verb = "Get"
  230. ,
  231.    # [Parameter(Position=1, Mandatory=$false, ValueFromPipeline=$true)]
  232.    # [string]
  233.    $Path
  234. ,
  235.    # [Parameter(Position=2, Mandatory=$false)]
  236.    [hashtable]$with
  237. ,
  238.    # [Parameter(Position=3, Mandatory=$false)]
  239.    $Content
  240. ,
  241.    $Type # Of Content
  242. ,
  243.    $authenticate
  244. ,
  245.    [switch]$waitForResponse
  246. )
  247. BEGIN {
  248.    $Verbs = "Post", "Get", "Put", "Delete", "Head", "Options"
  249.    if($Verbs -notcontains $Verb) {
  250.       Write-Warning "The specified verb '$Verb' is NOT one of the common verbs: $Verbs"
  251.    }
  252.  
  253.    if($Path) {
  254.       if($Content) {
  255.          Write-Output ($Path | Invoke-Http $Verb -With $With -Content $Content -Type $Type -Authenticate $authenticate -waitForResponse:$WaitForResponse)
  256.       } else {
  257.          Write-Output ($Path | Invoke-Http $Verb -With $With -Type $Type-Authenticate $authenticate -waitForResponse:$WaitForResponse)
  258.       }
  259.    } # else they'd better pass it in on the pipeline ...
  260. }
  261. PROCESS {
  262.    if($_) {
  263.       $Path = $_
  264.      
  265.       $plug = Get-DreamPlug $Path $With
  266.       Write-Verbose "Content Type: $Type"
  267.       Write-Verbose "Content: $Content"
  268.       ## Special Handling for FORM_URLENCODED
  269.       if($Type -like "Form*" -and !$Content) {
  270.          $dream = [MindTouch.Dream.DreamMessage]::Ok( $Plug.Uri )
  271.          $Plug = [MindTouch.Dream.Plug]::New( $Plug.Uri.SchemeHostPortPath )
  272.          Write-Verbose "RECREATED Plug: $($Plug.Uri.SchemeHostPortPath)"
  273.       } else {
  274.          $dream = Get-DreamMessage $Content $Type
  275.       }
  276.      
  277.       if(!$plug -or !$dream) {
  278.          throw "Can't come up with a request!"
  279.       }
  280.      
  281.       Write-Verbose $( $dream | Out-String )
  282.      
  283.       if($authenticate){
  284.             Write-Verbose "AUTHENTICATE AS $($authenticate.UserName)"
  285.          if($authenticate -is [System.Management.Automation.PSCredential]) {
  286.             Write-Verbose "AUTHENTICATING AS $($authenticate.UserName)"
  287.             $plug = $plug.WithCredentials($authenticate.UserName, ($authenticate.GetNetworkCredential().Password))
  288.          } elseif($authenticate -is [System.Net.NetworkCredential]) {
  289.             Write-Verbose "AUTHENTICATING AS $($authenticate.UserName)"
  290.             $plug = $plug.WithCredentials($authenticate.UserName, $authenticate.Password)
  291.          } else {
  292.             Get-HttpCredential
  293.             Write-Verbose "AUTHENTICATING AS $($authenticate.UserName)"
  294.             $plug = $plug.WithCredentials($global:HttpRestCredential.UserName, $global:HttpRestCredential.Password)
  295.          }
  296.       }
  297.      
  298.       Write-Verbose $plug.Uri
  299.      
  300.       ## DEBUG:
  301.       Write-Debug "URI: $($Plug.Uri)"
  302.       Write-Debug "Verb: $($Verb.ToUpper())"
  303.       Write-Debug $($dream | Out-String)
  304.      
  305.       $result = $plug.InvokeAsync( $Verb.ToUpper(),  $dream )
  306.      
  307.       Write-Debug $($result | Out-String)
  308.       #  if($DebugPreference -eq "Continue") {
  309.       #     Write-Debug $($result.Wait() | Out-String)
  310.       #  }
  311.      
  312.       if($waitForResponse) {
  313.          $result = $result.Wait()
  314.       }
  315.      
  316.      
  317.       write-output $result
  318.    
  319.       trap [MindTouch.Dream.DreamResponseException] {
  320.          Write-Error @"
  321. TRAPPED DreamResponseException
  322.      
  323. $($_.Exception.Response | Out-String)
  324.  
  325. $($_.Exception.Response.Headers | Out-String)
  326. "@
  327.          break;
  328.       }
  329.    }
  330. }
  331. }
  332.  
  333.  
  334. function Get-WebPageContent {
  335. #[CmdletBinding()]
  336. param(
  337. #   [Parameter(Position=0,Mandatory=$true)]
  338.    [string]$url
  339. ,
  340. #   [Parameter(Position=1,Mandatory=$false)]
  341.    [string]$xpath=""
  342. ,
  343. #   [Parameter(Mandatory=$false)]
  344.    [hashtable]$with=@{}
  345. ,
  346. #   [Parameter(Position=2,Mandatory=$false)]
  347.    [switch]$AsXml
  348. )
  349. BEGIN { $out = "Text"; if($AsXml) { $out="Xml" } }
  350. PROCESS {
  351.    invoke-http get $url $with | receive-http $out $xpath
  352. }
  353. }
  354.  
  355. new-alias gwpc Get-WebPageContent -EA "SilentlyContinue"
  356. new-alias http Invoke-Http        -EA "SilentlyContinue"
  357. new-alias rcv  Receive-Http       -EA "SilentlyContinue"
  358.  
  359.  
  360. # function Get-Http { return Invoke-Http "GET" @args }
  361. # function New-Http { return Invoke-Http "PUT" @args }
  362. # function Update-Http { return Invoke-Http "POST" @args }
  363. # function Remove-Http { return Invoke-Http "DELETE" @args }
  364. # new-alias Set-Http Update-Http
  365. # new-alias Put-Http New-Http
  366. # new-alias Post-Http Update-Http
  367. # new-alias Delete-Http Remove-Http
  368.  
  369. function Set-HttpDefaultUrl {
  370. PARAM ([uri]$baseUri=$(Read-Host "Please enter the base Uri for your RESTful web-service"))
  371.    $global:url = $baseUri
  372. }
  373.  
  374. function Set-HttpCredential {
  375.    param($Credential=$(Get-CredentialBetter -Title   "Http Authentication Request - $($global:url.Host)" `
  376.                                       -Message "Your login for $($global:url.Host)" `
  377.                                       -Domain  $($global:url.Host)) )
  378.    if($Credential -is [System.Management.Automation.PSCredential]) {
  379.       $global:HttpRestCredential = $Credential
  380.    } elseif($Credential -is [System.Net.NetworkCredential]) {
  381.       $global:HttpRestCredential = new-object System.Management.Automation.PSCredential $Credential.UserName, $(ConvertTo-SecureString $credential.Password)
  382.    }
  383. }
  384.  
  385. function Get-HttpCredential([switch]$Secure) {
  386.    if(!$global:url) { Set-HttpDefaultUrl }
  387.    if(!$global:HttpRestCredential) { Set-HttpCredential }
  388.    if(!$Secure) {
  389.       return $global:HttpRestCredential.GetNetworkCredential();
  390.    } else {
  391.       return $global:HttpRestCredential
  392.    }
  393. }
  394.  
  395. # function Authenticate-Http {
  396. # PARAM($URL=@("users","authenticate"), $Credential = $(Get-HttpCredential))
  397. #   $plug = [MindTouch.Dream.Plug]::New( $global:url )
  398. #   $null = $plug.At("users", "authenticate").WithCredentials( $auth.UserName, $auth.Password ).Get()
  399. # }
  400.  
  401.  
  402. function Encode-Twice {
  403.    param([string]$text)
  404.    return [System.Web.HttpUtility]::UrlEncode( [System.Web.HttpUtility]::UrlEncode( $text ) )
  405. }
  406.  
  407. function Join-Url ( [uri]$baseUri=$global:url ) {
  408.    $ofs="/";$BaseUrl = ""
  409.    if($BaseUri -and $baseUri.AbsoluteUri) {
  410.       $BaseUrl = "$($baseUri.AbsoluteUri.Trim('/'))/"
  411.    }
  412.    return [URI]"$BaseUrl$([string]::join("/",@($args)).TrimStart('/'))"
  413. }
  414.  
  415. function ConvertTo-SecureString {
  416. Param([string]$input)
  417.    $result = new-object System.Security.SecureString
  418.  
  419.    foreach($c in $input.ToCharArray()) {
  420.       $result.AppendChar($c)
  421.    }
  422.    $result.MakeReadOnly()
  423.    return $result
  424. }
  425.  
  426. ## Unit-Test Get-FileName  ## Should return TRUE
  427. ##   (Get-FileName C:\Windows\System32\Notepad.exe)               -eq "C:\Windows\System32\Notepad.exe"   -and
  428. ##   (Get-FileName C:\Windows\Notepad.exe C:\Windows\System32\)   -eq "C:\Windows\System32\Notepad.exe"   -and
  429. ##   (Get-FileName WaitFor.exe C:\Windows\System32\WaitForIt.exe) -eq "C:\Windows\System32\WaitForIt.exe" -and
  430. ##   (Get-FileName -Path C:\Windows\System32\WaitForIt.exe)       -eq "C:\Windows\System32\WaitForIt.exe"      
  431. function Get-FileName {
  432.    param($fileName=$([IO.Path]::GetRandomFileName()), $path)
  433.    $fileName = $fileName.trim("\/""'")
  434.    ## if the $Path has a file name, and it's folder exists:
  435.    if($Path -and !(Test-Path $Path -Type Container) -and (Test-Path (Split-Path $path) -Type Container)) {
  436.       $path
  437.    ## if the $Path is just a folder (and it exists)
  438.    } elseif($Path -and (Test-Path $path -Type Container)) {
  439.       $fileName = Split-Path $fileName -leaf
  440.       Join-Path $path $fileName
  441.    ## If there's no valid $Path, and the $FileName has a folder...
  442.    } elseif((Split-Path $fileName) -and (Test-Path (Split-Path $fileName))) {
  443.       $fileName
  444.    } else {
  445.       Join-Path (Get-Location -PSProvider "FileSystem") (Split-Path $fileName -Leaf)
  446.    }
  447. }
  448.  
  449. function Get-UtcTime {
  450.    Param($Format="yyyyMMddhhmmss")
  451.    [DateTime]::Now.ToUniversalTime().ToString($Format)
  452. }
  453.  
  454. ## Get-CredentialBetter
  455. ## An improvement over the default cmdlet which has no options ...
  456. ###################################################################################################
  457. ## History
  458. ## v 1.2 Refactor ShellIds key out to a variable, and wrap lines a bit
  459. ## v 1.1 Add -Console switch and set registry values accordingly (ouch)
  460. ## v 1.0 Add Title, Message, Domain, and UserName options to the Get-Credential cmdlet
  461. ###################################################################################################
  462. function Get-CredentialBetter{
  463. PARAM([string]$UserName, [string]$Title, [string]$Message, [string]$Domain, [switch]$Console)
  464.    $ShellIdKey = "HKLM:\SOFTWARE\Microsoft\PowerShell\1\ShellIds"
  465.    ## Carefully EA=SilentlyContinue because by default it's MISSING, not $False
  466.    $cp = (Get-ItemProperty $ShellIdKey ConsolePrompting -ea "SilentlyContinue")
  467.    ## Compare to $True, because by default it's $null ...
  468.    $cp = $cp.ConsolePrompting -eq $True
  469.  
  470.    if($Console -and !$cp) {
  471.       Set-ItemProperty $ShellIdKey ConsolePrompting $True
  472.    } elseif(!$Console -and $Console.IsPresent -and $cp) {
  473.       Set-ItemProperty $ShellIdKey ConsolePrompting $False
  474.    }
  475.  
  476.    ## Now call the Host.UI method ... if they don't have one, we'll die, yay.
  477.    $Host.UI.PromptForCredential($Title,$Message,$UserName,$Domain,"Generic","Default")
  478.  
  479.    ## BoyScouts: Leave everything better than you found it (I'm tempted to leave it = True)
  480.    Set-ItemProperty $ShellIdKey ConsolePrompting $cp
  481. }

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me