PowerShell Remoting(WinRM)入門 ── 一次管理多台 Windows

· · PowerShell, Windows, WinRM, 遠端管理, 自動化, 維運改善, 安全性, 腳本

「Windows Update 之後,幫我確認一下 20 台伺服器是不是都正常啟動了」「請幫忙查一下所有據點的 PC 上,那個設定值現在是什麼狀態」── 面對這類要求,你是不是還在用遠端桌面一台一台登入確認?就算一台只要 3 分鐘,20 台加起來也要 1 小時。人在中途會感到厭煩,也容易發生漏檢。

PowerShell Remoting 就是把這種「對多台機器做同一件事」化為一道指令的機制。Windows 標準內建了名為 WinRM 的遠端管理基礎架構,在 Windows Server 上更是預設就已啟用。也就是說,在許多現場,不必額外安裝軟體,今天就能開始使用。儘管如此,還是常聽到「總覺得有點可怕」「在工作群組環境連不上就放棄了」這樣的聲音。

本文以中小企業的資訊系統與維運人員為對象,整理 Remoting 的運作機制(什麼在哪個連接埠上運作、誰能連線)、以 Invoke-Command 進行批次執行、網域環境與工作群組環境的差異、像 second hop 問題這樣有名的陷阱、連不上時的故障排除,以及「先從讀取開始」的安全維運方式。

前提環境

  • 被連線的一端: Windows Server 2012 以後的 Windows Server,PowerShell Remoting 預設已啟用1 用戶端版 Windows 的 WinRM 服務預設為停用,因此需要透過 Enable-PSRemoting 來啟用。1
  • 發起連線的一端: 本文中的指令範例,只使用 Windows PowerShell 5.1 與 PowerShell 7 兩者都具備的 Cmdlet。不過 WSMan: 磁碟機與 Test-WSMan 等 WS-Management 相關 Cmdlet,僅能在 Windows 上的 PowerShell 中使用(Linux・macOS 上的 PowerShell 要使用第 6 章介紹的 SSH 版 Remoting)。2
  • 權限: 變更遠端那一端的設定(Enable-PSRemoting、TrustedHosts、接聽程式),都需要以系統管理員身分啟動的 PowerShell1
  • 網路: 本文同時處理網域環境與工作群組環境,兩者的差異整理在第 3 章。

1. 先講結論

  • PowerShell Remoting 運作在 WinRM(WS-Management 實作)之上,預設使用 HTTP 5985 / HTTPS 5986 連接埠。即使是 HTTP,通訊內容也會由驗證通訊協定施加訊息層級的加密。3
  • 預設情況下,只有遠端那一端 Administrators 群組的成員才能連線,且工作階段是在連線使用者的內容中執行。並非「只要啟用了 Remoting,任何人都能進來」。3
  • Enable-PSRemoting 所做的事有明確定義。包括啟動 WinRM 服務並設為自動啟動、建立接聽程式、建立防火牆例外、啟用工作階段組態。Windows Server 預設已啟用,用戶端版 Windows 則需要手動啟用。43
  • 網域環境靠 Kerberos 就能直接運作,工作群組則需要 NTLM + TrustedHosts + 明確指定的認證資訊。TrustedHosts 並不是「信任對方」的設定,而是「放棄驗證對方身分的清單」,所以應盡量壓到最小限度。53
  • 批次執行用 Invoke-Command,互動操作用 Enter-PSSession,想保留狀態並重複使用則用 New-PSSession。Invoke-Command 預設最多可同時平行處理 32 台。67
  • 從遠端回傳的是反序列化後的物件,不具備方法(method)。操作應在 ScriptBlock 內(遠端那一側)完成,本機端只負責彙整結果。87
  • 無法從連線目標再進一步存取其他伺服器(second hop 問題)。這並非缺陷,而是「不將認證資訊送到遠端」這種安全設計下的必然結果。對策有好幾種,可依需求選擇。9
  • PowerShell 7 也可以使用以 SSH 為基礎的 Remoting。這是需要與 Linux 交互管理,或不希望開放 WinRM 的環境的一個選項。2

2. 運作機制 ── 在 WinRM 之上,誰能以何種方式登入

PowerShell Remoting 的基礎是 WinRM(Windows Remote Management)。WinRM 是標準通訊協定 WS-Management 的 Microsoft 實作,PowerShell Remoting 透過這個 WinRM,把命令送達遠端電腦上的 PowerShell。3 通訊預設使用 HTTP 5985 埠與 HTTPS 5986 埠。35

常有人擔心「用 HTTP 是不是等於明文傳輸」,但初次驗證完成之後,WinRM 就會把通訊內容加密。HTTPS 使用 TLS,HTTP 則使用驗證通訊協定協商出的訊息層級加密(若是 Kerberos,在現代環境中即為 AES-256)。3 此外,預設能連線的只有遠端那一端 Administrators 群組的成員,而且工作階段是在連線使用者的內容中執行,因此對檔案與登錄檔的存取控制,依然會照常套用。3

接收端的準備工作是 Enable-PSRemoting。這個 Cmdlet 會做什麼,官方文件有明確列出。它會在內部執行 Set-WSManQuickConfig,完成:(1)啟動 WinRM 服務、(2)將啟動類型設為自動、(3)建立可在任意 IP 位址接收要求的接聽程式、(4)啟用 WS-Management 通訊的防火牆例外、(5)建立並啟用工作階段組態(端點)並允許遠端存取,最後重新啟動 WinRM 服務。4

# 在「被連線」的那一端,以系統管理員權限的 PowerShell 執行一次即可
# (Windows Server 預設已啟用,通常不需要。用戶端版 Windows 才需要)
Enable-PSRemoting

# 從「發起連線」的那一端做連線測試 ── 只要這裡能通,Remoting 的基礎就已經就緒
Test-WSMan -ComputerName sv-app01

有兩個不知道就容易踩到的規格。第一是防火牆。伺服器版 Windows 上,Enable-PSRemoting 即使針對公用網路,也會建立「僅允許來自同一子網路」的規則;但用戶端版上,如果網路設定檔是公用,啟用本身就會直接失敗(這是把驗證機接上公司 Wi-Fi 時的經典狀況)。這種情況下,可以加上 -SkipNetworkProfileCheck,或是把網路設定檔改為私人。4

第二是 PowerShell 版本與端點之間的關係。Enable-PSRemoting 會設定「執行時所用 PowerShell 版本專屬」的端點。用 PowerShell 7 執行,不會影響 Windows PowerShell 5.1 的端點,反過來也一樣。4 而且即使是從 PowerShell 7 發起連線,預設也會使用 Windows PowerShell 5.1 既有的端點(Microsoft.PowerShell)10,因此「明明本機是 7,遠端實際跑的卻是 5.1」是很常見的情況。請養成在遠端那一端顯示 $PSVersionTable 來確認的習慣。

3. 網域與工作群組 ── 驗證的門檻在這裡

初學 Remoting 時最容易卡關的,不是指令的語法,而是驗證。所需的準備工作會因環境而異。

項目 網域環境 工作群組環境
驗證通訊協定 Kerberos(有相互驗證)5 NTLM(不驗證伺服器身分)5
額外設定 原則上不需要。直接用電腦名稱連線即可 需要在連線端登錄到 TrustedHosts5
認證資訊 直接使用目前登入的使用者 基本上要用 -Credential 明確指定
以 IP 位址指定 需要登錄 TrustedHosts 或使用 HTTPS11 同左

若是網域環境,由於 Kerberos 的相互驗證(用戶端與伺服器互相驗證彼此)會發揮作用,Invoke-Command -ComputerName sv-app01 { ... } 可以直接執行。工作群組因為無法使用 Kerberos5,所以要在連線端的 TrustedHosts 中登錄對方。

# 在「發起連線」的一端,以系統管理員身分啟動的 PowerShell 執行(僅工作群組環境需要)
# 變更 TrustedHosts 也需要系統管理員權限。既有值會被覆寫,所以先確認目前的值
Get-Item WSMan:\localhost\Client\TrustedHosts

# 只追加必要最小限度的主機名稱。沒有 -Concatenate 的話,既有的登錄會被清除。請避免用 '*' 全部允許
Set-Item WSMan:\localhost\Client\TrustedHosts -Value 'sv-app01,sv-app02' -Concatenate

# 明確指定認證資訊並測試連線
$cred = Get-Credential sv-app01\Administrator
Invoke-Command -ComputerName sv-app01 -Credential $cred -ScriptBlock { hostname }

這裡重要的是 TrustedHosts 的真正意涵。官方文件明確寫著:「登錄在 TrustedHosts 中的電腦不會被驗證,用戶端有可能因此把認證資訊送出去」。5 也就是說,與其說這是「值得信任的對象清單」,不如說它是「用來抑制『無法驗證伺服器身分』警告的清單」3 在 DNS 或 ARP 被動過手腳的環境中,存在把系統管理員認證資訊交給偽造伺服器的風險。所以要避免登錄萬用字元,只登錄固定且必要最小限度的主機名稱・IP。若是要正式營運的工作群組環境或 DMZ,實務上的判斷是準備好憑證、設定 HTTPS(5986)接聽程式會是更好的做法。3

另外,如果開始把 Get-Credential 取得的認證資訊以明文寫進腳本裡,就是一個危險訊號。認證資訊的保存與傳遞的標準做法,整理在同時發布的「PowerShell 中安全處理認證資訊 ── 把明文密碼逐出腳本」中。

在工作群組環境中,還有一個容易被忽略的重點是密碼是否存在。如果連線目標的帳戶未設定密碼(空白密碼),就無法執行遠端命令。1

3.1. 設定 HTTPS(5986)接聽程式

若要在工作群組或 DMZ 環境中長期使用,不要只靠 TrustedHosts 湊合,而應該架設 HTTPS 接聽程式。步驟大致如下。12

  1. 準備一張伺服器驗證用的憑證。要求為「必須是本機電腦的伺服器驗證憑證」「CN(或主體別名)必須與主機名稱一致」「必須在有效期限內、未被撤銷,且不是自我簽署」。如果公司內部有 CA,可以透過 https://<憑證授權單位伺服器>/certsrv 的網頁註冊功能提出申請。
  2. 把憑證放進本機電腦的個人存放區。可透過憑證嵌入式管理單元(在 MMC 中加入「憑證」,並在精靈中選擇「電腦帳戶」)的 憑證(本機電腦) > 個人 > 憑證 進行確認。
  3. 建立 HTTPS 接聽程式。最簡便的方式是下面這一行指令。

     winrm quickconfig -transport:https
    

    若有多張憑證,想明確指定要使用哪一張,也可以從 PowerShell 指定憑證指紋來建立(可用 Get-ChildItem Cert:\LocalMachine\My 確認指紋)。

     New-Item -Path WSMan:\localhost\Listener -Address * -Transport HTTPS -CertificateThumbPrint '憑證的指紋' -Force
    
  4. 在防火牆上允許 TCP 5986 的傳入流量。因為 Enable-PSRemoting 建立的規則是針對 HTTP(5985),HTTPS 需要另外處理。
  5. 確認接聽程式是否已建立。

     winrm enumerate winrm/config/listener
    

連線端只需要加上 -UseSSL 即可。

Invoke-Command -ComputerName sv-app01.example.local -UseSSL -Credential $cred -ScriptBlock { hostname }

如果憑證不符合條件,在建立接聽程式時就會出現「Cannot create a WinRM listener on HTTPS because this machine does not have an appropriate certificate.(錯誤碼 -2144108267 / 0x80338115)」的錯誤。這種情況下,請依序確認憑證的有效期限、發行對象是否與主機名稱一致、增強金鑰使用方式是否包含「伺服器驗證」,以及憑證路徑是否有效。12

4. Invoke-Command ── 「對 20 台做同一件事」的基本做法

Remoting 的主角是 Invoke-Command。把多台主機傳給 -ComputerName,並在 -ScriptBlock 中寫下「要在遠端做的事」。6 先從唯讀性質的盤點作業開始,是安全維運的鐵律。

$servers = 'sv-app01', 'sv-app02', 'sv-db01'

# 確認套用修補程式後的狀態 ── 只是讀取,可以放心執行
$result = Invoke-Command -ComputerName $servers -ScriptBlock {
    # 這個區塊裡的內容是在「遠端」執行
    $os = Get-CimInstance Win32_OperatingSystem
    [PSCustomObject]@{
        LastBoot   = $os.LastBootUpTime                      # 是否已完成重新啟動
        SpoolerRun = (Get-Service -Name Spooler).Status      # 業務所需服務的狀態
        FreeGB     = [math]::Round((Get-PSDrive C).Free / 1GB, 1)
    }
}

# 哪個結果來自哪台伺服器,可以透過 PSComputerName 得知
$result | Sort-Object PSComputerName |
    Select-Object PSComputerName, LastBoot, SpoolerRun, FreeGB |
    Export-Csv -Path .\patch-check.csv -NoTypeInformation -Encoding UTF8

對各伺服器的連線是平行處理的,預設的同時執行數(ThrottleLimit)為 32。7 結果會依照抵達的先後順序混雜返回,因此像上面的範例一樣,要用自動附加的 PSComputerName 屬性重新排序。8

4.1. 傳遞變數的方法 ── $using: 與 -ArgumentList

ScriptBlock 是在遠端執行,所以本機端的變數原封不動是看不到的。要把值帶進去,有兩種方法。13

$threshold = (Get-Date).AddDays(-30)

# 方法 1: $using: ── 把呼叫端變數的「值的副本」內嵌到遠端
Invoke-Command -ComputerName $servers -ScriptBlock {
    (Get-ChildItem 'D:\AppLogs' -Filter *.log |
        Where-Object LastWriteTime -lt $using:threshold).Count
}

# 方法 2: -ArgumentList ── 在 ScriptBlock 端用 param 接收(參數較多時較易讀)
Invoke-Command -ComputerName $servers -ScriptBlock {
    param($limit)
    (Get-ChildItem 'D:\AppLogs' -Filter *.log |
        Where-Object LastWriteTime -lt $limit).Count
} -ArgumentList $threshold

透過 $using: 傳遞的值,在遠端那一側是獨立的副本。就算在遠端改寫,本機端的變數也不會跟著改變。13

4.2. 回傳的是「快照」── 反序列化後的物件

使用 Remoting 時,最先讓人感到困惑的就是這一點。活生生的 .NET 物件無法跨越網路傳輸,因此遠端的輸出會先序列化為 XML(CLIXML)再傳送,並在本機端還原成反序列化後的物件。這是執行當下屬性值的快照,不具備方法。87

舉例來說,不能在本機端接收 Get-Service 的結果後呼叫 .Stop()。如果想停止服務,就要在 ScriptBlock 內執行 Stop-Service ── 換句話說,正確的做法是把角色分開:操作在遠端那一側完成,帶回本機端的只有用於報告的資料。至於屬性的篩選、整理、轉成 CSV 等在本機端進行的加工,則可以用平常操作 PowerShell 的感覺來處理(這部分的基本操作可以參考「PowerShell 指令基礎 ── 該先學會的操作與安全使用方式」)。

5. Enter-PSSession 與 New-PSSession ── 互動操作與重複使用

想以互動方式調查單一一台主機時,可以使用 Enter-PSSession。提示字元會變成 [sv-app01]: PS>,輸入的指令會在遠端執行。用 exit 退出。11 與遠端桌面不同,不會帶來畫面,但如果只是「看看日誌」「確認設定」這種程度的工作,這種方式反而更快,而且同樣需要是 Administrators 群組的成員才能連線。11

另一方面,每次以 -ComputerName 呼叫 Invoke-Command,都會重新建立並拆除連線。14 在需要對同一群伺服器多次下達指令的調查工作中,用 New-PSSession 建立持續性的工作階段並重複使用,速度會更快,而且遠端那一側的變數與狀態也會在多次指令之間保留下來。1415

# 只建立一次工作階段,之後用變數 $s 重複使用
$s = New-PSSession -ComputerName $servers
try {
    # 第 1 次: 在遠端建立一個名為 $hotfix 的變數
    Invoke-Command -Session $s { $hotfix = Get-HotFix | Sort-Object InstalledOn -Descending }

    # 第 2 次: 上一個指令建立的變數可以直接沿用(工作階段保留了狀態)
    Invoke-Command -Session $s { $hotfix | Select-Object -First 5 }
}
finally {
    # 即使中途發生錯誤或中斷,也一定要釋放(釋放遠端那一側的資源)
    Remove-PSSession $s
}

6. 陷阱 ── second hop,以及 SSH 這個選項

6.1. second hop(雙重躍點)問題

這是現場最有名的一道牆。從手邊的 PC(A)透過 Remoting 進入伺服器 B,再從 B 裡面嘗試讀取 \\fs01\share(伺服器 C)時,會遭到拒絕存取。因為預設的 Kerberos/NTLM 驗證,是一種不把認證資訊本身送到 B 的安全驗證方式,所以 B 無法代替你向 C 進行驗證。39

對策有好幾種,官方文件依推薦順序整理如下。9 這裡只列出主要的幾種。

  • 在 ScriptBlock 內明確傳遞認證資訊 ── 不需要變更伺服器端設定,最為簡便。以 $using:cred 把認證資訊傳給內層的 Invoke-Command。9 不過,既然認證資訊物件會傳到中繼伺服器(B)的工作階段裡,一旦 B 遭到入侵,傳過去的認證資訊也可能被濫用,因此前提是只在完全信任 B 的情況下才使用,而且傳遞的帳戶也應該是在 C 端擁有必要最小限度權限的專用帳戶
  • 以資源為基礎的 Kerberos 約束委派 ── 不儲存認證資訊,而是在存取目標(C)那一端設定「接受來自 B 的委派」的方式。不需要網域管理員權限即可設定,是在安全性與設定簡便度之間取得良好平衡的選項。9
  • JEA(Just Enough Administration) ── 準備一個只允許「該項業務所需指令」的專用端點,藉此縮限權限的 PowerShell 機制。若採用虛擬帳戶的設定,使用者就能以非管理員的認證資訊連線,同時只執行被允許的管理指令。16 在 second hop 的情境下,這代表不必把管理員認證資訊發放到中繼伺服器(B),而是建立一個只能執行包含存取 C 在內的固定作業的窗口。9
  • CredSSP ── 認證資訊會被快取在遠端伺服器上,因此一旦該伺服器遭到入侵,認證資訊也會一併被竊取。預設為停用狀態,啟用時應僅限於最值得信賴的環境。9
# 最簡便的規避方式: 用 $using:cred 把認證資訊傳給內層的 Invoke-Command
# 對外層(sv-app01)以自己的認證資訊連線,傳給內層的則是 fs01 那一端
# 只使用擁有必要最小限度權限的專用帳戶(不發放管理員的認證資訊)
#
# 【前提】內層的呼叫等於是「從 sv-app01 到 fs01 的一個新 Remoting 連線」,因此需要:
#   1. 從 sv-app01 能連到 fs01 的 WinRM(5985/5986)
#   2. 若是工作群組或以 IP 位址指定,sv-app01 端的 TrustedHosts 必須已登錄 fs01
#   3. $cred 必須是在 fs01 上有效的帳戶(網域帳戶,或 fs01 的本機帳戶)
# 若沒有確認以上條件就直接複製貼上,經常會變成「本機端可以動,但中繼伺服器上卻失敗」
$cred = Get-Credential CONTOSO\svc-fileread
Invoke-Command -ComputerName sv-app01 -ScriptBlock {
    Invoke-Command -ComputerName fs01 -Credential $using:cred -ScriptBlock { hostname }
}

說到底,先思考「能不能不透過 B,而是從手邊直接對 C 執行 Invoke-Command」,才是成本最低的解決方案。

6.2. 若使用 PowerShell 7,也可以選擇以 SSH 為基礎的 Remoting

PowerShell 6.0 以後,可以改用 SSH 而非 WinRM 來連線進行 Remoting。Invoke-Command / Enter-PSSession / New-PSSession 新增了 -HostName-UserName-KeyFilePath 這組 SSH 專用參數,能夠橫跨 Windows 與 Linux 進行管理。2 連線目標需要有 SSH 伺服器,以及 PowerShell 的 SSH 子系統設定,而 WinRM 版本才有的端點組態或 JEA 這類功能,目前尚不支援。2 若環境中混雜著 Linux 伺服器,或想統一以金鑰驗證來維運,不妨把這個選項記在心裡。Windows PowerShell 5.1 沒有這項功能,若有需要,也可以作為遷移的動機(整體差異可參考同時發布的「Windows PowerShell 5.1 與 PowerShell 7 的差異」)。

順帶一提,Remoting 的工作階段不會像 RDP 那樣建立桌面工作階段。兩者在「於遠端執行」這件事上的意義有何不同,整理在「如何理解 Windows 的工作階段隔離 ── Session 0・RDP・多使用者同時執行」一文中。

7. 連不上時的故障排除

初學者放棄 Remoting 的理由,大多是「連不上」。而且失敗的原因,可能出在服務、接聽程式、防火牆、驗證、權限中的任何一環。從上游依序排查,就不會迷失方向。

7.1. 排查順序

  1. 確認連線是否可通。先在連線端執行 Test-WSMan -ComputerName sv-app01。如果這一步能通過,代表 WinRM 服務・接聽程式・防火牆都還活著(驗證或權限的問題仍可能存在)。若不通,請往下看。
  2. 確認遠端那一端的 WinRM 服務是否正在執行。伺服器版的啟動類型是自動,但用戶端版 Windows 的 WinRM 服務預設為停用1Get-Service WinRM 確認,必要時執行 Enable-PSRemoting(一次完成服務啟動・自動啟動化・接聽程式・防火牆例外・工作階段組態的設定)。4
  3. 確認接聽程式是否正在等待連線。在遠端那一端執行以下指令,查看 ListeningOn 是否為空。若為空,常見的原因是透過群組原則配發接聽程式的環境中設定有誤。1

     Get-WSManInstance winrm/config/listener -Enumerate
    
  4. 確認網路設定檔。用戶端版上,如果網路是公用,Enable-PSRemoting 本身就會因「Unable to check the status of the firewall」而失敗。請把設定檔改為私人,或加上 -SkipNetworkProfileCheck1
  5. 確認防火牆規則。即使是伺服器版,在公用設定檔下也會套用「僅允許來自同一子網路」的規則。若要從不同子網路連線,就需要調整規則(請先用 Get-NetFirewallRule 確認規則名稱後再修改。規則名稱會因 Windows 版本而異)。1
  6. 是否滿足驗證方式的條件。若是工作群組、未加入網域,或以 IP 位址指定的情況,都無法使用 Kerberos 而會改用 NTLM,因此登錄 TrustedHosts(或使用 HTTPS)以及明確指定 -Credential必要條件。連線目標的帳戶不能使用空白密碼。1
  7. 是否擁有可連線的權限。能連線到預設端點的,只有遠端那一端 Administrators 的成員。不同網域的使用者或本機帳戶,預設會拿到標準使用者的權杖,因此無法以管理員身分行動(如有需要可使用 LocalAccountTokenFilterPolicy,但這是對所有使用者停用 UAC 遠端限制的設定,請先理解其影響再使用)。1
  8. 確認端點的 PowerShell 版本。如果明明連上了,卻被告知「沒有那個 Cmdlet」,如同第 2 章所述,有可能是進入了 Windows PowerShell 5.1 那一側的端點。用 Invoke-Command -ComputerName sv-app01 { $PSVersionTable.PSVersion } 確認,必要時以 -ConfigurationName 明確指定。10

7.2. 常見錯誤訊息的解讀方式

錯誤訊息幾乎都是固定格式,與其死記,不如建立「看到這句話就檢查這裡」的對應關係,更為實用。1

錯誤訊息(節錄) 常見原因 首先要看的地方
Access is denied. You need to run this cmdlet from an elevated process. 手邊的 PowerShell 沒有以系統管理員權限執行 用「以系統管理員身分執行」重新開啟
ACCESS IS DENIED 連線目標未啟用 Remoting/連線的使用者不是 Administrators/不同網域・本機管理員的權杖限制 在連線目標端執行 Enable-PSRemoting、用 -Credential 指定管理員,必要時檢視工作階段組態的權限或 LocalAccountTokenFilterPolicy
The connection to the remote host was refused. Verify that the WS-Management service is running on the remote host and configured to listen for requests on the correct port and HTTP URL. WinRM 服務已停止、沒有接聽程式、連接埠不正確 Get-Service WinRM、列舉接聽程式、連接埠設定
The client cannot connect to the destination specified in the request. Verify that the service on the destination is running and is accepting requests. 接聽程式的 ListeningOn 為空(原則設定有誤)、Proxy 的影響 列舉接聽程式、New-PSSessionOption 的 Proxy 設定
The WinRM client cannot process the request. If the authentication scheme is different from Kerberos, or if the client computer is not joined to a domain, then HTTPS transport must be used or the destination machine must be added to the TrustedHosts configuration setting. 工作群組、未加入網域、以 IP 位址指定 登錄 TrustedHosts + -Credential,或依 3.1 設定 HTTPS
Unable to check the status of the firewall(執行 Enable-PSRemoting 時) 用戶端版上網路為公用 把設定檔改為私人,或使用 -SkipNetworkProfileCheck
The WS-Management service cannot complete the operation within the time specified in OperationTimeout. 處理耗時較長、對方負載較高 New-PSSessionOption -OperationTimeout 延長逾時
The total data received from the remote client exceeded allowed maximum. 回傳的資料量過大 在 ScriptBlock 內先彙整・篩選後再回傳。必要時調整配額

排查的訣竅在於逐一確定「是本機端的問題、路徑上的問題,還是對方的問題」。用 Test-WSMan 是否能通,先把路徑與對方服務這一段排查掉,通過之後的錯誤則聚焦在驗證與權限上。採用這種兩段式的做法,就不會在原因不明的情況下不斷亂改設定。

8. 實務上的判斷準則(判斷表)

論點 選項 判斷依據
以互動方式調查單一一台 RDP / Enter-PSSession 需要畫面就用 RDP,指令就能搞定則用 Enter-PSSession 較輕量11
對多台進行相同處理 一台一台手動操作 / Invoke-Command 超過 3 台就用 Invoke-Command。預設最多可平行處理 32 台67
需要多次下達指令 每次用 -ComputerName 連線 / 重複使用 New-PSSession 若調查工作需要反覆互動往返,就重複使用工作階段。結束後執行 Remove-PSSession14
工作群組的驗證 TrustedHosts(HTTP) / HTTPS 接聽程式 臨時使用就用最小限度的 TrustedHosts。長期使用則設定 HTTPS(步驟見 3.1)5312
second hop 對策 明確傳遞認證資訊 / 以資源為基礎的委派 / CredSSP 先採用不需變更設定的明確傳遞。若是常態需求則用以資源為基礎的委派。CredSSP 是最後手段9
最先執行的指令 變更類 / 讀取類 一定先用 Get 系列做盤點。變更類則先用支援 -WhatIf 的指令試跑,再正式執行

最後這一行要特別強調。Invoke-Command 既是「一瞬間修好 20 台的指令」,同時也是「一瞬間弄壞 20 台的指令」。所幸,像 Stop-ServiceSet-ItemProperty 這類變更類 Cmdlet,大多支援 -WhatIf,在 ScriptBlock 內也可以直接使用。若能養成新腳本先在 1 台上試、接著加上 -WhatIf 在全部主機上試、最後才正式執行這種三階段的習慣,事故率會明顯降低。

9. 總結

  • Remoting 運作在 WinRM(WS-Management)之上,預設連接埠為 HTTP 5985 / HTTPS 5986。預設能連線的只有遠端那一端 Administrators 的成員,通訊會在驗證後加密。
  • Enable-PSRemoting 會完成 WinRM 服務啟動・建立接聽程式・防火牆例外・啟用工作階段組態。請注意,設定出來的端點是針對執行時所用的 PowerShell 版本。
  • 網域環境用 Kerberos 就能直接運作,工作群組則需要 TrustedHosts + 明確指定的認證資訊。TrustedHosts 是放棄身分驗證的清單,務必壓到最小限度。
  • 批次執行用 Invoke-Command(預設 32 並行),互動用 Enter-PSSession,想保留狀態就重複使用 New-PSSession。結果是不具備方法的反序列化物件,所以操作要在遠端那一側完成。
  • 從連線目標無法再往下一步(second hop)。先嘗試明確傳遞認證資訊,若是長期運用,則考慮採用以資源為基礎的 Kerberos 約束委派。
  • 遇到「連不上」時,先用 Test-WSMan 排查路徑與對方的服務,再把焦點縮小到驗證(TrustedHosts・認證資訊)與權限(Administrators)上。常見錯誤訊息與對應方式整理在第 7 章的表格中。
  • 維運上先從讀取類指令開始。變更類則以「1 台 → -WhatIf → 正式執行」三階段進行。應用於檔案伺服器盤點的具體案例,請參考同時發布的「PowerShell 盤點檔案伺服器 ── 容量調查與存取權限(ACL)稽核」。

相關文章

相關諮詢領域

合同會社小村軟體承接以 PowerShell 建構伺服器・用戶端批次管理機制、設計與審查納入 Remoting 的維運腳本,以及「連不上」「只在特定環境下驗證失敗」這類 WinRM/驗證相關問題的調查。

參考連結

  1. Microsoft Learn, about_Remote_Troubleshooting。關於 Windows Server 2012 以後的 Windows Server 上 Remoting 預設已啟用、用戶端版 Windows 的 WinRM 服務預設停用、變更 WSMan: 磁碟機的設定需要系統管理員權限、常見錯誤訊息(拒絕存取/連線遭拒/Unable to check the status of the firewall/與 TrustedHosts 及 HTTPS 有關的 WinRM 用戶端錯誤/逾時/超出配額)及其對應方式、以 Get-WSManInstance 列舉接聽程式以及 ListeningOn 為空的原則設定錯誤、公用網路下防火牆規則的行為、工作群組中無法使用空白密碼的帳戶,以及不同網域・本機帳戶管理員的權杖限制與 LocalAccountTokenFilterPolicy 的說明。  2 3 4 5 6 7 8 9 10 11

  2. Microsoft Learn, PowerShell remoting over SSH。關於 PowerShell 6 以後可使用 SSH 版 Remoting、New-PSSession/Enter-PSSession/Invoke-Command 新增了 -HostName/-UserName/-KeyFilePath 參數組、可跨多個平台運作,以及端點組態與 JEA 目前尚不支援的說明。  2 3 4

  3. Microsoft Learn, Security Considerations for PowerShell Remoting using WinRM。關於 Remoting 使用 WinRM(WS-Management 的 Microsoft 實作)、預設連接埠為 HTTP 5985/HTTPS 5986、預設只有 Administrators 群組成員可以連線且工作階段在使用者的內容中執行、驗證後的通訊會加密、TrustedHosts 只是抑制身分驗證錯誤的清單,以及 second hop 問題背景的說明。  2 3 4 5 6 7 8 9 10 11 12

  4. Microsoft Learn, Enable-PSRemoting。關於 Enable-PSRemoting 所執行操作的清單(啟動 WinRM 服務・設為自動啟動、建立接聽程式、防火牆例外、啟用工作階段組態並變更安全性描述元)、Windows Server 預設已啟用、用戶端版在公用網路下的限制與 SkipNetworkProfileCheck,以及會設定對應執行版本的端點的說明。  2 3 4 5

  5. Microsoft Learn, Installation and configuration for Windows Remote Management。關於 WinRM 2.0 預設接聽連接埠為 5985/5986、網域帳戶會選用 Kerberos・本機帳戶則選用 NTLM、Kerberos 無法在工作群組中使用而僅限於網域,以及 TrustedHosts 中的電腦不會被驗證、有可能因此送出認證資訊,所以應盡量壓到最小限度的說明。  2 3 4 5 6 7 8

  6. Microsoft Learn, Invoke-Command。關於 Invoke-Command 能以單一指令對多台電腦執行命令、-ComputerName 的臨時連線與 -Session 使用 PSSession 之間的區分,以及 -ArgumentList、-FilePath 等參數的說明。  2 3

  7. Microsoft Learn, PowerShell Remoting FAQ。關於同時連線數的預設值為 32、可用 ThrottleLimit 參數變更、遠端命令的輸出會序列化為 CLIXML 並以反序列化物件(不具方法)的形式返回,以及 Invoke-Command 的結果會附加用於判別來源的屬性的說明。  2 3 4 5

  8. Microsoft Learn, about_Remote_Output。關於遠端命令的輸出經過序列化/反序列化後,會變成只保留屬性值的快照,以及結果會依抵達順序返回,因此需要以 PSComputerName 重新排序的說明。  2 3

  9. Microsoft Learn, Making the second hop in PowerShell Remoting。關於 second hop 問題的情境、對策清單及推薦順序(CredSSP、以資源為基礎的 Kerberos 約束委派、JEA 等)、CredSSP 因為會把認證資訊快取在遠端而在遭入侵時有風險、預設為停用,以及在 ScriptBlock 內以 $Using:cred 傳遞認證資訊的範例的說明。  2 3 4 5 6 7 8

  10. Microsoft Learn, Migrating from Windows PowerShell 5.1 to PowerShell 7。關於在啟用 WinRM 的環境中,PowerShell 7 預設會使用 Windows PowerShell 5.1 既有的端點(Microsoft.PowerShell)進行連線,以及若要建立 PowerShell 7 自身的端點,需要執行 Enable-PSRemoting 的說明。  2

  11. Microsoft Learn, Enter-PSSession。關於 Enter-PSSession 會開始與單一遠端電腦之間的互動工作階段、以 exit/Exit-PSSession 結束、必須是遠端那一端 Administrators 群組的成員,以及以 IP 位址指定時需要設定 HTTPS 或登錄 TrustedHosts 的說明。  2 3 4

  12. Microsoft Learn, How to configure WINRM for HTTPS (KB 2019527)。關於 HTTPS 接聽程式所需的憑證要求(本機電腦的伺服器驗證憑證、CN 與主機名稱一致、未過期・未撤銷・非自我簽署)、透過憑證嵌入式管理單元確認的步驟、以 winrm quickconfig -transport:https 進行設定、以 winrm enumerate winrm/config/listener 確認、Windows 7 以後 HTTP 5985/HTTPS 5986 的連接埠,以及沒有合適憑證時的錯誤 0x80338115 及應確認的憑證屬性的說明。  2 3

  13. Microsoft Learn, about_Remote_Variables。關於在遠端執行的命令中使用本機變數的 $using: 範圍修飾詞、在遠端工作階段中值是以獨立副本的形式傳遞,以及因序列化而失去方法的說明。  2

  14. Microsoft Learn, New-PSSession。關於 New-PSSession 會建立持續性的連線(PSSession)、用於執行需要共享資料的多個命令、以 -ComputerName 指定時會建立臨時連線並在每個命令後關閉,以及也支援 SSH 版連線的說明。  2 3

  15. Microsoft Learn, Running Remote Commands。關於以 Invoke-Command 執行指令碼檔案(-FilePath)、在以 New-PSSession 建立的持續性工作階段中,變數等狀態會在多個命令之間保留的說明。 

  16. Microsoft Learn, Overview of Just Enough Administration (JEA)。關於 JEA 是一種能對 PowerShell 管理對象實現委派管理的安全技術、可以限制可執行的 Cmdlet・函式・外部命令、透過虛擬帳戶或群組受管理服務帳戶可以減少管理員帳戶的數量,以及可透過逐字稿與記錄檔掌握執行內容的說明。 

共用相同標籤的最新文章。能以相近的主題延伸理解。

與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。

本文連結到以下服務頁面,歡迎從最接近的入口查看。

常見問題

整理諮詢這個主題時常見的問題。

執行 Enable-PSRemoting 會發生什麼事?
內部會執行 Set-WSManQuickConfig,完成以下動作:啟動 WinRM 服務並將其設為自動啟動、建立可在任意 IP 位址接收要求的接聽程式、啟用 WS-Management 通訊的防火牆例外,以及啟用工作階段組態(端點)並變更為允許遠端存取。Windows Server 預設已啟用,但用戶端版 Windows 需要自行執行。這只是接收連線那一端才需要的操作,發起連線的一端不需要執行。
在工作群組環境(沒有網域)中使用 PowerShell Remoting 需要什麼?
沒有網域就無法使用 Kerberos 驗證,因此會改用 NTLM 驗證。基本做法是在發起連線的一端,將連線目標登錄到 WSMan 的 TrustedHosts 清單中,並以 -Credential 明確傳遞認證資訊。不過,登錄在 TrustedHosts 中的對象並不會經過驗證(身分冒充檢查),因此有可能在未驗證對方身分的情況下就把認證資訊送出去,所以請不要使用萬用字元,只登錄必要最小限度的主機名稱,並考慮在可行時設定 HTTPS(5986)接聽程式。
為什麼在 Invoke-Command 的結果物件上無法呼叫方法?
因為遠端命令的輸出為了透過網路傳送,會被序列化為 XML(CLIXML),在本機端則被還原成反序列化後的物件。這是執行當下屬性值的快照,並不是活生生的物件,因此不具備方法。像停止服務這類操作,不應在本機端呼叫方法,而必須在 ScriptBlock 內(遠端那一側)執行。
什麼是 second hop(雙重躍點)問題?
這是指從 PC A 透過 Remoting 進入伺服器 B,再從 B 嘗試存取另一台伺服器 C(例如檔案伺服器)時會被拒絕的問題。預設的 Kerberos/NTLM 驗證不會把認證資訊本身傳送到 B,因此 B 無法以你的身分向 C 進行驗證。對策包括:在 ScriptBlock 內明確傳遞認證資訊、以資源為基礎的 Kerberos 約束委派,以及 CredSSP(因為認證資訊會傳到遠端,風險較高)等,可依需求選擇。
任何人都能連線到 PowerShell Remoting 嗎?
不會。預設情況下,只有遠端電腦 Administrators 群組的成員才能連線。而且連線後的工作階段是在連線使用者的內容(context)中執行,因此作業系統的存取控制會照常套用。話雖如此,對管理員而言這仍是一個威力強大的入口,建議搭配檢視防火牆規則、HTTPS 接聽程式、僅限必要管理員存取等多層防禦措施一併運用。

作者檔案

本文作者的個人檔案頁面。

Go Komura

小村軟體有限公司 代表

以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。

回到部落格一覽