【发布时间】: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-Jobserializes-InputObject参数提供的 ($user) 对象(这通常发生在内存中)。如您自己的推荐所述:"For complex types, the copy is imperfect".
标签: powershell scope arguments deserialization