我正在开发一个课程,该课程必须在本地和远程运行。简化版本在下面的代码中。
假设:
模块文件 C:\Test\MyEmployee.psm1 如下所示:
using namespace System.Collections.Generic
class MyEmployee
{
[int]$UniqueID
[string]$Firstname
[string]$Lastname
[string]$Folder
MyEmployee( [int]$ID, [string]$First, [string]$Last, [string]$Folder )
{
$this.UniqueID = $ID
$this.Firstname = $First
$this.Lastname = $Last
If( $Folder.Length -lt 0 )
{
$this.Folder = $Folder
}
Else
{
$this.Folder = "Employee" + $this.UniqueID.ToString( ).PadLeft( 5 , "0" )
}
}
}
class MyEmployees
{
[List[MyEmployee]]$Employees
MyEmployees( )
{
$this.Employees = [List[MyEmployee]]::New( )
}
}
调用脚本如下所示:
using Module "C:\Test\MyEmployee.psm1"
Function RunCode( )
{
$MyEmps = [MyEmployees]::New( )
$MyEmp = [MyEmployee]::New( 1, "John", "Doe", "" )
$MyEmps.Employees.Add( $MyEmp )
ForEach( $MyEmp in $MyEmps.Employees )
{
Write-Host "Employee $( $MyEmp.UniqueID ) : $( $MyEmp.Lastname ), $( $MyEmp.Firstname ) "
}
}
$ScriptBlock = {
Import-Module "C:\Test\MyEmployee.psm1"
$MyEmps = [MyEmployees]::New( )
$MyEmp = [MyEmployee]::New( 1, "John", "Doe", "" )
$MyEmps.Employees.Add( $MyEmp )
ForEach( $MyEmp in $MyEmps.Employees )
{
Write-Host "Employee $( $MyEmp.UniqueID ) : $( $MyEmp.Lastname ), $( $MyEmp.Firstname ) "
}
}
Clear-Host
$LocalHost = $Env:ComputerName
$Servername = $LocalHost
#$Servername = "remote"
If( $Servername -eq $LocalHost )
{
RunCode
}
Else
{
$LogResult = $( Invoke-Command -ComputerName $ServerName -ScriptBlock $ScriptBlock )
}
当在本地运行时,无论是在“远程”还是在我的机器上,代码都可以完美执行,我得到了预期的结果:
Employee 1 : Doe, John
Employee 2 : Doe, Peter
Employee 3 : Doe, Jane
Employee 4 : Doe, Petra
但是,一旦我取消注释
#$Servername = "remote"
行,告诉 PowerShell 运行 ScriptBlock 而不是 te 函数,我就会收到以下错误:
Unable to find type [MyEmployees].
+ CategoryInfo : InvalidOperation: (MyEmployees:TypeName) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
+ PSComputerName : remote
我在这里做错了什么?是否可以在 PowerShell 中像这样远程运行类代码?
Import-Module
不会公开 psm1
中定义的 PowerShell 类,您需要在 using module
中使用 $scriptblock
,就像在调用脚本中一样。如果您要创建一个只有类而没有函数的项目,那么使用 psm1
已经是不正确的方法,使用 ps1
会更容易,您可以 dot source (. 'path\to\MyEmployeeClass.ps1'
).
如果您尝试将
using module
语句添加到 $scriptblock
中,下一个问题将是一个解析错误,因为“A 'using' 语句必须出现在脚本中的任何其他语句之前。PowerShell”,因此要解决此问题需要将您的代码定义为字符串,并使用 ScriptBlock.Create
. 从它创建一个脚本块
总结:
$ScriptBlock = [scriptblock]::Create(@'
using module "C:\Test\MyEmployee.psm1"
Import-Module "C:\Test\MyEmployee.psm1"
$MyEmps = [MyEmployees]::New( )
$MyEmp = [MyEmployee]::New( 1, "John", "Doe", "" )
$MyEmps.Employees.Add( $MyEmp )
ForEach( $MyEmp in $MyEmps.Employees )
{
Write-Host "Employee $( $MyEmp.UniqueID ) : $( $MyEmp.Lastname ), $( $MyEmp.Firstname ) "
}
'@)
那么假设
Invoke-Command
存在于 C:\Test\MyEmployee.psm1
中,$ServerName
语句应该可以正常工作。