【问题标题】:PowerShell - Passing OBJECTS to start-job - deserializePowerShell - 将 OBJECTS 传递给 start-job - 反序列化
【发布时间】:2021-10-03 20:45:24
【问题描述】:

我知道通过 start-job 执行的脚本块看不到脚本块之外的变量。要传递变量,请使用 -arguments 参数。从我读过的文档来看,如果没有serialising,工作就不能互相传递对象。显然这是因为作业的工作方式——当使用Start-job 时,PowerShell 会创建一个新进程并在那里运行命令;为了将对象传输到需要对其进行序列化的其他进程,其他 exe 将在导入时对其进行反序列化。当您想将对象与 start-job 一起使用时,这会带来问题。

注意:以下是演示我的问题的示例 - 我正在运行的实际 cmdlet 和脚本完全不同并且更复杂,所以如果你想知道为什么我什至会运行这些命令请记住,我不会,它们只是简单的命令来演示我的问题。

这是我用于简单 Get-aduser 命令的语法示例

$user = get-aduser samaccount

当我们输出 $user 时,我们看到对象的类型是 ADUser

$user|GM
TypeName: Microsoft.ActiveDirectory.Management.ADUser

现在让我们序列化对象(以模拟 start-job 的作用)

$user| Export-Clixml C:\temp\test.xml

现在重建它(反序列化)

$user = Import-Clixml C:\temp\test.xml

现在当我们查看它的类型时,它是不同的。它前面有“反序列化”这个词。

 $user|GM
TypeName: Deserialized.Microsoft.ActiveDirectory.Management.ADUser

我现在遇到的问题是它不是原始对象的真实表示。即使所有属性和设置都相同,我们仍然会遇到对象类型不同的问题。现在来说明为什么这是一个问题。

Get-aduser 接受一个字符串作为输入(第一个示例),但它也将接受一个有效的ADuser 对象。但是当我们现在运行时:

get-aduser $user

我们得到以下错误:

"Cannot convert the "AD_distinguishedname_here. I have omitted this for security reasons" value of type 
"Deserialized.Microsoft.ActiveDirectory.Management.ADUser" to type "Microsoft.ActiveDirectory.Management.ADUser"."

此错误是因为 Get-aduser 希望您提供 Microsoft.ActiveDirectory.Management.ADUser 类型的对象,但我们提供了 Deserialized.Microsoft.ActiveDirectory.Management.ADUser 并且它不知道如何转换它。这正是您通过 start-job 运行命令时发生的情况,以及您无法将对象传递给作业的原因。

正如我上面所说,我没有在我的真实代码中使用 get-aduser,我只是使用这个每个人都可以访问的简单命令来演示这个问题。在我的真实代码中,我必须为作业提供一个对象。

所以我的问题是,有谁知道您如何解决这个问题或知道如何以原始形式重建对象?

【问题讨论】:

  • 您听说的-ArgumentList 不正确。您绝对可以使用此方法传入对象。 “参数必须作为单维数组参数传递给 ArgumentList。例如,逗号分隔的列表。”这只是意味着您不应该传入参数/参数对的哈希表。相反,只需按照脚本块 param() 块中列出的参数顺序传递参数,或者如果不使用 param() 块,则使用 $args 数组访问参数。
  • 好吧还是不行,我试过了。从那以后我又读了一些书。我认为这是因为我上面提到的序列化/反序列化。根据这里的MS文章docs.microsoft.com/en-us/powershell/module/…,它说后台作业(开始作业)先被序列化然后反序列化。如果您查看我上面的错误,它表明对象类型是“反序列化的”。我认为这是问题所在。如何将其转换回原始对象类型?
  • 至于您的问题,AD cmdlet 是出了名的挑剔。该错误不是由将对象传递给 Start-Job 或 Invoke-Command 引起的,而是由 Get-ADUser 返回仅具有最少属性或您请求的属性的精简(反序列化)对象的方式引起的。我通常最终不得不做Get-ADUser $user.SamAccountName之类的事情,而不仅仅是Get-ADUser $user。这是直接的问题,不仅在后台作业中。
  • 不,它是...阅读文章,它明确指出这就是原因。 get-aduser 本身不返回反序列化数据。问题(似乎)是数据被临时写入磁盘(因此其他进程可以获取它),这被称为“序列化”。后台作业从文件中读取并重建它,但它不是真正的副本,因此它的类型设置为反序列化。
  • Get-ADUser 输出一个ADUser 对象Start-Job serializes -InputObject 参数提供的 ($user) 对象(这通常发生在内存中)。如您自己的推荐所述:"For complex types, the copy is imperfect".

标签: powershell scope arguments deserialization


【解决方案1】:

在这条直线上花了 8 个小时后,我终于弄清楚发生了什么。这是一个很长的故事,但是 TLDR 版本是您无法使用任何本机工具来解决这个问题 - 您必须在 start-job 脚本块内重新构建对象,如果您有一个大型复杂对象,这是不可行的。我最终找到了一个可以下载的模块,它通过启动线程而不是启动作业运行命令,并且不使用序列化。 Guide here 到 DL 并安装它。这在我测试时有效

要获取 PowerShell 模块,请转到 PowerShell 库并搜索“start-thread”

【讨论】:

  • 哈!我很高兴你发现了。我刚刚在另一个帖子上看到了你的评论。我想我的 StackOverflow 不够。我的回答真的是:你试过 PSThreadJob 吗? ?
  • 好的,谢谢。顺便说一句,您在创建自己的反序列化方法的其他线程上做了一些出色的工作!
猜你喜欢
  • 2023-01-02
  • 2017-10-08
  • 2013-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-11
  • 1970-01-01
  • 2013-03-12
相关资源
最近更新 更多