參考

命令列參考

bws 版本 0.5.0 的每個命令、每個選項和每個結束代碼。bws --help 才是權威的,而且更長:這個頁面是同一套內容,排版成便於閱讀的樣子。

命令

共十一個命令。snapshot 是名詞,後面要跟一個詞。tool 也是名詞,單獨使用時會列出各個工具。

bws list [--query TEXT] [--signatures] [--memory] [--required-by] [--follow-network] [--json] [--timing]
bws show NAME [--full] [--follow-network] [--json] [--timing]
bws stop|start|restart NAME [--dry-run] [--dependents] [--timeout SECONDS] [--json] [--timing]
bws kill NAME [--force] [--restart] [--dry-run] [--dependents] [--timeout SECONDS] [--json] [--timing]
bws start-type NAME automatic|delayed|manual|disabled [--stop] [--dry-run] [--json] [--timing]
bws snapshot create [FILE] [--note TEXT] [--follow-network] [--force] [--json] [--timing]
bws snapshot diff EARLIER LATER [--exit-code] [--json] [--timing]
bws snapshot diff EARLIER --live [--exit-code] [--json] [--timing]
bws history [NAME] [--json] [--timing]
bws tool
bws tool fix
bws tool fix NAME [--dry-run] [--timeout SECONDS] [--json] [--timing]
bws license [--components]
bws --help
bws --version

拼錯的命令會得到一個你可能想用的命令的提示,並以代碼 2 結束,而不是去做某件與你的要求相近的事。

$ bws lst
There is no command lst. Did you mean list?

每個命令做什麼

list 和 show

list 是整台電腦,由 --query 縮小範圍。show 是單一項目及其所有已知資訊:簽章、特殊權限、安全性描述元和記憶體,每次都會全部讀取,因為針對一個項目只需約六十毫秒,而針對整台電腦則需要一秒。真正為空的欄位會被省略,除非你傳入 --full。無人能讀取的欄位無論如何都會被列印,因為省略它會看起來像一個答案。

stop、start 和 restart

每個都會產生計畫並執行。--dry-run 列印計畫而不做任何變更,--dependents 把會受影響的服務作為獨立的步驟放進計畫,--timeout 指定一個步驟可以在沒有進展的情況下持續多久。驅動程式會被拒絕而不是嘗試,因為停止核心驅動程式往往不重新啟動就無法復原。

kill:用於停不下來的服務

它會要求服務停止,只有在無效時才結束它背後的處理程序,所以自己能停止的項目絕不會被強行結束。結束一個處理程序會帶走該處理程序中的所有其他服務,不論它們是否事先已經停止,預覽會點出它們的名稱,並依編號指出該處理程序。--force 跳過禮貌的那一步,預覽於是顯示一個步驟而不是兩個。--restart 隨後把一切帶回來。

Windows 對這個想法的表述不同。Stop-Service 上的 --force 的意思是「即使有東西依賴它」,這在這裡是 --dependents 的作用。這就是它是一個獨立命令、而不是 stop 上的一個選項的原因。

start-type:是一項設定,而不是一次動作

它指明服務管理員在下次啟動時如何處理某個項目,沒有 --stop 時它不會移動任何東西:正在執行的項目繼續執行,已停止的保持停止,計畫會這樣說明。disabled 值得停下來想一想,因為它會讓服務管理員根本不再啟動該項目,包括依需求為其他需要它的東西啟動。delayed 是自動,比其他自動項目稍晚啟動:在查詢中 start:delayed 詢問的就是這個詞。Windows 會拒絕把它用於屬於載入順序群組的項目,計畫會在任何動作發生之前說明這一點。四種類型都會像 sc.exe 那樣記錄該項目是否延遲啟動。--stop 只能與 disabled 搭配,在寫入設定之後,在同一份計畫中停止該項目。

snapshot create 和 snapshot diff

create 始終會讀取簽章和雜湊,因為快照是要儲存下來、之後再比較的,沒有它們的快照與有它們的快照比較時,會讓人覺得電腦發生了變化。diff 說明從第一個檔案到第二個檔案,或用 --live 從一個檔案到這台電腦,發生了哪些變化。快照頁面介紹了格式和理由。

history:誰改的,來自 System 記錄檔

從 System 記錄檔中讀取啟動類型變更和安裝記錄,最新的在前,帶有 Windows 記錄的帳戶。第一行說明記錄檔能追溯多遠、是否被清除過,因為歷程記錄的長度只取決於記錄檔。帶上名稱時,顯示的是該服務的啟動類型變更:安裝記錄只在不帶名稱時列出,因為 Windows 記錄安裝時用的是顯示名稱,而從不是服務名稱。帳戶在這台電腦能自行解析其名稱時顯示名稱,否則顯示其 SID,啟動類型則使用 Windows 所寫的詞。

tool:針對常見問題的現成答案

與視窗在 Tools 索引標籤上顯示的工具相同。bws tool 列出它們,bws tool fix 列出快速修復:printer、sound、indexing 和 search,每一項都是重新啟動一個 Windows 服務連同依賴它的內容,之所以選它們,是因為 Microsoft 自己的疑難排解頁面就是這樣建議的。bws tool fix printer 就是 bws restart Spooler --dependents:相同的計畫、相同的輸出和相同的結束代碼,而且和這裡每個會變更內容的命令一樣,它不會先詢問,所以想在執行前檢視,請使用 --dry-run。

license:你下載的檔案裡有什麼

它什麼也不讀取,既不讀服務管理員,也不讀磁碟和網路,而是從編譯進可執行檔的登記表中回答。--components 會把通知變成每個元件及其版本、授權和來源。這與隨下載一同發行的物料清單所含的集合相同,因為兩者都由同一份登記表產生,這也是值得擁有它的原因:程式是一個獨立式的單一檔案,所以它旁邊沒有任何東西可供掃描程式讀取。

範例

下面的計畫已針對本頁所描述的程式用 --dry-run 檢查過。會變更內容的命令不會先詢問,所以想在執行前檢視,請使用 --dry-run。Spooler 代表任何服務,請換成你自己的服務名稱。

尋找與讀取

bws list                                       這台電腦上的每個服務和驅動程式
bws list --query "start:auto !status:running"  應該執行卻沒有執行的內容
bws list --query "status:running" --memory     每個執行中項目的處理程序正在使用什麼
bws show Spooler                               關於一個項目的所有已知資訊
bws show Spooler --full                        也包括真正為空的欄位

先看,再變更

bws restart Spooler --dry-run                只顯示計畫,不做別的
bws restart Spooler --dependents             連同依賴它的內容一起重新啟動
bws stop Spooler --dependents --timeout 120  允許每個步驟在沒有進展的情況下持續兩分鐘
bws start-type WSearch delayed --dry-run     比其他自動項目稍晚啟動
bws start-type Spooler disabled --stop       在一份計畫中停用並停止它

停不下來的服務

bws kill Spooler --dry-run          處理程序,以及同在其中的每個服務
bws kill Spooler --restart          只有停止失敗時才結束處理程序,然後把一切帶回來
bws kill Spooler --force --dry-run  一步而不是兩步:立即結束處理程序

快照與漂移

bws snapshot create before.json --note "before the patch"  凍結電腦,並在其中保留一則備註
bws snapshot diff before.json after.json                   兩個檔案:相隔兩天,或兩台電腦
bws snapshot diff before.json --live                       把檔案與這台電腦的目前狀態比較
bws snapshot diff before.json --live --exit-code           同上,若組態發生漂移則以 5 結束

誰改的

bws history          System 記錄檔中保存的每一次啟動類型變更和安裝
bws history Spooler  某一個服務的啟動類型變更
bws history --json   同樣的內容,作為文件,含記錄檔和變更

快速修復

bws tool                      現有的工具
bws tool fix                  快速修復,以及每一項背後的服務
bws tool fix sound --dry-run  重新啟動兩個音訊服務的計畫
bws tool fix printer          連同依賴它的內容一起重新啟動 Print Spooler

檔案裡有什麼

bws license --components  每個元件、版本、授權和來源
bws --version             此可執行檔的版本

在 PowerShell 指令碼中

# 應該執行卻沒有執行的項目,作為物件
bws list --query "start:auto !status:running" --json | ConvertFrom-Json | Select-Object serviceName, displayName, status

# 未簽章的檔案,寫入試算表
bws list --query "signed:no" --json | ConvertFrom-Json | Select-Object serviceName, binaryPath | Export-Csv unsigned.csv -NoTypeInformation

# 一個服務需要什麼
(bws show Spooler --json | ConvertFrom-Json).dependsOn

# 依結束代碼分支的夜間檢查
bws snapshot diff C:\baselines\web01.json --live --exit-code > $null
switch ($LASTEXITCODE) {
  0 { 'no configuration drift' }
  5 { 'the configuration drifted' }
  default { "no clean answer, exit code $LASTEXITCODE" }
}

在 cmd 和批次檔中

rem 僅當第一個命令沒有正常結束時才執行第二個命令
bws restart Spooler || echo the restart did not end cleanly

rem 在啟用了延遲擴充的批次檔中,! 前面需要插入符號 ^
bws list --query "start:auto ^!status:running"

選項

共 18 個。第三欄是每個選項所屬的命令:把選項傳給用不上它的命令是一個錯誤,錯誤中會帶有這份清單,而不是一個被悄悄忽略的旗標。

選項作用適用範圍
--query用查詢語言縮小清單範圍。list
--signatures讀取誰替每個可執行檔簽章,以及 Windows 是否信任它。在整台電腦上需要幾秒鐘,所以除非被要求,否則是關閉的,而關於簽章的查詢會自動把它開啟。list
--memory讀取每個執行中項目的處理程序正在使用什麼。預設關閉,因為它是一次測量而不是一項設定:一秒鐘之後它就不同了。list
--required-by讀取停止某一個項目後哪些項目會出問題,直接向 Windows 詢問,而不是根據各方的宣告推算。每個項目需要一次呼叫,所以除非被要求,否則是關閉的。show 和 snapshot create 每次都會讀取它。list
--follow-network讓工具完全可以存取這台電腦之外的內容:位於別人共用資料夾上的啟動路徑,以及這台電腦尚未持有的憑證。出於安全考量預設關閉:一個無法存取的共用資料夾會耗費二十一秒,並以執行者的身分進行驗證,而取得憑證則是在一次普通清單的過程中連線第三方。沒有它時,簽章會根據這裡已有的內容進行檢查,而可能是由於沒有去查看而導致的結果,會被回報為未讀取,而不是給出判定。list, show, snapshot create
--force對 kill 而言,是不再禮貌地詢問而直接結束處理程序:這樣預覽顯示的是一個步驟,而不是兩個。對 snapshot create 而言,是取代已經存在的快照:不是快照的檔案絕不會被取代。snapshot create, kill
--restart對 kill 而言,是在處理程序消失後,把該項目連同與它共用處理程序的所有內容一起帶回來。kill
--stop對 start-type 而言,並且只能與 disabled 搭配,在寫入設定之後,在同一份計畫中停止該項目。啟動類型改變的是下一次啟動,而不是現在,所以沒有它時,設為 disabled 的執行中項目會繼續執行。start-type
--full對 show 而言,是同時列印真正為空的欄位。無人能讀取的欄位無論如何都會被列印。show
--json同一份文件,以機器可讀的形式輸出到標準輸出。list, show, stop, start, restart, start-type, snapshot create, snapshot diff, kill, history, tool fix NAME
--note這份快照是為什麼而產生的,儲存在檔案內部。snapshot create
--exit-code當組態不同時以代碼 5 結束:項目被新增或刪除,或者某個項目的設定不同。僅有執行狀態的變化不計入。預設關閉,這樣只想列印差異的指令碼,就不會因為發現了差異而被絆住。snapshot diff
--live把檔案與這台電腦的目前狀態比較,而不是與第二個檔案比較。snapshot diff
--timing讀取的每個部分花了多長時間,輸出到標準錯誤。list, show, stop, start, restart, start-type, snapshot create, snapshot diff, kill, history, tool fix NAME
--dry-run列印計畫,不做任何變更。它與實際執行所執行的是同一份計畫:真正執行時沒有第二條程式碼路徑。stop, start, restart, start-type, kill, tool fix NAME
--dependents把會出問題的服務作為獨立的步驟放進計畫。stop, restart, kill
--timeout一個步驟在沒有進展的情況下最多可以持續多久,超過後就會被放棄,服務每次回報進展時都會重新計時。如果你不另行指定,則為六十秒。一直在回報進展的服務會被一直觀察下去,直到完成為止。逾時只是觀察結束,而不是失敗,報告會說明該項目被留在了什麼狀態。stop, start, restart, kill, tool fix NAME
--components對 license 而言,是把通知變成這個可執行檔內部的每個元件及其版本、授權和來源。這與隨下載一同發行的物料清單所含的集合相同,因為兩者都由同一份登記表產生。license

結束代碼

共 6 種結束方式,每一種對指令碼來說都是不同的處理。資料輸出到標準輸出,其餘所有內容輸出到標準錯誤,因此 bws list --json | jq 可以正常運作,警告也絕不會混進你的 JSON。

每個 JSON 文件都是純 ASCII:ASCII 之外的字元會被寫成六個字元的逸出序列,所有 JSON 讀取器都會把它還原成那個字元,所以 bws list --json > file.json 是有效的 UTF-8,而 | ConvertFrom-Json 無論主控台設定為什麼字碼頁都能正確讀取。在供人閱讀的文字中,會移動終端機而不是被列印出來的字元,例如定位字元、換行、逸出序列和方向覆寫字元,會顯示為它的碼位 <U+001B>。

-- 表示選項到此結束,所以名稱以連字號開頭的服務仍然可以指定:bws show -- -odd。工具交給你的命令列是為 PowerShell 撰寫的:帶空格的名稱放在雙引號中,cmd 對其讀取方式相同,而 PowerShell 會在雙引號內展開的名稱,例如 MSSQL$SQLEXPRESS,則放在單引號中。

代碼意義
0完成,一切都到了它該去的地方。
1工具失敗了:由於與工具本身而不是與計畫有關的原因,它無法完成被要求做的事。
2命令列有誤。拼錯的命令會得到一個你可能想用的命令的提示。
3計畫是好的,也執行了,但其中有些內容沒有到達它該去的地方:服務管理員拒絕了,或者工作階段沒有相應的權限。
4有人手動停止了執行。即使每個步驟都已到達,結果也不是零,這樣包裝指令碼就不會把被中斷的執行當作正常結束。
5比較已執行,並發現組態發生了漂移:項目被新增或刪除,或者某個項目的設定不同。僅有執行狀態的變化不算漂移。僅在使用 --exit-code 時才會這樣,因為漂移正是這個工具要找的東西,找到它並不是失敗。

Ctrl+C 有三個層級,每一級都說明下一級的代價。第一級停止繼續前進,並仍會把已取走的東西放回去,第二級讓現狀保持原樣,並仍會列印報告,第三級結束處理程序。手動停止的執行即使每個步驟都已完成,也會以 4 結束。

關閉主控台視窗算作第一次 Ctrl+C。此後 Windows 會給程式五秒鐘,在這段時間內它會停止前進,並把它關掉的東西放回去。登出和關機會在沒有任何它能作出反應的警告的情況下結束它,中斷連線的遠端工作階段也可能如此。

在排程工作中

這個工具為之而生的形態:在電腦已知良好時把它凍結,然後每晚詢問它是否仍然如此。

# 電腦投入使用的那一天
bws snapshot create C:\baselines\web01.json --note "after the build"

# 每晚,透過排程工作
bws snapshot diff C:\baselines\web01.json --live --exit-code --json > C:\logs\drift.json
#   0 - 沒有組態漂移
#   5 - 組態發生了漂移,drift.json 會說明具體內容
#   3 - 已執行但無法讀取全部內容,因此答案是部分的

視窗是同一引擎的另一半:BetterWindowsServices-win-x64.zip 中包含它,而下載頁面說明了每個壓縮檔是什麼。

視窗的參數

BetterWindowsServices.exe 接受一個供人使用的參數:--catalogue 會開啟一張開發者用的表,顯示視窗的每個元件在每種狀態下的樣子,並且不會從你的電腦讀取任何內容。第二個參數 --carry 是視窗把它正在顯示的內容交給它以系統管理員身分重新啟動的自己的副本的方式。沒有人會手動輸入它,其中任何該視窗不可能寫出的內容都會被拒絕。