【问题标题】:Why does my variable behave like this inside a Job?为什么我的变量在 Job 中的行为是这样的?
【发布时间】:2020-08-22 16:10:04
【问题描述】:

我在我的 Powershell 脚本中的 Jobs 中遇到了 XmlElements 的奇怪行为。 $CommandConfiguration 是一个带有嵌套元素的 XML 元素。这些元素存在于作业范围之外的脚本中,这已经过测试和调试。考虑一下这段代码:

if($CommandConfiguration.ChildNodes.Name -contains "DomainCheck"){
    Write-Host ChildNode exists                            # this is executed
}
$Jobs += Start-Job -Name "WMI-Job" -ScriptBlock {
    $th = $Using:TargetHost
    $cc = $Using:CommandConfiguration                     
    $creds = $Using:Creds

    if($cc.ChildNodes.Name -contains "DomainCheck"){
        Write-Host ChildNode exists                        # this is NOT executed
    }

...

显然,为什么子节点存在于作业之外而不存在于作业内部?我错过了什么吗?

感谢您帮助我!

【问题讨论】:

  • 为了完整起见,您确实使用Receive-Job 之类的东西来实际获得作业输出,对吗?否则Write-Host 无论如何也不会显示太多。
  • 是的,我正在等待作业失败或完成,然后再收到。输出 write-host 应该给出的结果不显示。
  • 取决于CommandConfiguration 是什么,它可能无法正确序列化以在using 中有用,但这是推测。查看($using:CommandConfiguration).GetType() 输出的内容,而不是块外的类型。任何比string 更复杂的东西都会冒着不能完全像以前那样结束的风险,并且脚本或魔法属性等某些便利可能会消失。一个简单的 XML 元素在我的测试中有效,但你永远不知道。
  • @JeroenMostert 在 Job 之外它是一个 XMLElement,在它内部是一个 System.Management.Automation.PSObject。有什么办法可以解决这个问题吗?
  • 不,这只是意味着 PowerShell 已将其序列化为无法简单转换为字符串的内容(我不知道具体是什么),因此我提出的反序列化方法失败了。您始终可以将其强制为扁平字符串 ($stringCommandConfiguration = $CommandConfiguration.InnerXml; ... $cc = [xml] $using:stringCommandConfiguration)。

标签: xml powershell jobs using


【解决方案1】:

tl;dr

正如Jeroen Mostert 所述,您必须在后台作业中将调用方范围内的 XML 元素作为字符串引用,然后在此处再次将它们解析为 XML DOM。

Start-Job -Name 'WMI-Job' -ScriptBlock {
  # ...
  # Use .OuterXml to get the XML element's string representation
  # from the caller's scope, and parse it into an XML document,
  # which makes $cc.ChildNodes work as expected.
  [xml] $cc = $Using:CommandConfiguration.OuterXml
  # ...
}

由于跨进程边界的会话之间传输的值必须经过序列化以及反序列化的仿真XmlElement 输入对象缺少ChildNodes 属性 - 请继续阅读以了解更多信息。


上下文

通常,当数据在进程外会话(例如以Start-Job 开始的后台作业)之间传输时,只有少数知名类型会以类型保真度反序列化。

所有其他类型的实例都是原始对象的无方法仿真,实际上[pscustomobject]s 具有原始对象属性值的静态副本,并具有 PowerShell ETS(扩展类型系统)反映原始类型全名的类型名称,前缀为Deserialized.

请参阅this answer 了解更多信息。


也许令人惊讶,

请注意,在 XmlElement 的情况下,只有原始实例的所谓 adapted 属性会反映在 Deserialized.System.Xml.XmlElement (pscustomobject) 属性中。

也就是说,仿真只有PowerShell添加到原始实例的属性,即直接显示底层XML DOM的子元素和属性的属性,这可以方便地使用通常的点符号 - 请参阅this answer

.NET XmlElement 类型的真实属性(例如 ChildNodes)在反序列化仿真中存在,这就是您的代码失败的原因。

如顶部所示,解决方法是将XmlElement 实例的字符串 表示传递给后台作业(可通过OuterXml 属性获得)并重新解析该字符串到那里的 XML DOM 中(请注意,严格来说,转换为 [xml] 会创建一个 System.Xml.XmlDocument 实例,但就您尝试执行的操作而言,这无关紧要)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-02-13
    • 2017-10-31
    • 2021-11-08
    • 1970-01-01
    • 2019-10-05
    • 2015-09-09
    • 2021-04-20
    • 1970-01-01
    相关资源
    最近更新 更多