通过一些额外的安全预防措施和防止无意的字符串外推,您可以将Invoke-Expression 与Write-Output 结合使用,但请注意Invoke-Expression should generally be avoided:
$fieldList = '"Miller, Steve", "Zappa, Frank", "Johnson, Earvin ""Magic""", "Honey, I''m $HOME"'
# Parse into array.
$fields = (
Invoke-Expression ("Write-Output -- " + ($fieldList -replace '\$', "`0"))
) -replace "`0", '$$'
注意:
-
-replace '\$', "`0" 临时替换文字 $ 字符。在带有 NUL 字符的输入中。防止意外(或恶意)string expansion (interpolation);第二个-replace 操作恢复原来的$ 字符。
有关基于正则表达式的-replace 运算符的更多信息,请参阅this answer。
-
将Write-Output -- 添加到结果字符串并通过Invoke-Expression 将结果解释为PowerShell 命令 导致Write-Output 将字符串的其余部分解析为单独的参数并按原样输出。 -- 确保任何碰巧看起来像 Write-Output 的 自己的 参数的参数都不被这样解释。
-
当且仅当保证输入字符串永远不会包含嵌入的$ 字符,解决方案可以简化为:
$fields = Invoke-Expression "Write-Output -- $fieldList"
输出$fields 会产生以下结果:
Miller, Steve
Zappa, Frank
Johnson, Earvin "Magic"
Honey, I'm $HOME
约束说明和列表:
解决方案依赖于将输入字符串作为 string 的一部分,其 content 是语法上有效的 Write-Output 调用,输入字符串用作后者的 参数。 Invoke-Expression 然后评估此字符串,就好像它的内容已直接作为命令提交,因此执行Write-Output 命令。根据 PowerShell 解析命令参数的方式,这意味着以下约束:
-
支持的字段分隔符:
-
嵌入字段的非/引用:
-
字段可以被引用:
-
字段也可以不加引号:
-
但是,此类字段不得包含任何 PowerShell 参数模式元字符(其中,< > @ # 只是令牌开始处的元字符):
<space> ' " ` , ; ( ) { } | & < > @ #
替代方案,通过ConvertFrom-Csv:
iRon's helpful answer 显示基于ConvertFrom-Csv 的解决方案,假设输入字符串中嵌入的字段列表是逗号-分隔的(,):
使解决方案尴尬的是需要预测最大值。嵌入字段的数量并为它们提供虚拟标题(列名)(-Header (0..99))以使ConvertFrom-Csv工作,这既脆弱又可能造成浪费。 p>
但是,一个简单的技巧可以绕过这个问题:提交输入字符串两次,在这种情况下ConvertFrom-Csv 将输入字符串中的字段同时视为列名和 em> 作为唯一输出行(对象)的列值,然后可以查询其值:
$fieldList = '"Miller, Steve", "Zappa, Frank", "Johnson, Earvin ""Magic""", "Honey, I''m $HOME"'
# Creates the same array as the solution at the top.
$fields = ($fieldList, $fieldList | ConvertFrom-Csv).psobject.Properties.Value