-
Notifications
You must be signed in to change notification settings - Fork 0
MS_PowerShellRemoting
- 戻る(PowerShell)
リモートコンピューターで PowerShell のコマンドを実行する方法についてまとめる。
invoke-command マシン名やSessionを指定 -scriptblock { ・・・コード・・・ }
invoke-command マシン名やSessionを指定 -filepath ファイルパス※ Session を指定すれば処理中のジョブ等に再接続することも可能。
移行メモ(体裁): 移行元では上記の注記が
#で始まっており、
PukiWiki 上は本文として扱われていた。
Markdown では見出し記法と衝突するため「※」に置き換えた。
補足(PowerShell リモート処理の全体像): 本ページは
Workgroup(非ドメイン)環境という最も面倒なケースを扱っている。
前提を整理しておくと、以降の手順の意味が分かりやすい。【PSRemoting の基盤】★ PowerShell Remoting └ WS-Management(WS-Man)… 標準プロトコル └ WinRM サービス … Windows の実装 └ HTTP:5985 / HTTPS:5986 ★ (旧 80/443 から変更された) 【認証方式と難易度】★ ・【ドメイン参加】環境 → Kerberos で相互認証できる → 【設定はほぼ Enable-PSRemoting だけ】★ ・【Workgroup】環境(本ページ) → Kerberos が使えず NTLM になる → サーバの真正性を確認できない → だから【TrustedHosts に手で登録する】必要がある → 本ページの手順が長いのはこのため 【もう一つの選択肢】 ・【HTTPS(5986)+ 証明書】で構成する → TrustedHosts が不要になる ★ → 証明書の配布・更新は必要 → Workgroup で恒久運用するならこちらが本筋
Invoke-Command を使って、リモートでコマンド実行ができます。
- ただし、事前に構成を変更しておく必要があります。
- また、実行する要件によっては追加の構成が必要です。
- PowerShell リモート処理を有効にする
Enable-PSRemoting Enable-PSRemoting は、PowerShell を使ってリモートからコマンド実行できるように、
以下の様な構成変更をまとめて行います。
- WinRM サービスを起動します。
- WinRM サービスのスタートアップの種類を [自動] に設定します。
- 任意の IP アドレスで要求を受け入れるためのリスナーを作成します。
- WS-Management 通信のファイアウォール例外を有効にします。
- "Microsoft.PowerShell" セッション構成がまだ登録されていない場合は登録します。
- "Microsoft.PowerShell32" セッション構成が 64 ビット コンピューターで
まだ登録されていない場合は登録します。 - 登録済みのすべてのセッション構成のセキュリティ記述子から
"Deny Everyone" 設定を削除します。 - WinRM サービスを再起動して、変更を有効にします。
解放しすぎる場合は(任意の IP アドレスで..など)、範囲を調整する必要があるか、検討ください。
リモートから実行の可否を制御するには、ユーザーと権限(後述)、または、
ファイアウォール例外("Windows リモート管理 (HTTP 受信)")のスコープ設定で行います。
移行メモ(体裁・誤字): 上記引用の 1 行目は移行元で
PukiWiki の打ち消し記法(%%...%%)が使われていたため、
GitHub の打ち消し記法(~~...~~)に変換した。
また「ファイルウォール例外」を「ファイアウォール例外」に修正した。
- PowerShell リモート処理可能なユーザーと権限の設定
Set-PSSessionConfiguration Microsoft.Powershell -ShowSecurityDescriptorUI 実行すると権限を設定する画面が表示されるので、リモートから指定するユーザーと
権限を追加。
(Administrators メンバー以外のユーザーを使用する場合に必要)
補足(
Enable-PSRemotingは何を開けるのか): 上の一覧のうち、
セキュリティ上いちばん効くのはファイアウォール規則の範囲である。【ファイアウォール規則のスコープ】★ ・Enable-PSRemoting は 「Windows リモート管理 (HTTP 受信)」を有効化する ・ネットワーク プロファイルが 【パブリック】の場合、 既定では【同一サブネットのみ】に制限される → Enable-PSRemoting -SkipNetworkProfileCheck で 強制的に有効化できるが、 【範囲が広がるので慎重に】★ 【範囲を絞る】 Set-NetFirewallRule -Name "WINRM-HTTP-In-TCP" ` -RemoteAddress 10.0.0.0/24 【セッション構成(Endpoint)で絞る方が強力】★★ ・【JEA(Just Enough Administration)】 → 「このユーザーはこのコマンドだけ実行できる」 という制限付きエンドポイントを作れる → 管理者権限を渡さずに 特定の運用作業だけ委譲できる ★ → Workgroup / ドメインどちらでも使える New-PSSessionConfigurationFile -Path .\ops.pssc ` -SessionType RestrictedRemoteServer ` -VisibleCmdlets 'Get-Service','Restart-Service' Register-PSSessionConfiguration -Name Ops -Path .\ops.pssc → 本ページの「権限を設定する画面」より 【はるかに細かく制御できる】
- WinRM サービスを開始
Start-Service WinRMWinRM サービスを開始していなければ実行します。
- UAC のリモート設定
Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System -Name LocalAccountTokenFilterPolicy -Value 1 -Type DWord 管理者特権を維持するように設定変更します。
これをしないと、下の wsman:localhost\client\trustedhosts の設定が出来ません。
- 対象のコンピュータを 信頼されたホストの一覧に追加
set-item wsman:localhost\client\trustedhosts -value リモートコンピュータ名 リモートコンピュータ名 が複数ある場合は、
"リモートコンピュータ名,リモートコンピュータ名" の様に 文字列にして , で繋ぎます。
既存の設定値に追加する場合は、get-item で値を確認し、 , で連結して設定します。
移行メモ(体裁・誤字): 移行元では上記 2 のコマンドが
「(上は、行を折り返しています、1行のコマンドです。)」という注記付きで
3 行に分けて記載されていたため、1 行のコマンドとして整形した
(本ページ内 2 箇所)。
また「依存の設定値に追加する場合」を「既存の設定値に追加する場合」に修正した。
※ LocalAccountTokenFilterPolicy と wsman:localhost\client\trustedhosts の関係について。
wsman:localhost\client\trustedhostsを設定するためには、以下の条件があります。
- 管理者実行のコマンドプロンプト(PowerShell) で行う場合は、
LocalAccountTokenFilterPolicy を 1 にする - ビルトイン Administrator で行う場合は、 LocalAccountTokenFilterPolicy の変更は不要
-
wsman:localhost\client\trustedhostsを設定した後は、
LocalAccountTokenFilterPolicy を 0 に戻しても構いません。
(LocalAccountTokenFilterPolicy を 0 に戻してもすぐには設定不可能に戻りません。
その場合は WinRM サービスを再起動します。)
補足(
LocalAccountTokenFilterPolicyの意味と危険性): このレジストリは
UAC のリモート制限を解除するもので、副作用が大きい。【既定の動作(UAC リモート制限)】★ ・リモートからローカル アカウントで接続すると、 Administrators のメンバーであっても 【フィルタされた(標準ユーザー相当の)トークン】が 与えられる → 管理者操作ができない ・例外は【ビルトイン Administrator(RID 500)】のみ → 原文の 2 番目の条件はこれを指している ★ 【1 にすると何が起きるか】 ・リモート接続で【完全な管理者トークン】が渡る ・つまり → 管理共有(\\host\C$)にアクセスできる → リモートでレジストリを操作できる → 【Pass-the-Hash 攻撃の横展開が容易になる】★★ 【推奨】 ・原文が書くとおり、 【設定後は 0 に戻す】★ ・恒久的に必要なら ドメイン参加 or HTTPS + 証明書を検討する ・そもそも 【TrustedHosts に "*" を入れない】 → 中間者攻撃を無条件に許すことになる ★
- Invoke-Command を実行
Invoke-Command -ComputerName リモートコンピュータ名 -Credential (get-credential) -ScriptBlock { リモートコマンド リモートコマンド引数... } (get-credential) によって、ユーザー名を入力する画面が開きます。
-Credential (get-credential) を指定しないと、Invoke-Command を実行している
ユーザーで、リモートコンピュータへ接続し、コマンド実行されます。
ユーザー名を入力したくない場合は、 get-credential を先に行って、変数に入れておくか、
-Credential を指定しないようにします。
- PowerShell でリモート実行するコマンドから、
ファイル共有などのネットワークリソースへアクセスする際は、匿名ユーザーが使われます。
リモートのコマンド実行の中からネットワークリソースへユーザー指定でアクセスする場合は、
後述のダブルホップ編を参照するか、
sysinternals の psexec ツール を検討ください。
( psexec は サービス・タスク系のいろいろ も参照ください。)
移行メモ(誤字): 移行元の「ネットワーリソース」を
「ネットワークリソース」に修正した。
-
Invoke-Command は リモートとの通信用に http や https も使用できます。
それらの構成方法、オプションなどは、各コマンドを get-help で確認ください。- また、リモートとの通信に proxy を使用することもできます。
- 必要であれば netsh コマンドなどで winhttp の proxy を設定する、
通信できない場合に winhttp proxy が原因になっていないか確認ください。
-
Credential を指定しない場合は、PowerShell を実行しているアカウントが使われます。
- Get-Credential はパスワード入力のためにポップアップ画面を表示します。
バックグラウンド処理など、画面表示をしたくない場合には、
パスワードを事前に暗号化してファイルに保存しておくこともできます。 - パスワードをファイルに保存する方法、
ファイルから取り出して Credential オブジェクトを作成する方法は、
下のページを参考ください。- ヒント: 資格情報を受け付ける Windows PowerShell スクリプトを作成する
http://technet.microsoft.com/ja-jp/windows/ps_tips13.aspx
- ヒント: 資格情報を受け付ける Windows PowerShell スクリプトを作成する
- Get-Credential はパスワード入力のためにポップアップ画面を表示します。
補足(パスワードのファイル保存は「同一ユーザー・同一マシン」限定):
この手法は便利だが、制約を知らずに使うと運用時に破綻する。【仕組み】★ ConvertFrom-SecureString は 既定で【DPAPI】(Data Protection API)を使う → 【現在のユーザー + 現在のマシン】に紐付いて暗号化 # 保存 (Get-Credential).Password | ConvertFrom-SecureString | Set-Content cred.txt # 復元 $sec = Get-Content cred.txt | ConvertTo-SecureString $cred = New-Object PSCredential('user', $sec) 【破綻する場面】★★ ・【別のユーザー】で実行すると復号できない → タスク スケジューラで 別アカウントを指定した瞬間に失敗する ★ ・【別のマシン】にコピーしても復号できない ・ユーザー プロファイルを作り直すと失われる 【-Key を使えば移植できるが】 ConvertFrom-SecureString -Key $bytes → 鍵を渡せば他マシンでも復号できる → 【その鍵をどこに置くのか】という問題が残る → 本質的な解決にならない ★ 【現在の推奨】★ ・【SecretManagement / SecretStore】モジュール Install-Module Microsoft.PowerShell.SecretManagement Get-Secret -Name MyCred → Azure Key Vault / KeePass 等とも連携できる ・【gMSA(グループ管理サービス アカウント)】 → パスワードを持たずに認証する(ドメイン環境)★ ・証明書ベースの認証 ・.NET Core 以降の PowerShell 7 では 【DPAPI が非 Windows で使えない】点にも注意
- Invoke-Command -ComputerName Server1,Server2,... の様に複数のサーバーを記述すると、
それらのサーバーに対して同時実行します。
実行結果は、PowerShell のオブジェクトとして、1つの配列に混合されて返ります。
(cmd.exe など PowerShell でないコマンドを実行した場合は String(文字列) の配列になる。)
オブジェクトには PSComputerName プロパティが付加されるので、
サーバー別にソートしたり区別したいときは PSComputerName で判断できます。
同時ではなく、順に実行したい場合は、-ComputerName に1つずつ指定します。
移行メモ(誤字): 移行元の「-ComputerName に1つつず指定します」を
「1つずつ指定します」に修正した。
補足(並列実行の上限とオブジェクトの制約): 複数サーバーへの同時実行は
強力だが、2 つの注意点がある。【① 同時実行数の上限】★ ・既定の【ThrottleLimit は 32】 ・それを超える台数を指定すると 順次キューイングされる → -ThrottleLimit で調整する → 上げすぎると呼び出し側が詰まる 【② 返るオブジェクトは「デシリアライズ済み」】★★ ・リモートからの戻り値は XML でシリアライズされて運ばれる → 型名が【Deserialized.System.XXX】になる → 【メソッドが呼べない】(プロパティのみ)★ $s = Invoke-Command -ComputerName X ` -ScriptBlock { Get-Service W32Time } $s.Stop() # ← 【失敗する】 【対処】 ・操作は【リモート側のスクリプト ブロック内で完結】させる ・戻すのは「結果の値」だけにする ★【PowerShell 7 での改善】 ・【ForEach-Object -Parallel】が追加された → ローカルの並列処理 ・SSH ベースのリモーティングが使える ★ Invoke-Command -HostName host -UserName user -SSHTransport → WinRM / TrustedHosts の設定が不要 → Linux とも相互に接続できる → 【Workgroup 環境での有力な代替】★
- Invoke-Command については、下のページも参照ください。
- Windows PowerShell: リモート処理について
http://technet.microsoft.com/ja-jp/magazine/gg981683.aspx
- Windows PowerShell: リモート処理について
(ダブルホップについては ベース クライアント セキュリティ モデル を参照)
上の Workgroup 編では、リモートコマンドの中から、他サーバーのリソースにアクセスすると、
匿名ユーザーが使用されますが、
下の手順の様に、ダブルホップを使用することで、
-credential で指定するものと同じアカウントで 他サーバーのリソースに
アクセスすることができます。
補足(ダブルホップ問題とは): 本節の前提を明示しておく。
【ダブルホップ(二重ホップ)問題】★ あなたのPC ──①認証──→ サーバA ──②?──→ サーバB (成功) (失敗する) ・① で使った資格情報は サーバ A に【委任されない】 ・サーバ A から B へ行こうとすると 【匿名(NULL セッション)】になる → 「アクセスが拒否されました」 【なぜ既定で禁止されているのか】★ ・資格情報を渡すと、 サーバ A が【あなたになりすませる】 ・A が侵害されていた場合、 被害が B 以降へ無制限に広がる → だから【明示的に有効化する仕組み】になっている 【解決手段の比較】★ ・【CredSSP】(本ページの手法) → 資格情報を【平文相当で A に渡す】 → 実装が簡単だが【最も危険】★ → Microsoft も「他に手段がない場合のみ」と注意喚起 ・【Kerberos の制約付き委任】 → ドメイン環境でのみ可能 → 【委任先を限定できる】ので安全 ★ → 可能ならこちらを選ぶ ・【リソース ベースの制約付き委任(RBCD)】 → さらに新しい方式。委任される側が許可する ・【そもそも二重ホップしない設計にする】★★ → B の処理を 「A から呼ぶ」のではなく 「手元から直接 B に対して行う」 → 二段階のスクリプトに分ける → 最も安全で、最も見落とされがちな選択肢
- リモート先でリモートコマンドを呼ばれる準備 (PowerShell を 管理者として実行)
# 1.
Enable-PSRemoting
# 2.
Set-PSSessionConfiguration Microsoft.Powershell -ShowSecurityDescriptorUI- リモートを呼び出す側の準備 (PowerShell を 管理者として実行)
# 1.
Start-Service WinRM
# 2.
Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System -Name LocalAccountTokenFilterPolicy -Value 1 -Type DWord
# 3.
set-item wsman:localhost\client\trustedhosts -value リモートコンピュータ名- リモート先で資格情報を受け取る準備 (PowerShell を 管理者として実行)
# 1.
Enable-WSManCredSSP -Role Server- リモートを呼び出す側で、資格情報を送信する準備 (PowerShell を 管理者として実行)
# 2.
Enable-WSManCredSSP -Role Client -DelegateComputer リモートコンピュータ名- リモートを呼び出す側で、資格情報を NTLM 認証で行う様にグループポリシーを設定
# 3. gpedit.msc コマンド
コンピューターの構成 >> 管理用テンプレート >> システム >> 資格情報の委任
NTLMのみのサーバー認証で新しい資格情報の委任を許可する
(x) 有効
サーバーを一覧に追加: [表示]
wsman/リモートコンピュータ名
リモートでコマンドを実行
- Invoke-Command に -Authentication CredSSP を付けて実行
Invoke-Command -ComputerName リモートコンピュータ名 -Credential (get-credential) -ScriptBlock { cmd.exe /c "dir \\リソースサーバー\ファイル共有" } -Authentication CredSSP(-ScriptBlock { ... } の中は例です。)
移行メモ(誤字・体裁): 移行元の「-Authentication CredSSP を付けてを実行」の
重複した助詞を整理した。
また折り返し注記付きで複数行に分かれていたコマンドを 1 行に整形した。
補足(CredSSP の既知の脆弱性): この手法を使う前に、
必ず知っておくべき事故がある。【CVE-2018-0886(CredSSP の暗号化オラクル脆弱性)】★★ ・2018年3月に公開された【リモートコード実行】の脆弱性 ・中間者が CredSSP セッションに介入し、 委任された資格情報を悪用できた ・修正後、Microsoft は 【既定のポリシーを「緩和済みクライアントのみ許可」に変更】 → 【パッチ適用状況が食い違うと接続できなくなる】★ → 「昨日まで動いていた RDP / CredSSP が 突然エラーになる」の原因として有名 ・回避のためにレジストリで AllowEncryptionOracle=2(脆弱)に戻す手順が ネット上に多数あるが、 【絶対に行ってはならない】★★ → 双方にパッチを当てるのが正解 【CredSSP を使う場合の最低限の防御】 ・【HTTPS(5986)で使う】★ → 平文の HTTP で CredSSP は避ける ・-DelegateComputer に【ワイルドカード(*)を使わない】 ・使い終わったら Disable-WSManCredSSP -Role Client Disable-WSManCredSSP -Role Server で【必ず無効化する】★ ・委任するアカウントの権限を最小にする → 原文の注意事項(Administrators でなくてよい)は まさにこの趣旨であり、適切な助言である ★
'-credential で指定する ユーザー について
-credential で指定する ユーザーおよびパスワード は、
リモートコンピュータ名 と リソースサーバー の両方に共通なものを作成しておきます。
上の例で\\リソースサーバー\ファイル共有の共有フォルダは、
指定する ユーザー で参照権限を設定しておきます。
リモートコンピュータ上のユーザーは、Administrators でなくてもかまいません。
リモートコマンドの内容に応じて 権限を付加してください。
移行メモ(リンク切れ): 本ページの
technet.microsoft.comは
2018〜2019 年に Microsoft Learn へ統合されており、到達しない。
記録として残す。
Tags: 移行, シェル, インフラストラクチャ, Windows
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。