I have a solution in Powershell (7) where I have a module that includes a class, like
test.psm1
class TestClass {
[string]$Test
TestClass(
[string]$_test
) {
$this.Test = $_test
}
[void] TestMethod() {
xxx
}
}
In the main script I can successfully import the module including its classes and work with it.
In the main script I also want to process certain steps in parallel using jobs, like
using module .\test.psm1
[TestClass]$test = [TestClass]::new()
$job = $objects | ForEach-Object -Parallel {
[TestClass]$testJob = $using:test
} -ThrottleLimit $ParallelJobsThrottleLimit -AsJob
In these jobs I want to use an object of type TestClass that has been declared outside of the parallel statement.
All my approaches so far failed with Unable to find type.
How can I make this work?
CodePudding user response:
As of PowerShell 7.2.x, the instances of a script block ({ ... }) passed to ForEach-Object -Parallel, which run in parallel runspaces, do not see any of the caller's runspace state, which includes class definitions.
Hence the need for the
$using:scope to reference values stored in the caller's variables.Unfortunately, there is no equivalent mechanism for custom classes.
GitHub issue #12240 discusses a future enhancement that will allow parallel runspaces to see at least parts of the caller's state, which would hopefully included classes.
The problem, in a nutshell:
In order for parallel runspaces to see your
[TestClass]too, they would have to import its containing module.However, only when you import a module via
using moduleare a module's classes visible to the caller (not also when you useImport-Module).Unfortunately,
usingstatements may only be placed at the start of a script file, and therefore cannot be used inside script blocks.
There is a cumbersome workaround:
Define your
classin a regular.ps1script that you reference from theScriptsToProcessentry of your module's manifest file (.psd1)That way, when the module is first imported into a runspace, the
.ps1script is dot-sourced in the caller's (importer's) scope, andclassdefinitions therefore become visible.This allows you to use a regular
Import-Modulecall in your parallel script block in order to see theclassdefinition there.
Note that your module itself will not see such class definitions by default - unless you explicitly dot-source the .ps1 file from the module's top-level code too.
