【问题标题】:In PowerShell, pass a complex object (SmoServer) to a background job in the ArgumentList - stuck in "NotStarted"在 PowerShell 中,将复杂对象 (SmoServer) 传递给 ArgumentList 中的后台作业 - 卡在“未启动”中
【发布时间】:2018-09-27 16:44:15
【问题描述】:

我正在尝试将预构建的 SmoServer 对象传递给后台作业,以并行处理针对多个 SQL Server 的一些操作。但是,当我尝试执行此操作时,被调用作业的子作业陷入“未启动”状态。一个非常基本的测试:

[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO")
$SmoServer = New-Object Microsoft.SqlServer.Management.Smo.Server MySqlServer
Start-Job -Name Test -ScriptBlock {
    param($SmoServer) 
    $SmoServer.Databases.Name 
} -InitializationScript {
    [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO"); Import-Module SQLPS -DisableNameChecking
} -ArgumentList $SmoServer

作业开始,但 ChildJob 卡在“未启动”

PS C:\Users\omrsafetyo> Get-Job Test

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
5      Test            BackgroundJob   Running       True            localhost            param($SmoServer) $Smo...


PS C:\Users\omrsafetyo> Get-Job Test | select -expand childjobs

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
6      Job6                            NotStarted    True            localhost            param($SmoServer) $Smo...

我之前遇到过这个问题,一直没有找到解决办法。然后我遇到了-IntializationScript,并认为这可能是灵丹妙药。好像不是。

Invoke-Command 也是如此。如果我只是运行 Invoke-Command,则该命令可以正常工作。但是,如果我运行 Invoke-Command -AsJob,并传递一个 SmoServer 对象,它仍然会失败。

如何将这些需要在 ArgumentList 中预先加载的程序集/模块的复杂对象传递给后台作业?

【问题讨论】:

  • 我不认为你可以在运行空间之间通过引用传递对象;这是系统限制。
  • @TheIncorrigible1 我想这是有道理的。所以你认为也许我可以合并一个 RunSpace 池,如下所述:learn-powershell.net/2013/04/19/… 并获得此功能?
  • 事实证明,这不是一个好的解决方案。我确实让运行空间正常工作。但是,一旦它开始工作,我遇到了一个问题(可能特定于 SMO),即 SMO 对象本身在读/写操作方面存在并发问题。一个更好的解决方案最终是使用常规后台作业,并将实例传入,并在脚本块中重新初始化环境(加载模块/程序集,定义凭据等)。

标签: powershell smo


【解决方案1】:

PowerShell 作业在单独的进程中运行,并且作为参数传递的对象被序列化(通过类似Export-CliXml 或道德等价物)。当您的对象在后台进程中“重新水化”时,它将不再是 Microsoft.SqlServer.Management.Smo.Server 的实例,而只是一个 看起来 像的对象(它将具有相同的属性,因为它们在原始过程中被序列化)。

可以将 .NET 对象传递到同一进程中的不同运行空间。一个简单的方法是使用PSThreadJob 模块。

一个实验来演示传递给后台作业的对象会发生什么:

$srcFi = [System.IO.FileInfo]::new( 'C:\windows\system32\ntdll.dll' )
$srcFi.GetType().FullName
start-job -ScriptBlock { param( $fi ) $fi.GetType().FullName } -Arg @( $srcFi ) | Receive-Job -Wait

输出:

System.IO.FileInfo
System.Management.Automation.PSObject

【讨论】:

    猜你喜欢
    • 2022-06-23
    • 1970-01-01
    • 2013-03-12
    • 2018-03-24
    • 2015-03-03
    • 1970-01-01
    • 2014-03-17
    • 2021-03-22
    • 1970-01-01
    相关资源
    最近更新 更多