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
#>