"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
我需要列出 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