使用自定义类(C#)打开Runspace池会引发错误

时间:2018-05-05 16:30:44

标签: c# multithreading powershell runspace

我必须为PowerShell脚本添加多线程功能。不幸的是,当我尝试使用InitialSessionState对象中的自定义C#类打开一个运行空间池时出现错误。以下示例仅是DEMO代码,而不是原始脚本。您可以复制并粘贴它,它将无需任何修改即可运行。真正奇怪的是,尽管在打开运行空间池时出现错误消息,但所有这些似乎都能正常工作。

这是错误消息(已翻译):

  

加载扩展类型数据文件时出错:类型数据错误" FooBar.BarClass":TypeData必须:"成员"," TypeConverters", " TypeAdapters"或" StandardMembers"。

我已经工作并测试了几个小时,并且不知道该消息的原因是什么。是的,我知道有很好的库和cmdlet可用于多线程,但由于不同的原因我无法使用它们。

# Simple c-sharp classes
Add-Type -TypeDef @"
namespace FooBar {
    public class FooClass {
        public string Foo() {
            return "Foo";
        }
    }

    public class BarClass {
        public string Bar() {
            return "Bar";
        }
    }
}
"@

function callFooBar {
    [FooBar.FooClass]$foo = New-Object FooBar.FooClass
    [FooBar.BarClass]$bar = New-Object FooBar.BarClass

    $foo.Foo() + $bar.Bar()
}

$scriptBlock = {
    Write-Output ( callFooBar )
}

# Setting up an initial session state object
$initialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()

# Getting the function definition for the functions to add
$functionDefinition = Get-Content function:\callFooBar
$functionEntry = New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList 'callFooBar', $functionDefinition

# And add it to the iss object
[void]$initialSessionState.Commands.Add($functionEntry)

# Get the type data for the custom types to add
$typeData = New-Object System.Management.Automation.Runspaces.TypeData -ArgumentList 'FooBar.FooClass'
$typeEntry = New-Object System.Management.Automation.Runspaces.SessionStateTypeEntry -ArgumentList $typeData, $false

# And add it to the iss object
[void]$initialSessionState.Types.Add($typeEntry)

# Get the type data for the custom types to add
$typeData = New-Object System.Management.Automation.Runspaces.TypeData -ArgumentList 'FooBar.BarClass'
$typeEntry = New-Object System.Management.Automation.Runspaces.SessionStateTypeEntry -ArgumentList $typeData, $false

# And add it to the iss object
[void]$initialSessionState.Types.Add($typeEntry)

# Create Runspace pool
$RunspacePool = [RunspaceFactory]::CreateRunspacePool(1, ([int]$env:NUMBER_OF_PROCESSORS + 1), $initialSessionState, $Host)
$RunspacePool.ApartmentState = 'MTA'
[void]$RunspacePool.Open()  # <<<< Error occurs here!

[System.Collections.Generic.List[object]]$Jobs = @()

1..2 | % {
    $job = [System.Management.Automation.PowerShell]::Create($initialSessionState)
    $job.RunspacePool = $RunspacePool
    [void]$job.AddScript($scriptBlock)   
    $jobs += New-Object PSObject -Property @{
        RunNum = $_
        Pipe   = $job
        Result = $job.BeginInvoke()
    }
}

do {
} while ($jobs.Result.IsCompleted -contains $false)
Write-Host "All jobs completed!"

$Results = @()
foreach ($job in $jobs) {
    $Results += $job.Pipe.EndInvoke($job.Result)
}

$Results

$RunspacePool.Close()
$RunspacePool.Dispose()

1 个答案:

答案 0 :(得分:2)

@ mklement0你的提示引导我走向正确的方向!必须以与runspacepool不同的方式添加具有类型定义的自定义C#类。这现在正在运行(经过几个小时的测试,使用所有可能的运行空间方法......):

# Get the script data for the custom c# class to add
$scriptDefinition = New-Object System.Management.Automation.Runspaces.ScriptConfigurationEntry -ArgumentList 'FooBar.FooClass', $false
$scriptEntry = New-Object System.Management.Automation.Runspaces.SessionStateScriptEntry -ArgumentList $scriptDefinition

# And add it to the iss object
[void]$initialSessionState.Commands.Add($scriptEntry)

# Get the script data for the custom c# class to add
$scriptDefinition = New-Object System.Management.Automation.Runspaces.ScriptConfigurationEntry -ArgumentList 'FooBar.BarClass', $false
$scriptEntry = New-Object System.Management.Automation.Runspaces.SessionStateScriptEntry -ArgumentList $scriptDefinition

# And add it to the iss object
[void]$initialSessionState.Commands.Add($scriptEntry)

不是按类型,而是使用脚本和命令。谢谢你的提示。