Recently I posted an article showing how to prevent Invoke-RestMethod from unescaping dots and slashes. Soon after that I got a great advice from Dave Wyatt, moderator for powershell.org forum. What he suggested was to create a proxy function around [Invoke-RestMethod](http://technet.microsoft.com/en-us/Library/hh849971.aspx) cmdlet which will disable UnEscapingDotsAndSlashes when the call is made. After some reading about proxy functions in PowerShell [1] [2] (I couldn’t believe how easy it is to create proxy function in PowerShell) I decided on creating a proxy function which will extend [Invoke-RestMethod](http://technet.microsoft.com/en-us/Library/hh849971.aspx) cmdlet with an extra parameter AllowEscapedDotsAndSlashes. Setting it to true will disable UnEscapingDotsAndSlashes for the time the call to the server is made and then switch back to original setting. This approach restricts intrusion to selected call only, minimising chances of breaking other existing code.

You would use it as follow:

$secpasswd = ConvertTo-SecureString 'guest' -AsPlainText -Force
$c = New-Object System.Management.Automation.PSCredential ('guest', $secpasswd)

Invoke-RestMethod -Credential $c -AllowEscapedDotsAndSlashes 'http://localhost:15672/api/queues/%2f/t1'

Invoke-RestMethod proxy function

Below is the code of [Invoke-RestMethod](http://technet.microsoft.com/en-us/Library/hh849971.aspx) proxy function:

function Invoke-RestMethod
{
    [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=217034')]
    param(
        [Microsoft.PowerShell.Commands.WebRequestMethod]
        ${Method},

        [Parameter(Mandatory=$true, Position=0)]
        [ValidateNotNullOrEmpty()]
        [uri]
        ${Uri},

        [Microsoft.PowerShell.Commands.WebRequestSession]
        ${WebSession},

        [Alias('SV')]
        [string]
        ${SessionVariable},

        [pscredential]
        ${Credential},

        [switch]
        ${UseDefaultCredentials},

        [ValidateNotNullOrEmpty()]
        [string]
        ${CertificateThumbprint},

        [ValidateNotNull()]
        [System.Security.Cryptography.X509Certificates.X509Certificate]
        ${Certificate},

        [string]
        ${UserAgent},

        [switch]
        ${DisableKeepAlive},

        [int]
        ${TimeoutSec},

        [System.Collections.IDictionary]
        ${Headers},

        [ValidateRange(0, 2147483647)]
        [int]
        ${MaximumRedirection},

        [uri]
        ${Proxy},

        [pscredential]
        ${ProxyCredential},

        [switch]
        ${ProxyUseDefaultCredentials},

        [Parameter(ValueFromPipeline=$true)]
        [System.Object]
        ${Body},

        [string]
        ${ContentType},

        [ValidateSet('chunked','compress','deflate','gzip','identity')]
        [string]
        ${TransferEncoding},

        [string]
        ${InFile},

        [string]
        ${OutFile},

        [switch]
        ${PassThru},

        [switch]
        ${AllowEscapedDotsAndSlashes})

    begin
    {
        try {
            $outBuffer = $null
            if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
            {
                $PSBoundParameters['OutBuffer'] = 1
            }
            
            $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Utility\Invoke-RestMethod', [System.Management.Automation.CommandTypes]::Cmdlet)

            # check whether need to disable UnEscapingDotsAndSlases on UriParser
            $requiresDisableUnEscapingDotsAndSlashes = ($AllowEscapedDotsAndSlashes -and $Uri.OriginalString -match '%2f')
            # remove additional proxy parameter to prevent original function from failing
            if($PSBoundParameters['AllowEscapedDotsAndSlashes']) { $null = $PSBoundParameters.Remove('AllowEscapedDotsAndSlashes') }

            $scriptCmd = {& $wrappedCmd @PSBoundParameters }
            $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
            $steppablePipeline.Begin($PSCmdlet)
        } catch {
            throw
        }
    }

    process
    {
        try {
            # Disable UnEscapingDotsAndSlashes on UriParser when necessary
            if ($requiresDisableUnEscapingDotsAndSlashes) {
                $getSyntax = [System.UriParser].GetMethod("GetSyntax", 40)
                $flags = [System.UriParser].GetField("m_Flags", 36)

                $parser = $getSyntax.Invoke($null, "http")
                $v = $flags.GetValue($parser)

                $flags.SetValue($parser, $v -bxor 0x2000000)
            }

            $steppablePipeline.Process($_)
        } catch {
            throw
        }
        finally {
            # Restore UnEscapingDotsAndSlashes on UriParser when necessary
            if ($requiresDisableUnEscapingDotsAndSlashes) {
                $getSyntax = [System.UriParser].GetMethod("GetSyntax", 40)
                $flags = [System.UriParser].GetField("m_Flags", 36)

                $parser = $getSyntax.Invoke($null, "http")
                $v = $flags.GetValue($parser)

                $flags.SetValue($parser, $v -bxor 0x2000000)
            }
        }
    }

    end
    {
        try {
            $steppablePipeline.End()
        } catch {
            throw
        }
    }
}

<#
.ForwardHelpTargetName Invoke-RestMethod
.ForwardHelpCategory Cmdlet
#>

References


  1. Extending and/or Modifing Commands with Proxies ↩︎

  2. Proxy Functions: Spice Up Your PowerShell Core Cmdlets ↩︎