如何在PowerShell作业中调用类对象?遇类型未找到错误
问题描述
我创建了Test PowerShell类,计划通过后台并行作业创建该类对象并执行类中的方法。编写相关代码后,作业显示完成但未达预期,查看作业详情发现每个作业均报错:无法找到[Test]类型,以及无法找到ComputerName属性。
原代码
class Test { [String]$ComputerName [String]TestMrParameter() { if ($this.ComputerName -eq 'jhon'){throw "Bad thing happened"} return $this.ComputerName } } $names = @('david', 'jhon', 'mark','tent') $jobs = [System.Collections.ArrayList]@() function TestMrParameter2 { param ( [String]$name ) [Test]$obj = [Test]::new() $obj.ComputerName = $name Write-Host $name + "TestMrParameter2 Function Reached!!!" $output=$obj.TestMrParameter() Write-Host "Output of the Test class is" + $output } foreach ($name in $names) { $out = Start-Job -ScriptBlock ${Function:TestMrParameter2} -ArgumentList $name $jobs.Add($out) | out-null }
错误信息
Unable to find type [Test]. + CategoryInfo : InvalidOperation: (Test:TypeName) [], RuntimeException + FullyQualifiedErrorId : TypeNotFound + PSComputerName : localhost The property 'ComputerName' cannot be found on this object. Verify that the property exists and can be set. + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : PropertyNotFound + PSComputerName : localhost
原因分析
PowerShell后台作业(Start-Job)会启动独立的子运行会话,当前会话中定义的类不会自动同步到子会话。你仅传递了函数TestMrParameter2,但函数依赖的Test类在子会话中未定义,因此会触发类型找不到的错误;后续的属性找不到错误是因为类不存在,对象创建失败导致的。
解决方案
方法1:通过初始化脚本在作业中加载类
将Test类的定义放到作业的初始化脚本中,确保作业启动时先加载类:
$names = @('david', 'jhon', 'mark','tent') $jobs = [System.Collections.ArrayList]@() # 初始化脚本:作业启动时加载Test类 $initScript = { class Test { [String]$ComputerName [String]TestMrParameter() { if ($this.ComputerName -eq 'jhon'){throw "Bad thing happened"} return $this.ComputerName } } } function TestMrParameter2 { param ( [String]$name ) [Test]$obj = [Test]::new() $obj.ComputerName = $name # 修正字符串拼接方式,避免输出多余的+符号 Write-Host "$name TestMrParameter2 Function Reached!!!" try { $output = $obj.TestMrParameter() Write-Host "Output of the Test class is $output" # 返回结果方便后续获取 return $output } catch { Write-Error $_ return $_ } } foreach ($name in $names) { $out = Start-Job -InitializationScript $initScript -ScriptBlock ${Function:TestMrParameter2} -ArgumentList $name $jobs.Add($out) | Out-Null } # 等待所有作业完成并接收结果 $jobs | Wait-Job | Receive-Job
方法2:将类定义保存为脚本文件导入
如果类定义较复杂,可将其保存为单独的脚本文件(如TestClass.ps1),再在作业初始化时导入:
TestClass.ps1内容:
class Test { [String]$ComputerName [String]TestMrParameter() { if ($this.ComputerName -eq 'jhon'){throw "Bad thing happened"} return $this.ComputerName } }
主脚本修改为:
$names = @('david', 'jhon', 'mark','tent') $jobs = [System.Collections.ArrayList]@() function TestMrParameter2 { param ( [String]$name ) [Test]$obj = [Test]::new() $obj.ComputerName = $name Write-Host "$name TestMrParameter2 Function Reached!!!" try { $output = $obj.TestMrParameter() Write-Host "Output of the Test class is $output" return $output } catch { Write-Error $_ return $_ } } foreach ($name in $names) { # 替换为实际的TestClass.ps1文件路径 $out = Start-Job -InitializationScript { . "C:\scripts\TestClass.ps1" } -ScriptBlock ${Function:TestMrParameter2} -ArgumentList $name $jobs.Add($out) | Out-Null } $jobs | Wait-Job | Receive-Job
额外说明:原代码中
Write-Host用+拼接字符串会导致输出格式错误,已修正为双引号插值的方式,避免输出多余的+符号。
内容的提问来源于stack exchange,提问作者Chethiya Amarasinghe
相关产品推荐
相关产品推荐

