クラスオブジェクトを作成し、それを使用Invoke-Command
してリモートマシンのクラスで関数を呼び出そうとしています。Invoke-Command
コンピューター名なしで使用すると、これは正常に機能しますが、リモートコンピューターでこれを実行しようとすると、タイプにメソッドが含まれていないというエラーが表示されます。これは、これをテストするために使用しているスクリプトです。
$ComputerName = "<computer name>"
[TestClass]$obj = [TestClass]::new("1", "2")
Get-Member -InputObject $obj
$credentials = Get-Credential
Invoke-Command -ComputerName $ComputerName -Credential $credentials -Authentication Credssp -ArgumentList ([TestClass]$obj) -ScriptBlock {
$obj = $args[0]
Get-Member -InputObject $obj
$obj.DoWork()
$obj.String3
}
class TestClass {
[string]$String1
[string]$String2
[string]$String3
[void]DoWork(){
$this.String3 = $this.String1 + $this.String2
}
TestClass([string]$string1, [string]$string2) {
$this.String1 = $string1
$this.String2 = $string2
}
}
これが私が得た出力です。
PS > .\Test-Command.ps1
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
User: <my user>
Password for user <my user>: *
TypeName: TestClass
Name MemberType Definition
---- ---------- ----------
DoWork Method void DoWork()
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
String1 Property string String1 {get;set;}
String2 Property string String2 {get;set;}
String3 Property string String3 {get;set;}
TypeName: Deserialized.TestClass
Name MemberType Definition
---- ---------- ----------
GetType Method type GetType()
ToString Method string ToString(), string ToString(string format, System.IFormatProvider formatProvider), string IFormattable.ToString(string format, System.IFormatProvider formatProvider)
String1 Property System.String {get;set;}
String2 Property System.String {get;set;}
String3 Property {get;set;}
Method invocation failed because [Deserialized.TestClass] does not contain a method named 'DoWork'.
+ CategoryInfo : InvalidOperation: (DoWork:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
+ PSComputerName : <computer name>
タイプがからTestClass
に変わるのがわかりますが、Deserialized.TestClass
これを回避する方法があるかどうか疑問に思っていますか?私の目標は、スクリプトを実行している各マシンに必要な関数を出荷できるようにすることですInvoke-Command
。これにより、スクリプトブロックのコンテキストで関数を書き直す必要がなくなります。
要するに:PowerShellがリモート処理中に舞台裏で採用していること、XMLベースのシリアライズ/デシリアライゼーションのバックグラウンドジョブでは、唯一の一握りハンドル知られている種類とタイプの忠実度を。
などあなたとカスタムクラスのインスタンスをされている、エミュレートしてメソッドレスの形で「プロパティバッグ」[pscustomobject]
インスタンスのクラスのインスタンスのエミュレートされたインスタンスは、リモートマシンには何のメソッドを持っていない理由です。
PowerShellのシリアル化/逆シリアル化の詳細な概要については、この回答の下部のセクションを参照してください。
マイクTWCが示唆、あなたのクラス渡すことで問題を回避することができます定義をリモートコマンドに沿ってだけでなく、リモートセッションでのカスタムクラスの再作成のインスタンスを、あなたがそこにクラスを再定義することができます。
ただし、カスタムクラスの定義を動的に取得することはできないため、クラス定義コードを複製するか、最初に文字列として定義する必要があり、を介して評価する必要Invoke-Expression
があります。これは通常は回避する必要があります。
単純化された例。パラメーターではなく$using:
スコープを使用して(via -ArgumentList
)、呼び出し元のスコープからの値を含めます。
# Define your custom class as a *string* first.
$classDef = @'
class TestClass {
[string]$String1
[string]$String2
[string]$String3
[void]DoWork(){
$this.String3 = $this.String1 + $this.String2
}
TestClass([string]$string1, [string]$string2) {
$this.String1 = $string1
$this.String2 = $string2
}
# IMPORTANT:
# Also define a parameter-less constructor, for convenient
# construction by a hashtable of properties.
TestClass() {}
}
'@
# Define the class in the caller's session.
# CAVEAT: This particular use of Invoke-Expression is safe, but
# it should generally be avoided.
# See https://blogs.msdn.microsoft.com/powershell/2011/06/03/invoke-expression-considered-harmful/
Invoke-Expression $classDef
# Construct an instance
$obj = [TestClass]::new("1", "2")
# Invoke a command remotely, passing both the class definition and the input object.
Invoke-Command -ComputerName . -ScriptBlock {
# Define the class in the remote session too.
Invoke-Expression $using:classDef
# Now you can cast the emulated original object to the recreated class.
$recreatedObject = [TestClass] $using:obj
# Now you can call the method...
$recreatedObject.DoWork()
# ... and output the modified property
$recreatedObject.String3
}
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加