Invoke-Command を使用してリモート コンピューターでコマンドまたは PowerShell スクリプトを実行する方法

PowerShellでリモートコマンドを実行しようとして何度も行き詰まった経験があるなら、きっとイライラするはずです。Invoke-Commandコマンドレットは、スクリプトやコマンドをリモートで実行するのに非常に便利ですが、WinRM(Windowsリモート管理)の設定全体が正しく構成されている場合にのみ機能します。通常、問題が発生するのは、ターゲットマシンでWinRMが有効になっていないか、ファイアウォールが受信リクエストをブロックしているためです。特に、ネットワークプロファイルやファイアウォールルールを変更するための正確なコマンドやパスを知らない場合は、これを正しく設定するのはモグラ叩きのように難しく感じるかもしれません。このガイドでは、WinRMを適切に有効にする方法、ネットワークがリモート管理用に設定されていることを確認する方法、そして実際にリモートシステムでコマンドを実行する方法について説明します。

Windows で PowerShell リモート処理 (WinRM) を有効にする方法

WinRMサービスの有効化 – リモートコマンドが機能するために必須

Invoke-Command が接続を拒否する主な理由は、WinRM が有効化されていないか、正しいネットワークルールが設定されていないことです。まず、WinRM サービスが実行中かつ設定されている必要があります。WinRM が既に実行中でリッスン状態かどうかを確認するには、対象マシンの PowerShell で次のコマンドを実行します。

Get-Service -Name "*WinRM*" | fl WinRM, State Get-Item wsman:\localhost\Listener 

設定されていない場合でも問題ありません。対象マシンで以下を実行してください。

winrm quickconfig

このコマンドは、WinRMサービスを起動し、自動起動に設定し、デフォルトのリスナーを作成し、ファイアウォールの例外を追加します。Enable-PSRemoting -Force特にリモートまたはスクリプト経由で実行する場合は、PowerShell内で管理者として実行するだけでもうまくいく場合があります。ただし、環境によっては、PowerShellリモートはデフォルトでパブリックネットワーク上でスムーズに動作しないため、ネットワークプロファイルをプライベートまたはドメインに調整する必要がある場合があります。

ご注意: 一部のマシンでは、ネットワークプロファイルに問題が発生する場合があります。少し奇妙に感じるかもしれませんが、「設定」>「ネットワーク」>「イーサネット」または「Wi-Fi」>「ネットワークプロファイル」でネットワークを「パブリック」から「プライベート」に変更すると、権限に関する問題が解決することがよくあります。それでもリモート接続できない場合は、ファイアウォールルールを調整するか、WinRMの受信トラフィックを明示的に許可してみてください。

Set-NetFirewallRule -Name "WINRM-HTTP-In-TCP" –RemoteAddress Any

この行は、ネットワークアドレスに関係なくWinRMの受信トラフィックを許可します。複数のサブネットセグメントや不安定なネットワーク設定を扱う場合に便利です。ただし、Windowsは必要以上に処理を複雑にする必要がある場合もあるので、覚えておいてください。

信頼できるホスト – ワークグループやIPアドレス間で作業する場合

システムがドメインに属していない場合、またはIPアドレスで接続している場合は、それらのリモートマシンを信頼できるホストリストに追加する必要があります。これは「利便性によるセキュリティ」という側面もありますが、必要なことです。以下のコマンドを実行してください。

Set-Item wsman:\localhost\Client\TrustedHosts -Value "192.168.1.201"

あるいは、無謀だと感じる場合は、すべてを許可してください。

Set-Item wsman:\localhost\Client\TrustedHosts -Value "*"

忘れないでください。その後、WinRM サービスを再起動する必要があります。

Restart-Service WinRM
注: 複数のホストを追加する場合は、 “192.168.1.201, 192.168.1.202”のように、IP または名前を引用符で囲んでコンマで区切ります。

Invoke-Commands を使用してリモート コンピュータでコマンドを実行する

単一のコマンドを実行する – 簡単ですが、正しい設定が必要です

WinRM をセットアップし、ネットワークルールを設定したら、Invoke-Command を使用するには、ターゲットマシンと実行するコマンドを指定するだけです。例えば、次のようになります。

Invoke-Command -ComputerName dc01 -ScriptBlock { Get-Service wuauclt }

これにより、 dc01というリモートマシンにWindows Update サービスが実行中かどうかが通知されます。サービスの状態が表示されるはずです。ある設定では問題なく動作しましたが、別の設定では認証に問題が発生する場合がありますので、権限とネットワークルールを再確認してください。

便利なヒント: 別のユーザー アカウントでコマンドを実行する場合は、-Credentialを追加して資格情報を指定します。

$cred = Get-Credential Invoke-Command -ComputerName dc01 -Credential $cred -ScriptBlock { Get-NetAdapter }

これは通常、現在のユーザーがターゲットマシンのリモート管理グループまたは管理者グループに属していない場合に役立ちます。ただし、多くの権限が関係しており、PowerShellのセキュリティポリシーによって特定のリモートコマンドがブロックされる場合があることに注意してください。

複数のコマンドやスクリプトをリモートで実行する — はい、できます

一度に複数の処理を実行したいですか?ScriptBlock内でコマンドをセミコロンで区切るだけです。

Invoke-Command -ComputerName dc01 -ScriptBlock { Get-TimeZone; Set-TimeZone -Name "Central Europe Standard Time" }

また、 などのどこかに保存したスクリプトがある場合は、次のようにしC:\PS\CheckStatus.ps1てリモートで実行できます。

Invoke-Command -ComputerName dc01 -FilePath "C:\PS\CheckStatus.ps1"

この方法なら、スクリプトをリモートシステムに手動でコピーする必要がなく、実行ポリシーの不一致も回避できます。定期的に実行するバッチジョブや管理スクリプトに便利です。

注意:スクリプトがリモートリソース(ネットワーク共有など)にアクセスする場合、恐ろしい「ダブルホップ」問題が発生する可能性があります。これはWindowsのセキュリティ上の問題です。Kerberos委任などの回避策をGoogleで検索するか、CredSSPを使用してください。そうしないと、資格情報がサードパーティのリソースに渡されません。

複数のコンピューターで同時にコマンドを実行する

複数のサーバーに対する並列コマンド

複数のサーバーを管理している場合、コマンドを逐次実行するのは面倒です。幸いなことに、Invoke-Command を使えば並列実行が可能です。サーバーをカンマで区切って列挙するだけです。

Invoke-Command server1, server2, server3 -ScriptBlock { get-date }

再利用のために名前を配列に保存することもできます。

$servers = @("server1", "server2", "server3") Invoke-Command -ComputerName $servers -ScriptBlock { get-date }
または、テキスト ファイルからリストを入力して、自動化を簡単にすることもできます。

Invoke-Command -ComputerName (Get-Content c:\ps\servers.txt) -ScriptBlock { Restart-Service spooler }

Active Directory からホスト名を取得する場合、Get-ADComputerコマンドレットを使用すると、特定のシステムをフィルター処理できます。

$computers = (Get-ADComputer -Filter 'OperatingSystem -like "*Windows server*" -and Enabled -eq "true"').Name Invoke-Command -ComputerName $computers -ScriptBlock { Get-EventLog -LogName System -Newest 10 } -ErrorAction SilentlyContinue

1つ以上のターゲットがオフラインまたはビジー状態の場合はどうでしょうか?-ErrorAction SilentlyContinueパラメータを使用すると、スクリプトはスムーズに実行されます。また、どのマシンが応答したかを確認するには、 ScriptBlock 内でPSComputerName変数を使用します。

$results = Invoke-Command -ComputerName $computers -ScriptBlock { get-date } $results | Select-Object PSComputerName, * 

PowerShellリモート永続接続 – 時間と手間を節約

長く続くセッションを作成する

同じリモートマシンで複数のコマンドを実行する場合、毎回再接続するのではなく、セッションを維持しておく方が合理的です。永続セッションの作成と使用方法は次のとおりです。

$session = New-PSSession -ComputerName Server01, Server02 Invoke-Command -Session $session -ScriptBlock { Get-ComputerInfo | select OsLastBootUpTime }

完了したら、次のコマンドでセッションを閉じます。

Remove-PSSession $session

この設定は、複数のサーバーを管理する際に、特にスクリプトやスケジュールされたジョブで多数のコマンドを実行する場合に、大幅な時間節約につながります。ただし、セッションはメモリ上に残る可能性があるため、不要になったら閉じるようにしてください。また、設定によっては、永続セッションを許可するために、セキュリティの調整やポリシーの変更が必要になる場合があります。

正直なところ、PowerShell リモート管理を初めて使い始めると、まるでボスを倒したような気分になりますが、一度使いこなせるようになると、その威力はとてつもなく強力です。ただし、ネットワークとファイアウォールのルールを確認し、多少の不具合には我慢してください。