为变量转义 Powershell 中的所有密码特殊字符
Escaping all password special characters in Powershell for Variable
我有以下场景,运行在 Powershell v5 上运行:
一个 Powershell 脚本从一个 API 调用中提取几位信息到一个批量 for-each 循环中的第 3 方系统,并将它们分配给变量。提取的信息包括密码(这样做是为了摆脱上述第 3 方系统并将其迁移到不允许您以纯文本形式检索密码的系统):
$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("=")
然后在脚本的其他地方使用这些密码。
例如,它们被传递给不同的 API 并且需要采用 URL 兼容的格式,所以我 运行 这个:
$urlescapeduserpass = [uri]::EscapeDataString($userpass)
适用于脚本的该部分
问题是这些密码可以包含任何特殊字符:
!"#$%&'()*+,-./:;<=>?@[]^_`{|}~
并且当我调用脚本的另一部分时,密码字符串中的特殊字符导致失败并退出脚本。使用调用命令时会发生这种情况:
& .\application.exe --option1 $option1 --user1 $user --password1 $userpass
或使用 invoke-expression 时
$command = "$path\application.exe --option1 $option1 --user1 $user --password1 $userpass"
Invoke-Expression $command
我尝试使用 Regex,使用 -replace cmdlet:
$escapedpass = $userpass -replace ' !"#$%&()*+,-./:;<=>?@[\]^_`{|}~', '`$&'
但运气不好,我知道与 [uri]escapedatastring 类似,Regex 也有一个类似的字符串,但似乎没有 Powershell 的本地字符串。我确定有一个 [contenttype] 将具有本机函数来转义特殊字符或某种方式来实现最终结果。
让我们 create a Minimal, Reproducible Example with a round trip based on the answer from @mklement0 为此:
(也考虑到我刚刚在空格上发表的评论)
不幸的是,PowerShell 造成了额外的障碍,因为它需要对字符串进行单引号,否则它将解释其他字符以及美元符号 ($
)。我在代码中放置了注释,您可能会忽略它。
Password.ps1
Param (
[String]$Password
)
Write-Host $Password
密码检查:
$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)
结果:
Input: !"'#$%&()*+,-./:;<=>?@[\]^_`{|}~
Command: PowerShell .\Password.ps1 "' !\"''#$%&()*+,-./:;<=>?@[\]^_`{|}~'"
Output: !"'#$%&()*+,-./:;<=>?@[\]^_`{|}~
Input and output are equal? True
因为 PowerShell 对传递给 外部程序 的参数中嵌入的 "
字符的处理被破坏了(从 PowerShell 7 开始) - 请参阅 - 您需要 手动 \
-转义 "
个字符 嵌入到您的字符串中:
$escapedpass = $userpass -replace , '"', '\"'
在您的命令上下文中:
& .\application.exe --option1 $option1 --user1 $user --password1 ($userpass -replace , '"', '\"')
我有以下场景,运行在 Powershell v5 上运行:
一个 Powershell 脚本从一个 API 调用中提取几位信息到一个批量 for-each 循环中的第 3 方系统,并将它们分配给变量。提取的信息包括密码(这样做是为了摆脱上述第 3 方系统并将其迁移到不允许您以纯文本形式检索密码的系统):
$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("=")
然后在脚本的其他地方使用这些密码。
例如,它们被传递给不同的 API 并且需要采用 URL 兼容的格式,所以我 运行 这个:
$urlescapeduserpass = [uri]::EscapeDataString($userpass)
适用于脚本的该部分
问题是这些密码可以包含任何特殊字符: !"#$%&'()*+,-./:;<=>?@[]^_`{|}~
并且当我调用脚本的另一部分时,密码字符串中的特殊字符导致失败并退出脚本。使用调用命令时会发生这种情况:
& .\application.exe --option1 $option1 --user1 $user --password1 $userpass
或使用 invoke-expression 时
$command = "$path\application.exe --option1 $option1 --user1 $user --password1 $userpass"
Invoke-Expression $command
我尝试使用 Regex,使用 -replace cmdlet:
$escapedpass = $userpass -replace ' !"#$%&()*+,-./:;<=>?@[\]^_`{|}~', '`$&'
但运气不好,我知道与 [uri]escapedatastring 类似,Regex 也有一个类似的字符串,但似乎没有 Powershell 的本地字符串。我确定有一个 [contenttype] 将具有本机函数来转义特殊字符或某种方式来实现最终结果。
让我们 create a Minimal, Reproducible Example with a round trip based on the answer
(也考虑到我刚刚在空格上发表的评论)
不幸的是,PowerShell 造成了额外的障碍,因为它需要对字符串进行单引号,否则它将解释其他字符以及美元符号 ($
)。我在代码中放置了注释,您可能会忽略它。
Password.ps1
Param (
[String]$Password
)
Write-Host $Password
密码检查:
$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)
结果:
Input: !"'#$%&()*+,-./:;<=>?@[\]^_`{|}~
Command: PowerShell .\Password.ps1 "' !\"''#$%&()*+,-./:;<=>?@[\]^_`{|}~'"
Output: !"'#$%&()*+,-./:;<=>?@[\]^_`{|}~
Input and output are equal? True
因为 PowerShell 对传递给 外部程序 的参数中嵌入的 "
字符的处理被破坏了(从 PowerShell 7 开始) - 请参阅 \
-转义 "
个字符 嵌入到您的字符串中:
$escapedpass = $userpass -replace , '"', '\"'
在您的命令上下文中:
& .\application.exe --option1 $option1 --user1 $user --password1 ($userpass -replace , '"', '\"')