我在XML文件中有数据,最终将用作注册表路径,该路径可能包含非打印字符(例如,将路径从网站复制到XML中时)。如果发现非打印字符,我想验证数据并抛出一个特定的错误。
在Powershell中,如果我在单引号中定义一个非打印字符的变量,然后test-Path
,它作为有效路径进行测试,因为非打印字符被作为文字处理。
Test-Path 'HKEY_LOCAL_MACHINESOFTWARETest`n@microsoft.com/GENUINE@microsoft.com/GENUINE' -isValid
同样的东西用双引号将"展开"。非打印字符并返回false,这正是我需要的。
Test-Path "HKEY_LOCAL_MACHINESOFTWARETest`n@microsoft.com/GENUINE@microsoft.com/GENUINE" -isValid
我发现[string]::Format(()
被用来扩展非打印字符,但是
$invalidPath = 'HKEY_LOCAL_MACHINESOFTWARETest`n@microsoft.com/GENUINE@microsoft.com/GENUINE'
[string]::Format("{0}",$invalidPath)
不按预期展开非打印字符。我也看到使用Invoke-Expression
的参考,但这是不安全的,也不是一个选择。
最后我发现$ExecutionContext.InvokeCommand.ExpandString()
,这似乎工作,
$ExecutionContext.InvokeCommand.ExpandString('HKEY_LOCAL_MACHINESOFTWARETest`n@microsoft.com/GENUINE@microsoft.com/GENUINE')
返回一个多行字符串到控制台,而$ExecutionContext.InvokeCommand.ExpandString('Write-Host "Screwed"')
将实际字符串返回到控制台,而不是实际执行Write-Host
,只将Screwed
返回到控制台。
最后,
$invalidPath = 'HKEY_LOCAL_MACHINESOFTWARETest`n@microsoft.com/GENUINE@microsoft.com/GENUINE'
Test-Path ($ExecutionContext.InvokeCommand.ExpandString($invalidPath)) -isValid
按预期返回false。这让我认为这是要追求的正确方法,但考虑到其他地方的所有陷阱,我想100%确定这种方法没有办法被用作安全弱点。我是在正确的轨道上,还是有我的Google-Fu还没有发现的问题?
和Invoke-Expression
一样,$ExecutionContext.InvokeCommand.ExpandString()
也容易被注入不需要的命令,只是在后一种情况下,这些命令只有包含在$(...)
(子表达式操作符)中才能被识别,因为这是将命令嵌入可扩展字符串(方法的参数被解释为)的唯一方法。
例如:
$ExecutionContext.InvokeCommand.ExpandString('a $(Write-Host -Fore Red Injected!) b')
防止这种情况的一个简单方法是对所有嵌入的$
字符进行分类处理。逐字,通过使用`
:
转义'a $(Write-Host -Fore Red Injected!) b',
'There''s no place like $HOME',
'Too `$(Get-Date) clever by half' |
ForEach-Object {
$ExecutionContext.InvokeCommand.ExpandString(($_ -replace '(`*)$', '$1$1`$$'))
}
注意:在输入字符串中转义逐字 当然,如果存在命令(或变量值)注入的风险,您可以选择报告错误,这可以简单地像: 然而,这也阻止了在路径中合法使用逐字 退一步: 您声明路径可能是从网站复制粘贴过来的。这样一个粘贴的字符串可能确实包含(也许是隐藏的)控制字符,但是它们将被逐字包含而不是PowerShell_escape序列。 因此,可能足以测试/悄悄地从字符串的文字内容中删除控制字符(在调用$
就足够了。$
(或(
/)
) (`u{24}
(或`u{28}
/`u{29}
),在PowerShell (Core) v6+仅支持)的Unicode转义序列表示中,不需要关注,因为PowerShell将生成的字符逐字处理。$path = 'There''s no place like $HOME'
if ($path -match '$') { Throw 'Unsupported characters in path.' }
$
。Test-Path -IsValid
之前):# Test for control characters.
if ($path -match 'p{C}') { throw 'Path contains control characters.' }
# Quietly remove them.
$sanitizedPath = $path -replace 'p{C}'
我最初运行的是PS 7.1.3版本,其中所有这些方法都具有相同的结果。
当我跑步时:
$invalidPath = 'HKEY_LOCAL_MACHINESOFTWARETest`n@microsoft.com/GENUINE@microsoft.com/GENUINE'
Test-Path ($ExecutionContext.InvokeCommand.ExpandString($invalidPath)) -isValid
返回True
一样:
Test-Path ([regex]::Escape($invalidPath)) -IsValid
以及你提到的其他方法。
在5.1的测试中,我看到了和你一样的结果。
在XML中,您会看到`n
或n
或实际的非打印字符吗?即'HKEY_LOCAL_MACHINESOFTWARETest`n@microsoft.com/GENUINE@microsoft.com/GENUINE'
或
'HKEY_LOCAL_MACHINESOFTWARETest
@microsoft.com/GENUINE@microsoft.com/GENUINE'
如果后者为真,您应该能够将字符串传递给Test-Path "$invalidPath" -IsValid
等变量中的test-path以获得您正在寻找的内容。在7.1.3(可能更早)中,PS似乎足够聪明,可以解析这些转义序列之类的——或者没有简单的方法可以做你正在寻找的事情,我可以找到。