如何防止(序列化)表达式展开

时间:2019-06-29 10:49:53

标签: powershell expression deserialization unroll

由于使用PowerShell表达式模式,PowerShell提供了一些不错的方法来反序列化对象,例如:

我的一般期望是,给定表达式的结果应与在该表达式的相同序列化版本上使用上面列出的反序列化命令之一相同(有关背景,请参见{ {3}}问题。
换句话说:

<Expression> <=> Invoke-Command {<Expression>} <=> &([ScriptBlock]::Create('<Expression>'))
<Expression> <=> Invoke-Expression '<Expression>'

示例:

Get-ChildItem <=> &{Get-ChildItem}
Get-ChildItem <=> Invoke-Command {Get-ChildItem}
Get-ChildItem <=> Invoke-Expression 'Get-ChildItem'

1, 2, 3 <=> &{1, 2, 3}
1, 2, 3 <=> Invoke-Command {1, 2, 3}
1, 2, 3 <=> Invoke-Expression '1, 2, 3'

对于每个表达式而言,这确实确实适用,但是由于PowerShell默认情况下会展开(枚举)输出,因此在表达式包含具有单个项目的数组的情况下,此定义会有所不同:

,1 <≠> Invoke-Command {,1}
,1 <≠> Invoke-Expression ',1'
,"Test" <≠> Invoke-Command {,"Test"}
,"Test" <≠> Invoke-Expression ',"Test"'
@("Test") <≠> Invoke-Command {@("Test")}
@("Test") <≠> Invoke-Expression '@("Test")'
,@("Test") <≠> Invoke-Command {,@("Test")}
,@("Test") <≠> Invoke-Expression ',@("Test")'

是否有一种方法可以防止在无论如何调用(反序列化)表达式时都将其展开?

我正在考虑为ConvertTo-Expression上的-NoEnumerate请求一个Invoke-Expression参数(类似于'Save hash table in PowerShell object notation (PSON)' cmdlet),但这仍然会保留不支持参数的呼叫运营商和网点采购的问题/问题...

1 个答案:

答案 0 :(得分:0)

我找到了一种解决方法,以防止默认展开(序列化的)表达式:
将表达式包装在哈希表中

<Expression> <=> (Invoke-Command {@{e=<Expression>}})['e']
<Expression> <=> (Invoke-Expression '@{e=<Expression>}')['e']

示例:

Get-ChildItem <=> (Invoke-Command {@{e=Get-ChildItem}})['e']
Get-ChildItem <=> (Invoke-Expression '@{e=Get-ChildItem}')['e']

1, 2, 3 <=> (Invoke-Command {@{e=1, 2, 3}})['e']
1, 2, 3 <=> (Invoke-Expression '@{e=1, 2, 3}')['e']

,1 <=> (Invoke-Command {@{e=,1}})['e']
,1 <=> (Invoke-Expression '@{e=,1}')['e']

我在ConvertFrom-Expression cmdlet中进一步实现了此功能,  具有以下功能:

  • -NoEnumerate开关可防止具有单个项目的阵列展开
  • -NoNewScope开关类似于Invoke-Command
  • 通过管道或-Expression自变量
  • 多个脚本块和/或字符串项

ConvertFrom-Expression示例:

PS C:>'2*3', {3*4}, '"Test"' | ConvertFrom-Expression
6
12
Test

PS C:> (ConvertFrom-Expression ',"Test"' -NoEnumerate) -Is [Array]
True