powershell psobject显示为字符串而不是psobject,如何转换回psobject
Posted
技术标签:
【中文标题】powershell psobject显示为字符串而不是psobject,如何转换回psobject【英文标题】:powershell psobject showing as string instead of psobject, how to convert back to psobject 【发布时间】:2022-01-06 12:27:09 【问题描述】:我将以下变量 $Obj
设置为以下字符串值:
$Obj = '@Version=1; Name=a;'
如何将此值从字符串转换为自定义 psobject?
我希望能够打电话
$Obj.Version
并获取值 1。目前此调用不返回任何内容。
注意:由于我检索此变量的方式,如果没有单引号,我无法对其进行初始化。
编辑:
这是当前代码:
$Command = "script.ps1 -ExtraInfo $_"
Write-Host $Command
Invoke-Expression -Command $Command
$_
是 @Version=1; Name=a;
(不带引号)
原来这段代码是这样写的
. script.ps1 -ExtraInfo $_
并且工作,但是当我添加单元测试时,我将其更改为使用 Invoke-Expression,以便可以使用 Pester 单元测试对其进行测试。有没有更好的办法?
编辑2:
事实证明,这可以通过在表达式前加上一个反引号 ` 来解决,这为我解决了这个问题。谢谢大家的意见。
$Command = "script.ps1 -ExtraInfo `$_"
Write-Host $Command
Invoke-Expression -Command $Command
【问题讨论】:
请告诉我们$Obj
是如何生成的,以及为什么没有单引号就不能初始化它。
这确实是一个奇怪的情况,我不禁相信可以在代码库中更早地解决它
编辑了我的问题以显示更多信息。到目前为止,感谢您的 cmets。
不确定 pester 是如何工作的,从不关心它的使用,但 . script.ps1 -ExtraInfo $_
看起来比 iex
好得多。
在 Pester 方面有经验的人可能会给你一个替代你正在做的事情的方法,我认为 不应该在任何情况下都需要使用 iex
(除非非常利基)。如果您想获得“编码最佳实践”的答案,我建议您添加 Pester 代码以及 script.ps1
的最小示例(至少是 param(...)
块)。此外,在您的问题中添加pester 标签。
【参考方案1】:
[pscustomobject]
实例的字符串化版本类似于哈希表文字,不适合编程处理,如下所示示例演示:
# Stringify a [pscustomobject] instance.
PS> "$([pscsutomobject] @ Version=1; Name='a value' )"
@Version=1; Name=a value # !! Quoting of the .Name value was lost
对于本身就是复杂对象的属性值,问题会变得更糟。
由于您似乎确实可以访问原始 [pscustomobject]
实例,解决方案不字符串化。
为此,您只需使用verbatim (single-quoted) string literal ('...'
) 并让Invoke-Expression
- which should generally be avoided - 解释$_
变量来避免预先 字符串插值作为它的原始类型:
# Use *single* quotes to prevent up-front expansion.
$Command = 'script.ps1 -ExtraInfo $_'
Write-Host $Command
Invoke-Expression -Command $Command
请注意,逐字(非插值)字符串文字的使用使得Invoke-Expression
的使用在这里安全,但正如Santiago Squarzon 指出的那样,可能存在总体上更好的替代方案,尤其是在 Pester 的情况下。
一个script-block-based 解决方案 ( ...
) 接收对象作为参数:
$Command = script.ps1 -ExtraInfo $args[0]
Write-Host "Calling $Command with argument $_"
. $Command $_
【讨论】:
【参考方案2】:这不适用于Name=a
,因为a
不是已知对象(或至少未在我的 PS 会话中定义)。但如果这是一个字符串,则可以使用以下脚本来完成:
$Obj = '@Version=1; Name="a";'
$s= [System.Management.Automation.ScriptBlock]::Create("New-Object -TypeName PSObject -Property $Obj")
$o = Invoke-Command -ScriptBlock $s
$o.Version
【讨论】:
我也遇到过这个问题,但我认为这些只是占位符值。【参考方案3】:正如我在评论中所说,这很奇怪,应该在代码库的早期解决。但是,如果这不可能,请使用Invoke-Expression
像这样
$newObj = Invoke-Expression $Obj
Further reading on Invoke-Expression
【讨论】:
如果$Obj
是一个内容为'@Version=1; Name=a;'
的字符串,您的Invoke-Expression
调用将失败,因为 (a) 它会尝试将字符串解析为 hashtable 文字,而不是[pscustomobject]
,并且(b),更重要的是,a
被解释为要执行的命令,而不是字符串。换句话说:您无法从其字符串化表示中稳健地重新创建 [pscustomobject]
实例。此外,以这种方式使用Invoke-Expression
存在安全风险。以上是关于powershell psobject显示为字符串而不是psobject,如何转换回psobject的主要内容,如果未能解决你的问题,请参考以下文章
powershell psobject / hash对象/字典的示例
c#中的PowerShell cmd调用Invoke不返回特定用户电子邮件列表的PsObject
如何在C#中获取PSObject.Properties的ScriptProperty值?