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

如何正确验证powershell中的参数?

如何在C#中获取PSObject.Properties的ScriptProperty值?

如何在 C# 中获取 PSObject.Properties 的 ScriptProperty 值?

从 powershell 中的 JSON 文件中提取子字符串