RestPS.psm1
Write-Verbose 'Importing from [C:\projects\restps\RestPS\private]' # .\RestPS\private\Invoke-AvailableRouteSet.ps1 function Invoke-AvailableRouteSet { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingInvokeExpression", '')] $script:Routes = @( @{ 'RequestType' = 'GET' 'RequestURL' = '/proc' 'RequestCommand' = 'get-process | select-object ProcessName' } @{ 'RequestType' = 'GET' 'RequestURL' = '/process' 'RequestCommand' = "endpoints\GET\Invoke-GetProcess.ps1" } @{ 'RequestType' = 'PUT' 'RequestURL' = '/Service' 'RequestCommand' = "endpoints\PUT\Invoke-GetProcess.ps1" } @{ 'RequestType' = 'POST' 'RequestURL' = '/data' 'RequestCommand' = "endpoints\POST\Invoke-GetProcess.ps1" } @{ 'RequestType' = 'DELETE' 'RequestURL' = '/data' 'RequestCommand' = "endpoints\DELETE\Invoke-GetProcess.ps1" } ) } # .\RestPS\private\Invoke-GetContext.ps1 function Invoke-GetContext { $script:context = $listener.GetContext() $Request = $Context.Request return $Request } # .\RestPS\private\Invoke-RequestRouter.ps1 function Invoke-RequestRouter { [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingInvokeExpression", '')] [OutputType([boolean])] [OutputType([Hashtable])] param( [Parameter(Mandatory = $true)][String]$RequestType, [Parameter(Mandatory = $true)][String]$RequestURL, [Parameter()][String]$RoutesFilePath ) # Import Routes each pass, to include new routes. Write-Output "Attempting process Request type: $RequestType on URL: $RequestURL" #Import the Endpoint Routes . $RoutesFilePath $Route = ($Routes | Where-Object {$_.RequestType -eq $RequestType -and $_.RequestURL -eq $RequestURL}) if ($null -ne $Route) { # Process Request $Command = $Route.RequestCommand set-location $PSScriptRoot Write-Output "Attempting process Request type: $RequestType on URL: $RequestURL" $CommandReturn = Invoke-Expression -Command $Command -ErrorAction SilentlyContinue if ($null -eq $CommandReturn) { # Not a valid response $script:result = "Invalid Command" } else { # Valid response $script:result = $CommandReturn } } else { # No matching Routes $ErrorMessage = "No Matching Routes" Write-Output $ErrorMessage $script:result = $ErrorMessage } $script:result } # .\RestPS\private\Invoke-StartListener.ps1 function Invoke-StartListener { param( [Parameter()][String]$Port = 8080 ) $listener.Prefixes.Add("http://+:$Port/") $listener.Start() Write-Output "Starting HTTP Listener on Port: $Port" } # .\RestPS\private\Invoke-StopListener.ps1 function Invoke-StopListener { param( [Parameter()][String]$Port = 8080 ) Write-Output "Stopping HTTP Listener on port: $Port ..." $listener.Stop() } # .\RestPS\private\Invoke-StreamOutput.ps1 function Invoke-StreamOutput { # Process the Return data to send Json message back. # Convert the data to UTF8 bytes $message = $script:result | ConvertTo-Json [byte[]]$buffer = [System.Text.Encoding]::UTF8.GetBytes($message) # Set length of response $response.ContentLength64 = $buffer.length # Write response out and close $output = $response.OutputStream $output.Write($buffer, 0, $buffer.length) $output.Close() } Write-Verbose 'Importing from [C:\projects\restps\RestPS\public]' # .\RestPS\public\Start-RestPSListener.ps1 function Start-RestPSListener { <# .DESCRIPTION Start a HTTP listener on a specified port. .EXAMPLE Start-Listener .EXAMPLE Start-Listener -Port 8081 .EXAMPLE Start-Listener -Port 8081 -RoutesFilePath C:\temp\customRoutes.ps1 .EXAMPLE Start-Listener -RoutesFilePath C:\temp\customRoutes.ps1 .PARAMETER Port A Port can be specified, but is not required, Default is 8080. .PARAMETER RoutesFilePath A Custom Routes file can be specified, but is not required, default is included in the module. .NOTES No notes at this time. #> [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = "Low" )] [OutputType([boolean])] [OutputType([Hashtable])] [OutputType([String])] param( [Parameter()][String]$RoutesFilePath = "null", [Parameter()][String]$Port = 8080 ) # No pre-task $script:Status = $true if ($pscmdlet.ShouldProcess("Starting HTTP Listener.")) { $script:listener = New-Object System.Net.HttpListener Invoke-StartListener -Port $Port # Run until you send a GET request to /end Do { # Capture requests as they come in (not Asyncronous) $script:Request = Invoke-GetContext # Request Handler Data $RequestType = $Request.HttpMethod $RequestURL = $Request.RawUrl # Setup a placeholder to deliver a response $script:response = $context.Response $result = $null # Break from loop if GET request sent to /shutdown if ($RequestURL -match '/shutdown$') { Write-Output "Received Request to shutdown Endpoint." $script:result = "Shutting down ReST Endpoint." $script:Status = $false } else { # Attempt to process the Request. Write-Output "Processing RequestType: $RequestType URL: $RequestURL" if ($RoutesFilePath -eq "null") { $RoutesFilePath = "Invoke-AvailableRouteSet" } $script:result = Invoke-RequestRouter -RequestType $RequestType -RequestURL $RequestURL -RoutesFilePath $RoutesFilePath } # Convert the returned data to JSON and set the HTTP content type to JSON Write-Output "The result is $script:result" $script:response.ContentType = 'application/json' # Stream the output back to requestor. Invoke-StreamOutput } while ($script:Status -eq $true) #Terminate the listener Invoke-StopListener -Port $Port return "Listener Stopped" } else { # -WhatIf was used. return $false } } Write-Verbose 'Importing from [C:\projects\restps\RestPS\classes]' |