TheDemonLord
TheDemonLord

Reputation: 381

Escaping all password special characters in Powershell for Variable

I have the following scenario, running on Powershell v5:

A Powershell script pulls several bits of information from an API call to a 3rd party system in a bulk for-each loop and assigns them to Variables. Amongst the information that is pulled is Passwords (this is being done to get rid of said 3rd party system and to migrate it to something that doesn't allow you to retrieve passwords in plain text):

$userset = Invoke-WebRequest -Method Post -Uri "https://$Url/path/to/api.asmx" -Headers $Headers -Body $usercall

$xmluserset = [xml] $userset.Content

$userset2 = $xmluserset.Envelope.Body.UserSettingsResult.settingValues.string

$userpasstemp = $userset2[1].trimstart("password")
$userpass = $userpasstemp.trimstart("=")

These passwords are then used elsewhere in the Script.

For example, they are passed to a different API and need to be in a URL compatible format and so I run this:

$urlescapeduserpass = [uri]::EscapeDataString($userpass)

which works for that section of the Script

The problem is that these passwords can contain any of the special characters: !"#$%&'()*+,-./:;<=>?@[]^_`{|}~

And when I call another part of the script, the special characters in the password string cause a failure and the script to exit. This occurs when using either the call command:

& .\application.exe --option1 $option1 --user1 $user --password1 $userpass

or when using invoke-expression

$command = "$path\application.exe  --option1 $option1 --user1 $user --password1  $userpass"
Invoke-Expression $command

I've tried using Regex, using the -replace cmdlet:

$escapedpass = $userpass -replace ' !"#$%&()*+,-./:;<=>?@[\]^_`{|}~', '`$&'

But no luck, I know similar to the [uri]escapedatastring, there's a similar one for Regex, but there doesn't appear to be one native for Powershell. I'm sure there is either a [contenttype] that will have a native function to escape the special characters or some way to achieve the end-result.

Upvotes: 1

Views: 16201

Answers (2)

iRon
iRon

Reputation: 23763

Let's create a Minimal, Reproducible Example with a round trip based on the answer How to escape special characters in PowerShell? from @mklement0 for this:
(Also take the comment in account that I just made on spaces)

Unfortunately, PowerShell creates an extra handicap as it requires to single quote the string otherwise it will interpret other characters along with the dollar sign ($). I have placed comments in the code where you might leave this out.

Password.ps1

Param (
    [String]$Password
)
Write-Host $Password

Password check:

$Input = @'
 !"'#$%&()*+,-./:;<=>?@[\]^_`{|}~
'@

 

Write-Host 'Input:' $Input
$Escape = $Input.Replace('"', '\"')
$Escape = $Escape.Replace("'", "''") # Only required for PowerShell
Write-Host 'Command:' PowerShell .\Password.ps1 "'$Escape'"
# Omit the inner single quotes if it doesn't concern PowerShell
# But note that your .\application.exe might have its own syntax
# to support spaces and special characters from the command line,
# like double quotes: """$Escape"""
$Output = & PowerShell .\Password.ps1 "'$Escape'"
Write-Host 'Output:' $Output
Write-Host 'Input and output are equal?' ($Input -eq $Output)

Results:

Input:  !"'#$%&()*+,-./:;<=>?@[\]^_`{|}~
Command: PowerShell .\Password.ps1 "' !\"''#$%&()*+,-./:;<=>?@[\]^_`{|}~'"
Output:  !"'#$%&()*+,-./:;<=>?@[\]^_`{|}~
Input and output are equal? True

Upvotes: 1

mklement0
mklement0

Reputation: 439238

Because PowerShell's handling of embedded " characters in argument passed to external programs is broken (as of PowerShell 7) - see this answer - you need to manually \-escape " characters embedded in your string:

$escapedpass = $userpass -replace , '"', '\"'

In the context of your command:

& .\application.exe --option1 $option1 --user1 $user --password1 ($userpass -replace , '"', '\"')

Upvotes: 2

Related Questions