【问题标题】:Convert string to PSCustomObject将字符串转换为 PSCustomObject
【发布时间】:2018-12-15 23:53:17
【问题描述】:

我遇到的问题源于将PSCustomObject 作为参数传递给Start-Process cmdlet(我实际上是在启动一个新的PowerShell 进程以从调用脚本异步运行脚本)。虽然参数定义为PSCustomObject 类型,但由于某种原因它被接受为字符串,因此看起来我需要将其转换回PSCustomObject 才能访问任何属性。

这是我的调用脚本的必要部分:

# Convert JSON object to PowerShell object
$payload = ConvertFrom-Json $body

Write-Host $payload
## Returns exactly the following PsCustomObject:

## @{os=Windows Server Datacenter 2016; vmName=sbtestvm; diskType=Managed; username=testuser;
## password=Pa55w.rd1234; location=West Europe; size=Standard_D1;
## requestType=0; sender=test}

Write-Host $payload.os
## Returns: Windows Server Datacenter 2016

# Fire up new worker shell asynchronously
Start-Process powershell.exe -ArgumentList '-NoExit', "$PSScriptRoot\ServiceBus-AsyncWorker.ps1", "'$payload'"  # -Windowstyle Hidden

还有我执行的脚本:

Param(
    [Parameter(Mandatory=$True)]
    [PSCustomObject]$Request
)

# Import RequestHandler module to deal with processing service bus requests
Import-Module $PSScriptRoot\RequestHandler\RequestHandler.psm1

Write-Host $Request
## Returns exactly the same as 'Write-Host $payload' in the calling script

Write-Host $Request.os
## Returns empty string

Write-Host $Request.GetType()
## Returns System.String <--- This is the issue

长话短说:有没有办法一开始就防止这个对象被自动解析为字符串?如果不是 - 如何将此字符串转换回相关的对象类型?

【问题讨论】:

  • 您是否尝试过删除Start-Process 行中的引号? "'$payload'" -> $payload
  • 是的,我已经在这方面摆弄了很多 - 我也尝试传递原始 JSON 并在其他方法中解析它,但是 JSON 字符串中的所有引号消失,因此它实际上变得毫无用处。由于对象格式中的空格,您的建议失败,因此该命令认为单个参数实际上是多个。

标签: powershell casting start-process


【解决方案1】:

Start-Process powershell.exe 启动一个新的 PowerShell 进程。不能跨进程边界传递 PowerShell 对象。

你可以改变

Start-Process powershell.exe -ArgumentList '-NoExit', "$PSScriptRoot\ServiceBus-AsyncWorker.ps1", "'$payload'"

$PSScriptRoot\ServiceBus-AsyncWorker.ps1 $payload

为了避免创建新进程,但这会在同一个窗口中运行脚本。

如果您需要运行与控制台分离的脚本,您可以将其作为background job 运行:

$job = Start-Job -ScriptBlock {
    Param($Path, $Data)
    & "$Path\ServiceBus-AsyncWorker.ps1" $Data
} -ArgumentList $PSScriptRoot, $payload

否则,您需要在生成新进程时以序列化形式(例如原始 JSON)传递参数:

Start-Process powershell.exe -ArgumentList '-NoExit', "$PSScriptRoot\ServiceBus-AsyncWorker.ps1", "`"$body`""

然后(重新)从字符串创建对象:

Param(
    [Parameter(Mandatory=$true)]
    [string]$Json
)

# Import RequestHandler module to deal with processing service bus requests
Import-Module $PSScriptRoot\RequestHandler\RequestHandler.psm1

$Request = ConvertFrom-Json $Json
...

【讨论】:

  • 谢谢@ansgar - 后台工作是我以前从未见过的,但绝对看起来是一种更清洁的方式来解决这个问题。我试图完全使用您的代码 - 但是从一些研究来看,$using 命令似乎适用于 PowerShell V3 及更早版本。对于较新的版本,需要ArgumentList(请参阅我的编辑)。此外,我尝试使用您的最终解决方案(在我自己之前尝试过之后),但是,正如 @gms0ulman 所提到的,字符串转义字符破坏了 JSON 格式,使该方法无用。 PS。感谢您修复我的问题格式!
  • using scope modifier 是随 PowerShell v3 引入的。它在 PowerShell v4 及更高版本中运行良好。它在 PowerShell v3 之前不起作用。
  • 啊,好吧,我一定是看错了。虽然,我使用的是 v5,并且您建议的脚本产生了一些语法错误,即使前面有调用运算符也是如此。 $using: 之后的文件路径语法阻止脚本执行,如果我要将其更改为字符串变量,使用 $using:payload 会引发意外的令牌错误。
  • using 可能不适用于automatic variables,如$PSScriptRoot(尚未测试)。不过,$using:payload 应该可以工作。
猜你喜欢
  • 1970-01-01
  • 2016-08-03
  • 2021-02-25
  • 1970-01-01
  • 2019-09-26
  • 2019-10-10
  • 2019-01-05
  • 2015-01-18
  • 1970-01-01
相关资源
最近更新 更多