「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、接聽程式),都需要以系統管理員身分啟動的 PowerShell。1
- 網路: 本文同時處理網域環境與工作群組環境,兩者的差異整理在第 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
- 準備一張伺服器驗證用的憑證。要求為「必須是本機電腦的伺服器驗證憑證」「CN(或主體別名)必須與主機名稱一致」「必須在有效期限內、未被撤銷,且不是自我簽署」。如果公司內部有 CA,可以透過
https://<憑證授權單位伺服器>/certsrv的網頁註冊功能提出申請。 - 把憑證放進本機電腦的個人存放區。可透過憑證嵌入式管理單元(在 MMC 中加入「憑證」,並在精靈中選擇「電腦帳戶」)的 憑證(本機電腦) > 個人 > 憑證 進行確認。
-
建立 HTTPS 接聽程式。最簡便的方式是下面這一行指令。
winrm quickconfig -transport:https若有多張憑證,想明確指定要使用哪一張,也可以從 PowerShell 指定憑證指紋來建立(可用
Get-ChildItem Cert:\LocalMachine\My確認指紋)。New-Item -Path WSMan:\localhost\Listener -Address * -Transport HTTPS -CertificateThumbPrint '憑證的指紋' -Force - 在防火牆上允許 TCP 5986 的傳入流量。因為
Enable-PSRemoting建立的規則是針對 HTTP(5985),HTTPS 需要另外處理。 -
確認接聽程式是否已建立。
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. 排查順序
- 確認連線是否可通。先在連線端執行
Test-WSMan -ComputerName sv-app01。如果這一步能通過,代表 WinRM 服務・接聽程式・防火牆都還活著(驗證或權限的問題仍可能存在)。若不通,請往下看。 - 確認遠端那一端的 WinRM 服務是否正在執行。伺服器版的啟動類型是自動,但用戶端版 Windows 的 WinRM 服務預設為停用。1 用
Get-Service WinRM確認,必要時執行Enable-PSRemoting(一次完成服務啟動・自動啟動化・接聽程式・防火牆例外・工作階段組態的設定)。4 -
確認接聽程式是否正在等待連線。在遠端那一端執行以下指令,查看
ListeningOn是否為空。若為空,常見的原因是透過群組原則配發接聽程式的環境中設定有誤。1Get-WSManInstance winrm/config/listener -Enumerate - 確認網路設定檔。用戶端版上,如果網路是公用,
Enable-PSRemoting本身就會因「Unable to check the status of the firewall」而失敗。請把設定檔改為私人,或加上-SkipNetworkProfileCheck。1 - 確認防火牆規則。即使是伺服器版,在公用設定檔下也會套用「僅允許來自同一子網路」的規則。若要從不同子網路連線,就需要調整規則(請先用
Get-NetFirewallRule確認規則名稱後再修改。規則名稱會因 Windows 版本而異)。1 - 是否滿足驗證方式的條件。若是工作群組、未加入網域,或以 IP 位址指定的情況,都無法使用 Kerberos 而會改用 NTLM,因此登錄 TrustedHosts(或使用 HTTPS)以及明確指定
-Credential是必要條件。連線目標的帳戶不能使用空白密碼。1 - 是否擁有可連線的權限。能連線到預設端點的,只有遠端那一端 Administrators 的成員。不同網域的使用者或本機帳戶,預設會拿到標準使用者的權杖,因此無法以管理員身分行動(如有需要可使用
LocalAccountTokenFilterPolicy,但這是對所有使用者停用 UAC 遠端限制的設定,請先理解其影響再使用)。1 - 確認端點的 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-Service、Set-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 指令基礎 ── 該先學會的操作與安全使用方式
- PowerShell 實用指令集錦 ── 累積日常工作常用的小工具
- 用 PowerShell 為檔案伺服器盤點 ── 容量調查與存取權限(ACL)稽核
- PowerShell 中安全處理認證資訊 ── 把明文密碼逐出腳本
- 如何理解 Windows 的工作階段隔離 ── Session 0・RDP・多使用者同時執行
- 正確處理 Windows 偽裝權杖 - 執行緒層級的權限借用與安全還原方式
相關諮詢領域
合同會社小村軟體承接以 PowerShell 建構伺服器・用戶端批次管理機制、設計與審查納入 Remoting 的維運腳本,以及「連不上」「只在特定環境下驗證失敗」這類 WinRM/驗證相關問題的調查。
參考連結
-
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
-
Microsoft Learn, PowerShell remoting over SSH。關於 PowerShell 6 以後可使用 SSH 版 Remoting、New-PSSession/Enter-PSSession/Invoke-Command 新增了 -HostName/-UserName/-KeyFilePath 參數組、可跨多個平台運作,以及端點組態與 JEA 目前尚不支援的說明。 ↩ ↩2 ↩3 ↩4
-
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
-
Microsoft Learn, Enable-PSRemoting。關於 Enable-PSRemoting 所執行操作的清單(啟動 WinRM 服務・設為自動啟動、建立接聽程式、防火牆例外、啟用工作階段組態並變更安全性描述元)、Windows Server 預設已啟用、用戶端版在公用網路下的限制與 SkipNetworkProfileCheck,以及會設定對應執行版本的端點的說明。 ↩ ↩2 ↩3 ↩4 ↩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
-
Microsoft Learn, Invoke-Command。關於 Invoke-Command 能以單一指令對多台電腦執行命令、-ComputerName 的臨時連線與 -Session 使用 PSSession 之間的區分,以及 -ArgumentList、-FilePath 等參數的說明。 ↩ ↩2 ↩3
-
Microsoft Learn, PowerShell Remoting FAQ。關於同時連線數的預設值為 32、可用 ThrottleLimit 參數變更、遠端命令的輸出會序列化為 CLIXML 並以反序列化物件(不具方法)的形式返回,以及 Invoke-Command 的結果會附加用於判別來源的屬性的說明。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, about_Remote_Output。關於遠端命令的輸出經過序列化/反序列化後,會變成只保留屬性值的快照,以及結果會依抵達順序返回,因此需要以 PSComputerName 重新排序的說明。 ↩ ↩2 ↩3
-
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
-
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
-
Microsoft Learn, Enter-PSSession。關於 Enter-PSSession 會開始與單一遠端電腦之間的互動工作階段、以 exit/Exit-PSSession 結束、必須是遠端那一端 Administrators 群組的成員,以及以 IP 位址指定時需要設定 HTTPS 或登錄 TrustedHosts 的說明。 ↩ ↩2 ↩3 ↩4
-
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 -
Microsoft Learn, about_Remote_Variables。關於在遠端執行的命令中使用本機變數的 $using: 範圍修飾詞、在遠端工作階段中值是以獨立副本的形式傳遞,以及因序列化而失去方法的說明。 ↩ ↩2
-
Microsoft Learn, New-PSSession。關於 New-PSSession 會建立持續性的連線(PSSession)、用於執行需要共享資料的多個命令、以 -ComputerName 指定時會建立臨時連線並在每個命令後關閉,以及也支援 SSH 版連線的說明。 ↩ ↩2 ↩3
-
Microsoft Learn, Running Remote Commands。關於以 Invoke-Command 執行指令碼檔案(-FilePath)、在以 New-PSSession 建立的持續性工作階段中,變數等狀態會在多個命令之間保留的說明。 ↩
-
Microsoft Learn, Overview of Just Enough Administration (JEA)。關於 JEA 是一種能對 PowerShell 管理對象實現委派管理的安全技術、可以限制可執行的 Cmdlet・函式・外部命令、透過虛擬帳戶或群組受管理服務帳戶可以減少管理員帳戶的數量,以及可透過逐字稿與記錄檔掌握執行內容的說明。 ↩
相關文章
共用相同標籤的最新文章。能以相近的主題延伸理解。
PowerShell 腳本太慢時該檢查的地方 ── 陣列・管線・比對的訣竅
整理 PowerShell 腳本變慢的常見原因。從實務角度解說陣列 += 造成 O(n^2) 的原因、管線與 foreach 的差異、比對的雜湊表化、檔案 I/O 的改善,以及正確的測量方式。
告別 Write-Host ── PowerShell 的輸出資料流與日誌設計
本文整理 PowerShell 六個輸出資料流的使用區分、Write-Host 所存在的問題與正確用途、函式傳回值被污染的原因、透過 -Verbose 與 -InformationVariable 由呼叫端進行控制的方法,以及結構化日誌的留存方式。
PowerShell 的並行處理 ── ForEach-Object -Parallel 與工作(Job)的選用之道
從實務角度整理 ForEach-Object -Parallel、Start-ThreadJob、Start-Job 的差異與選用方式,$using: 與執行緒安全性,ThrottleLimit 的決定方法,以及反而變慢的情況。
從 PowerShell 正確呼叫外部 exe ── 引數的引號、結束代碼、亂碼陷阱
從 PowerShell 呼叫 robocopy 或公司內部 EXE 時,引數會被破壞、拿不到結束代碼、輸出出現亂碼。本文從實務角度整理 PowerShell 7.3 的引數傳遞變更、停止剖析權杖 --%、以及 Start-Process 的使用時機。
PowerShell 中安全處理認證資訊 ── 把明文密碼逐出腳本
本文整理將 PowerShell 腳本中的明文密碼遷移至安全保存方式的做法,說明 SecureString 的實際樣貌與限制、Export-Clixml 透過 DPAPI 保存的機制,以及 SecretManagement/SecretStore 的適用場合。
相關主題
與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。
Windows 技術主題
彙整 KomuraSoft LLC 關於 Windows 開發、故障調查與既有資產活用文章的主題中心。
常見問題
整理諮詢這個主題時常見的問題。
- 執行 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 接聽程式、僅限必要管理員存取等多層防禦措施一併運用。