Commands/Protocols/HTTP-Protocol.ps1
function Protocol.HTTP { <# .SYNOPSIS HTTP protocol .DESCRIPTION Converts an http(s) protocol commands to PowerShell. .EXAMPLE .> { https://api.github.com/repos/StartAutomating/PipeScript } .EXAMPLE { get https://api.github.com/repos/StartAutomating/PipeScript } | .>PipeScript .EXAMPLE Invoke-PipeScript { $GitHubApi = 'api.github.com' $UserName = 'StartAutomating' https://$GitHubApi/users/$UserName } .EXAMPLE .> -ScriptBlock { https://$GitHubApi/users/$UserName -GitHubApi api.github.com -UserName StartAutomating } .EXAMPLE .> -ScriptBlock { https://$GitHubApi/users/$UserName -GitHubApi api.github.com -UserName StartAutomating } .EXAMPLE .> -ScriptBlock { @(foreach ($repo in https://api.github.com/users/StartAutomating/repos?per_page=100) { $repo | .Name .Stars { $_.stargazers_count } }) | Sort-Object Stars -Descending } .EXAMPLE $semanticAnalysis = Invoke-PipeScript { http://text-processing.com/api/sentiment/ -Method POST -ContentType 'application/x-www-form-urlencoded' -Body "text=amazing!" | Select-Object -ExpandProperty Probability -Property Label } $semanticAnalysis .EXAMPLE $statusHealthCheck = { [Https('status.dev.azure.com/_apis/status/health')] param() } | Use-PipeScript & $StatusHealthCheck #> [ValidateScript({ $commandAst = $_ if ($commandAst -isnot [Management.Automation.Language.CommandAst]) { return $false } # If neither command element contained a URI if (-not ($commandAst.CommandElements[0..1].Value -match '^https{0,1}://')) { return $false # return false } # If the first element is not the URI if ($commandAst.CommandElements[0].Value -notmatch '^https{0,1}://') { # then we are only valid if the first element is a WebRequestMethod return $commandAst.CommandElements[0].Value -in ( [Enum]::GetValues([Microsoft.PowerShell.Commands.WebRequestMethod]) -ne 'Default' ) } # If we're here, then the first element is a HTTP uri, return $true # so we return true. })] [Alias('HTTP','HTTPS')] param( # The URI. [Parameter(Mandatory,ValueFromPipeline,Position=0,ParameterSetName='Protocol')] [Parameter(Mandatory,ValueFromPipeline,Position=0,ParameterSetName='Interactive')] [Parameter(Mandatory,ParameterSetName='ScriptBlock',Position=0)] [uri] $CommandUri, # The Command's Abstract Syntax Tree [Parameter(Mandatory,ParameterSetName='Protocol')] [Management.Automation.Language.CommandAST] $CommandAst, [Parameter(Mandatory,ValueFromPipeline,ParameterSetName='ScriptBlock')] [ScriptBlock] $ScriptBlock = {}, # Any remaining arguments. These will be passed positionally to the invoker. [Parameter(ValueFromRemainingArguments)] $ArgumentList = @(), # Any named parameters for the invoker. [Parameter(ValueFromRemainingArguments)] [Collections.IDictionary] $Parameter = @{}, # The HTTP method. By default, get. [string] $Method = 'GET', # The invocation command. By default, Invoke-RestMethod. # Whatever alternative command provided should have a similar signature to Invoke-RestMethod. [string] $Invoker = 'Invoke-RestMethod' ) process { if (-not $commandUri.Scheme) { $uriScheme = if ($MyInvocation.InvocationName -eq 'http') { 'http' } else { 'https' } $commandUri = [uri]"${uriScheme}://$($commandUri.OriginalString -replace '://')" } if ($PSCmdlet.ParameterSetName -eq 'Protocol') { $commandArguments = @() + $CommandAst.ArgumentList $commandParameters = [Ordered]@{} + $CommandAst.Parameter $offset = 1 if ($Method -and $CommandAst -match "^$Method") { $offset = 2 } # we will parse our input as a sentence. $mySentence = $commandAst.AsSentence($MyInvocation.MyCommand,$offset) # Walk thru all mapped parameters in the sentence $myParams = [Ordered]@{} + $PSBoundParameters foreach ($paramName in $mySentence.Parameters.Keys) { if (-not $myParams.Contains($paramName)) { # If the parameter was not directly supplied $myParams[$paramName] = $mySentence.Parameters[$paramName] # grab it from the sentence. foreach ($myParam in $myCmd.Parameters.Values) { if ($myParam.Aliases -contains $paramName) { # set any variables that share the name of an alias $ExecutionContext.SessionState.PSVariable.Set($myParam.Name, $mySentence.Parameters[$paramName]) } } # set this variable for this value. $ExecutionContext.SessionState.PSVariable.Set($paramName, $mySentence.Parameters[$paramName]) } } $method = '' $commandName = if ($CommandAst.CommandElements[0].Value -match '://') { $commandAst.CommandElements[0].Value } else { $method = $commandAst.CommandElements[0].Value $commandArguments = $commandArguments[2..($commandArguments.Count + 1)] $commandAst.CommandElements[1].Value } $startIndex = 0 $partsToJoin = @( foreach ($match in [Regex]::Matches( $commandName, '(?> (?<Variable>\$\w+\:\w+) | (?<Variable>\$\w+) )', 'IgnoreCase, IgnorePatternWhitespace' ) ) { "'" + $commandName.Substring($startIndex, $match.Index - $startIndex).Replace("'", "''") + "'" $varMatch = $match.Groups["Variable"].Value $varName = $varMatch.TrimStart('$') if ($commandParameters[$varName]) { $varParameter = $commandParameters[$varName] $commandParameters.Remove($varName) if ($varParameter -is [string]) { "'" + $varParameter + "'" } elseif ($varParameter -is [ScriptBlock]) { "{$varParameter}" } else { $varParameter } } else { $varMatch } $startIndex = $match.Index + $match.Length } "'" + $commandName.Substring($startIndex).Replace("'", "''") + "'" ) $newScript = if ($partsToJoin.Count -gt 1) { "$Invoker ($($PartsToJoin -join ',') -join '')$(if ($method) {" -Method '$Method'"})" } else { "$Invoker $PartsToJoin$(if ($method) {" -Method '$Method'"})" } $newScript += @( foreach ($argument in $commandArguments) { if ($argument -is [string]) { "'" + $argument.Replace("'", "''") + "'" } elseif ($argument -is [scriptblock]) { "{" + $argument + "}" } else { "$argument" } } foreach ($param in $commandParameters.GetEnumerator()) { if ($param.Value -isnot [bool]) { "-$($param.Key)" } if ($param.Value -is [string]) { "'" + $param.Value.Replace("'", "''") + "'" } elseif ($param.Value -is [ScriptBlock]) { "{" + $param.Value + "}" } elseif ($param.Value -is [bool]) { if ($param.Value) { "-$($param.Key)" } else { "-$($param.Key):`$false" } } else { $param.Value } } ) -join ' ' [scriptblock]::Create($newScript) } elseif ($psCmdlet.ParameterSetName -eq 'ScriptBlock') { if (-not $scriptBlock.Ast.ParamBlock.Parameters.Count -and -not $scriptBlock.Ast.EndBlock.Statements.Count) { [scriptblock]::Create(" $Invoker '$CommandUri'$(if ($method) {" -Method '$Method'"}) ") } } elseif ($psCmdlet.ParameterSetName -eq 'Interactive') { if ($Method -and -not $parameter.Method) { $parameter.Method = $method } & $Invoker $commandUri @ArgumentList @Parameter } } } |