Neptune443

PowerShell WebServer

Jan 12th, 2014
600
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. Function Invoke-WebServer {
  2.     [cmdletbinding()]
  3.     param(
  4.         $URL = 'http://localhost:9092/',
  5.         $AuthenticationSchemes = "Negotiate",
  6.         $RunspacesCount = 4,
  7.         [scriptblock]$ProcessRequest={},
  8.         [System.Management.Automation.Runspaces.InitialSessionState]$InitialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
  9.     )
  10.     $script:InitialSessionState = $InitialSessionState
  11.     $listener = New-Object System.Net.HttpListener
  12.     $listener.Prefixes.Add($url)
  13.     $listener.AuthenticationSchemes = $authenticationSchemes
  14.     $listener.Start()
  15.  
  16.     Write-Verbose "Starting up a runspace pool of $RunspacesCount runspaces"
  17.     $pool = [runspacefactory]::CreateRunspacePool(2, $RunspacesCount)  
  18.     $pool.Open()
  19.  
  20.     Function Add-SessionStateVariable {
  21.         param($Name)
  22.         $var = Get-Item "variable:\$name"
  23.         $variable = New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry $var.Name,$var.Value,$null
  24.         $script:InitialSessionState.Variables.Add($variable)
  25.     }
  26.  
  27.     $VerboseMessageQueue = [System.Collections.Queue]::Synchronized((new-object Collections.Queue))
  28.     $RequestHandler = {
  29.         param(
  30.             $Context,
  31.             $VerboseMessageQueue,
  32.             $ProcessRequest
  33.         )
  34.         # Add types so that we get some intellisense help while coding
  35.         [System.Net.HttpListenerRequest]$Request    = $context.Request
  36.         [System.Net.HttpListenerResponse]$Response  = $context.Response
  37.         [System.Security.Principal.IPrincipal]$User = $context.User
  38.  
  39.         $VerboseMessageQueue.Enqueue("User $($Context.User.Identity.Name) sent a request")
  40.         $length = $Request.ContentLength64
  41.         $buffer = New-Object "byte[]" $length
  42.         [void]$Request.InputStream.Read($buffer,0,$length)
  43.         $requestBody = [System.Text.Encoding]::UTF8.GetString($buffer)
  44.         $requestObject = $requestBody | ConvertFrom-Json
  45.         $context.Response | Add-Member -Name ResponseFile -MemberType NoteProperty -Value $null -Force
  46.         $context.Request  | Add-Member -Name RequestBody -MemberType NoteProperty -Value $requestBody -Force
  47.         $context.Request  | Add-Member -Name RequestObject -MemberType NoteProperty -Value $requestObject -Force
  48.         try {
  49.             $result = .$ProcessRequest $context $VerboseMessageQueue
  50.             if($context.Response.ResponseFile) {
  51.                 $buffer = [System.IO.File]::ReadAllBytes($context.Response.ResponseFile)
  52.                 $response.ContentLength64 = $buffer.Length
  53.                 $response.OutputStream.Write($buffer, 0, $buffer.Length)
  54.             } elseif($context.Response.ContentLength64 -eq 0){
  55.                 if($result) {
  56.                     $jsonResponse = $result | ConvertTo-Json
  57.                     $buffer = [System.Text.Encoding]::UTF8.GetBytes($jsonResponse)
  58.                     $response.ContentLength64 = $buffer.Length
  59.                     $response.OutputStream.Write($buffer, 0, $buffer.Length)
  60.                 }
  61.             }
  62.             $response.close()
  63.         } catch {
  64.             $Context.Response.StatusRequestHandler = "500"
  65.             $response.close()
  66.         }
  67.     }
  68.     $RequestListener = {
  69.         param(
  70.             $listener,
  71.             $pool,
  72.             $VerboseMessageQueue,
  73.             $RequestHandler,
  74.             $ProcessRequest,
  75.             $InitialSessionState
  76.         )
  77.         $VerboseMessageQueue.Enqueue("Waiting for request")
  78.         $psWorker = [powershell]::Create($InitialSessionState)
  79.         $context = $listener.GetContext()
  80.         $psWorker.RunspacePool = $pool
  81.         [void]$psWorker.AddScript($RequestHandler.ToString())
  82.         [void]$psWorker.AddArgument($context)
  83.         [void]$psWorker.AddArgument($VerboseMessageQueue)
  84.         [void]$psWorker.AddArgument($ProcessRequest)
  85.         [void]$psWorker.BeginInvoke()
  86.     }
  87.    
  88.     try {
  89.         Write-Verbose "Server listening on $url"
  90.         while ($listener.IsListening)
  91.         {
  92.             if($iasync -eq $null -or $iasync.IsCompleted) {
  93.                 $obj = New-Object object
  94.                 $ps = [powershell]::Create($InitialSessionState)
  95.                 $ps.RunspacePool = $pool
  96.                 [void]$ps.AddScript($RequestListener.ToString())
  97.                 [void]$ps.AddArgument($listener)
  98.                 [void]$ps.AddArgument($pool)
  99.                 [void]$ps.AddArgument($VerboseMessageQueue)
  100.                 [void]$ps.AddArgument($Requesthandler)
  101.                 [void]$ps.AddArgument($ProcessRequest)
  102.                 [void]$ps.AddArgument($InitialSessionState)
  103.                 $iasync = $ps.BeginInvoke()
  104.             }
  105.             while($VerboseMessageQueue.count -gt 0){
  106.                 Write-Verbose $VerboseMessageQueue.Dequeue()
  107.             }                
  108.             Start-Sleep -Milliseconds 30
  109.         }
  110.     } finally {
  111.         Write-Verbose "Closing down server"
  112.         $listener.Stop()
  113.         $listener.Close()
  114.     }
  115. }
  116.  
  117. # Create a simple html file
  118. "<html><body>Hej</body></html>" | Out-File c:\ps\out.html -Encoding utf8
  119.  
  120. # Sample server, serving up a single file in /file and
  121. Invoke-WebServer -URL "http://*:8080/" -AuthenticationSchemes negotiate -ProcessRequest {
  122.     param(
  123.         $context,
  124.         $VerboseMessageQueue
  125.     )
  126.     $VerboseMessageQueue.Enqueue("::Request::")
  127.     $VerboseMessageQueue.Enqueue($($context.Request | out-string))
  128.    
  129.     if($context.request.url.localpath -eq "/json" -and $context.request.httpmethod -eq "get") {
  130.         $VerboseMessageQueue.Enqueue($($context.request.requestobject | out-string))
  131.         [pscustomobject]@{
  132.             Sequence = @(3,2,1)
  133.             Strings = @("red","blue","green")
  134.         }
  135.     }
  136.     if($context.request.url.localpath -eq "/json" -and $context.request.httpmethod -eq "post") {
  137.         $VerboseMessageQueue.Enqueue($($context.request.requestobject | out-string))
  138.         [pscustomobject]@{
  139.             Sequence = @(3,3,3)
  140.             Strings = @("PUT","GET","POST")
  141.         }
  142.     }
  143.     if($context.request.url.localpath -eq "/file") {
  144.         $context.response.ResponseFile = "c:\ps\out.html"
  145.         $context.response.contenttype = "text/html"
  146.     }
  147. } -Verbose
  148.  
  149.  
  150.  
  151. # Sample client calls
  152.  
  153. # Simple Get JSON
  154. Invoke-RestMethod -Method get -Uri 'http://localhost:8080/json' -UseDefaultCredentials
  155.  
  156. # Post JSON to the webserver
  157. $data = [pscustomobject]@{
  158.     Sequence = @(1,2,3,4)
  159.     Strings = @("Orange","yellow","black")
  160. }
  161. $postData = $data | ConvertTo-Json
  162. Invoke-RestMethod -Method post -Uri 'http://localhost:8080/json' -UseDefaultCredentials -Body $postData
  163.  
  164. # Request a file
  165. Invoke-RestMethod -Method get -Uri 'http://localhost:8080/file' -UseDefaultCredentials
Advertisement
Add Comment
Please, Sign In to add comment