In PowerShell, pass a complex object (SmoServer) to a background job in the ArgumentList - stuck in “NotStarted”

家住魔仙堡 提交于 2020-12-15 06:45:33

问题


I am trying to pass a pre-built SmoServer object to a background job, to parallelize some operations against multiple SQL Servers. However, when I try to do this, the Child job of the invoked job gets stuck in a "NotStarted" state. A very basic test:

[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

The job starts, but the ChildJob gets stuck "NotStarted"

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...

I had encountered this a while ago, and never found a solution. And then I came across -IntializationScript, and thought that might be the silver bullet. It doesn't seem it is.

This same behavior is true with Invoke-Command. If I just run Invoke-Command, the command works fine. However, if I run Invoke-Command -AsJob, and pass an SmoServer object, it still fails.

How do I pass these complex objects that need an assembly/module loaded up front in the ArgumentList to a background job?


回答1:


PowerShell jobs are run in a separate process, and objects passed as arguments are serialized (via something like Export-CliXml or the moral equivalent). When your object is "rehydrated" in the background process, it will not be an instance of Microsoft.SqlServer.Management.Smo.Server anymore, but rather just an object that looks like one (it will have the same properties, as they were serialized in the originating process).

You can pass .NET objects to different runspaces within the same process. An easy way to do this would be to use the PSThreadJob module.

An experiment to demonstrate what happens to objects passed to background jobs:

$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

Output:

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


来源:https://stackoverflow.com/questions/52541648/in-powershell-pass-a-complex-object-smoserver-to-a-background-job-in-the-argu

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!