"You cannot call a method on a null-valued expression." 尝试在后台作业中接收更新搜索器 运行 的结果时

"You cannot call a method on a null-valued expression." when trying to receive Result of update Searcher running in Background Job

我需要列出 Windows 上所有未安装的更新并将它们写入文件。但是如果时间太长,肯定会超时。

我尝试 运行 将更新搜索器对象作为作业进行搜索,然后在完成或超时时继续。 然后我检查工作是否已经完成。如果是,我将作业传递给 Receive-Job 以获取结果并将其写入文件。

$session = New-Object -ComObject "Microsoft.Update.Session"
$searcher = $session.CreateUpdateSearcher()

$j = Start-Job -ScriptBlock {
    $searcher.Search("IsInstalled=0").Updates | Select-Object Type, Title, IsHidden
} | Wait-Job -Timeout 120

if ($j.State -eq 'Completed') {
    Receive-Job $j -Keep | Out-File @out_options
} else {
    echo "[TIMEOUT] Script took too long to fetch all missing updates." |
        Out-File @out_options
}

@out_options 已定义,如果你想知道的话。

我唯一收到的是以下错误:

You cannot call a method on a null-valued expression.
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
    + PSComputerName        : localhost

现在我发现错误源于调用 Receive-Job。似乎工作在没有结果之前就已经完成了。 我如何从我的后台作业中接收结果?

您 运行 遇到了范围问题。脚本块中的变量 $searcher 与脚本范围中的变量 $searcher 处于不同的范围(因此是不同的变量)。因为它没有正确初始化,脚本块中的变量是空的,因此导致您观察到的错误(您试图在空值上调用 Search())。

通常的解决方法是使用 using 范围修饰符

$j = Start-Job -ScriptBlock {
    $<b>using:</b>searcher.Search("IsInstalled=0").Updates | ...
} | ...

或将变量作为参数传递

$j = Start-Job -ScriptBlock {
    <b>Param($s)</b>
    <b>$s</b>.Search("IsInstalled=0").Updates | ...
} <b>-ArgumentList $searcher</b> | ...

但是,在您的情况下,这两种方法都不起作用,据我所知,这是因为 COM 对象在不同上下文之间传递时 serialized/deserialized 的方式。

为避免此陷阱,请在脚本块内创建更新会话和搜索器:

$j = Start-Job -ScriptBlock {
    $session = New-Object -ComObject 'Microsoft.Update.Session'
    $searcher = $session.CreateUpdateSearcher()
    $searcher.Search('IsInstalled=0').Updates | Select-Object Type, Title, IsHidden
} | Wait-Job -Timeout 120