Dokumentacja

Wiersz poleceń

Każda komenda, każdy przełącznik i każdy kod wyjścia programu bws w wersji 0.5.0. Źródłem prawdy jest bws --help i jest dłuższy - ta strona to ta sama powierzchnia, rozłożona tak, żeby dało się ją czytać. Program mówi po angielsku, więc komendy, przełączniki i jego własne komunikaty są tu w oryginale.

Komendy

Jedenaście komend. snapshot jest rzeczownikiem i wymaga słowa po sobie. tool też jest rzeczownikiem, a sam wypisuje listę narzędzi.

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

Literówka w czasowniku dostaje podpowiedź, o który prawdopodobnie chodziło, a przebieg kończy się kodem 2, zamiast zrobić coś zbliżonego do tego, o co prosiłeś.

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

Co robi każdy czasownik

list i show

list to cała maszyna, zawężona przez --query. show to jeden wpis ze wszystkim, co o nim wiadomo - podpis, przywileje, deskryptor bezpieczeństwa i pamięć, wszystko czytane za każdym razem, bo na jednym wpisie kosztuje to około sześćdziesięciu milisekund, a na całej maszynie sekundę. Pola naprawdę puste są pomijane, chyba że podasz --full. Pole, którego nie dało się odczytać, drukuje się i tak, bo pominięcie go wyglądałoby jak odpowiedź.

stop, start i restart

Każdy buduje plan i go wykonuje. --dry-run drukuje plan i nie zmienia niczego, --dependents wstawia do niego usługi, które przestaną działać, jako osobne kroki, a --timeout mówi, jak długo jeden krok może trwać bez postępu. Sterowniki są odmawiane, a nie próbowane, bo zatrzymanie sterownika jądra często nie jest odwracalne bez restartu.

kill - dla usługi, która nie chce się zatrzymać

Prosi usługę o zatrzymanie i kończy stojący za nią proces tylko wtedy, gdy to nie zadziała, więc wpis, który zatrzymuje się sam, nigdy nie jest ubijany. Zakończenie procesu zabiera ze sobą każdą inną usługę żyjącą w tym procesie, niezależnie od tego, czy zatrzymała się wcześniej - a podgląd wymienia je po nazwie i podaje numer procesu. --force pomija uprzejmy krok, więc podgląd pokazuje jeden krok zamiast dwóch. --restart podnosi wszystko z powrotem.

Windows nazywa ten pomysł inaczej. --force w Stop-Service znaczy „nawet jeśli coś od tego zależy", czyli to, co tutaj robi --dependents. Dlatego jest to osobny czasownik, a nie przełącznik przy stop.

start-type - ustawienie, nie ruch

Mówi, co menedżer zrobi z wpisem przy następnym starcie systemu, i bez --stop nie przesuwa niczego: wpis działający dalej działa, zatrzymany dalej stoi, i plan to mówi. Nad disabled warto się zatrzymać, bo to znaczy, że menedżer nie uruchomi wpisu w ogóle - także na żądanie, dla czegoś innego, co go potrzebuje. delayed to automatyczny, uruchamiany chwilę po pozostałych automatycznych - to samo słowo, o które pyta start:delayed w zapytaniu - a Windows odmawia go wpisowi z grupy kolejności ładowania, co plan mówi, zanim cokolwiek się stanie. Każde z czterech zapisuje też, czy wpis startuje z opóźnieniem, tak jak sc.exe. --stop, wyłącznie obok disabled, zatrzymuje wpis w tym samym planie, po zapisaniu ustawienia.

snapshot create i snapshot diff

create zawsze czyta podpisy i skróty, bo snapshot jest trzymany i porównywany później, a taki bez nich porównywałby się z takim z nimi tak, jakby maszyna się zmieniła. diff mówi, co się zmieniło w drodze z pierwszego pliku do drugiego, albo z pliku do tej maszyny przy --live. Strona o snapshotach niesie format i uzasadnienie.

history - kto to zmienił, z dziennika System

Zmiany typu startu i instalacje usług z dziennika System, od najnowszej, z kontem, które zapisał Windows. Pierwsza linia mówi, jak daleko wstecz sięga dziennik i czy był czyszczony, bo historia jest tylko tak długa jak dziennik. Z nazwą to zmiany typu startu tej jednej usługi - instalacje są wymienione tylko bez nazwy, bo Windows zapisuje instalację pod nazwą wyświetlaną, nigdy pod nazwą usługi. Konto ma nazwę tam, gdzie ta maszyna nazwie je sama, a w przeciwnym razie stoi jego SID. Typy startu są w słowach, które zapisał Windows.

tool - gotowe odpowiedzi na częste problemy

Te same narzędzia, które okno pokazuje na zakładce Tools. bws tool wypisuje je, a bws tool fix wypisuje szybkie naprawy: printer, sound, indexing i search. Każda to restart jednej usługi Windows razem z tym, co od niej zależy, wybrany dlatego, że tak radzą strony pomocy Microsoftu. bws tool fix printer to dokładnie bws restart Spooler --dependents - ten sam plan, to samo wyjście i te same kody wyjścia - i jak każda komenda, która coś zmienia, nie pyta wcześniej, więc --dry-run pozwala obejrzeć plan przed wykonaniem.

license - co jest w środku pobranego pliku

Nie czyta niczego - ani menedżera usług, ani dysku, ani sieci - i odpowiada z rejestru wkompilowanego w plik wykonywalny. --components zamienia notę w pełną listę: każdy składnik z wersją, licencją i adresem źródeł. Ten sam zestaw, który niesie spis składników publikowany obok pobrania, bo oba powstają z jednego rejestru. I stąd jego wartość: program jest jednym plikiem samowystarczalnym, więc obok niego nie ma czego czytać.

Przykłady

Plany niżej sprawdzono z --dry-run na programie, który opisuje ta strona. Komenda, która coś zmienia, nie pyta wcześniej, więc --dry-run jest sposobem, żeby zajrzeć, zanim się wykona. Spooler stoi tu za dowolną usługę - wstaw w to miejsce nazwę swojej.

Szukanie i czytanie

bws list                                       każda usługa i sterownik na tej maszynie
bws list --query "start:auto !status:running"  co powinno chodzić i nie chodzi
bws list --query "status:running" --memory     ile używa proces każdego działającego wpisu
bws show Spooler                               wszystko, co wiadomo o jednym wpisie
bws show Spooler --full                        także pola, które są naprawdę puste

Najpierw podgląd, potem zmiana

bws restart Spooler --dry-run                sam plan i nic więcej
bws restart Spooler --dependents             restart razem z tym, co od niej zależy
bws stop Spooler --dependents --timeout 120  dwie minuty na krok bez postępu
bws start-type WSearch delayed --dry-run     start chwilę po innych wpisach automatycznych
bws start-type Spooler disabled --stop       wyłączenie i zatrzymanie w jednym planie

Usługa, która nie chce się zatrzymać

bws kill Spooler --dry-run          proces i każda usługa, która w nim mieszka
bws kill Spooler --restart          proces kończony tylko wtedy, gdy zatrzymanie zawiedzie, potem powrót wszystkiego
bws kill Spooler --force --dry-run  jeden krok zamiast dwóch: proces kończony od razu

Snapshoty i dryf

bws snapshot create before.json --note "before the patch"  zamrożenie maszyny, z notatką zapisaną w środku
bws snapshot diff before.json after.json                   dwa pliki - dwa dni albo dwie maszyny
bws snapshot diff before.json --live                       plik wobec tej maszyny w tej chwili
bws snapshot diff before.json --live --exit-code           to samo, z kodem 5, gdy konfiguracja się rozjechała

Kto to zmienił

bws history          każda zmiana typu uruchomienia i instalacja z dziennika System
bws history Spooler  zmiany typu uruchomienia jednej usługi
bws history --json   to samo jako dokument, z log i changes

Szybkie naprawy

bws tool                      jakie są narzędzia
bws tool fix                  szybkie naprawy i usługa stojąca za każdą
bws tool fix sound --dry-run  plan restartu dwóch usług dźwięku
bws tool fix printer          restart bufora wydruku razem z tym, co od niego zależy

Co jest w pliku

bws license --components  każdy składnik z wersją, licencją i źródłem
bws --version             wersja tego pliku wykonywalnego

W skrypcie PowerShella

# wpisy, które powinny chodzić i nie chodzą, jako obiekty
bws list --query "start:auto !status:running" --json | ConvertFrom-Json | Select-Object serviceName, displayName, status

# niepodpisane pliki do arkusza
bws list --query "signed:no" --json | ConvertFrom-Json | Select-Object serviceName, binaryPath | Export-Csv unsigned.csv -NoTypeInformation

# czego potrzebuje jedna usługa
(bws show Spooler --json | ConvertFrom-Json).dependsOn

# nocne sprawdzenie, które rozgałęzia się po kodzie wyjścia
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" }
}

W cmd i pliku wsadowym

rem druga komenda tylko wtedy, gdy pierwsza nie skończyła się czysto
bws restart Spooler || echo the restart did not end cleanly

rem w pliku wsadowym z włączonym opóźnionym rozwijaniem ! potrzebuje daszka
bws list --query "start:auto ^!status:running"

Przełączniki

Jest ich 18. Trzecia kolumna to czasowniki, do których każdy należy - przełącznik podany czasownikowi, który nie ma z niego pożytku, jest błędem z tą listą w treści, a nie flagą po cichu zignorowaną.

PrzełącznikCo robiGdzie działa
--queryZawęża listę językiem zapytań.list
--signaturesCzyta, kto podpisał każdy plik i czy Windows temu podpisowi ufa. Kilka sekund na całej maszynie, więc jest wyłączone, dopóki nie poprosisz - a zapytanie o podpisy włącza to samo.list
--memoryCzyta, ile pamięci zajmuje proces każdego działającego wpisu. Domyślnie wyłączone, bo to pomiar, a nie ustawienie: sekundę później jest inny.list
--required-byCzyta, które wpisy przestaną działać po zatrzymaniu tego - pytając Windows wprost, zamiast wyliczać to z deklaracji. Jedno wywołanie na wpis, więc wyłączone, dopóki nie poprosisz. show i snapshot create czytają to zawsze.list
--follow-networkPozwala programowi sięgnąć poza tę maszynę - pod ścieżkę uruchomienia leżącą na udziale innego komputera oraz po certyfikat, którego ta maszyna jeszcze nie ma. Domyślnie wyłączone dla bezpieczeństwa: jeden nieosiągalny udział kosztuje dwadzieścia jeden sekund i uwierzytelnia się jako ten, kto uruchomił program, a pobranie certyfikatu to połączenie do obcego serwera w trakcie zwykłego listowania. Bez tego podpis jest sprawdzany wobec tego, co jest na miejscu, a wynik, który mógł wziąć się z niezajrzenia, jest zgłaszany jako nieodczytany, a nie jako werdykt.list, show, snapshot create
--forcePrzy kill kończy proces od razu, bez uprzejmego pytania - podgląd pokazuje wtedy jeden krok zamiast dwóch. Przy snapshot create zastępuje istniejący snapshot - pliku, który snapshotem nie jest, nie zastępuje nigdy.snapshot create, kill
--restartPrzy kill podnosi wpis z powrotem, gdy proces zniknie, razem ze wszystkim, co ten proces dzieliło.kill
--stopPrzy start-type, i tylko obok disabled, zatrzymuje wpis w tym samym planie, po zapisaniu ustawienia. Typ startu zmienia następny rozruch, a nie to, co dzieje się teraz, więc bez tego działający wpis ustawiony jako wyłączony dalej działa.start-type
--fullPrzy show drukuje także pola, które są naprawdę puste. Pole, którego nie dało się odczytać, drukuje się i tak.show
--jsonTen sam dokument, czytelny dla maszyny, na wyjściu standardowym.list, show, stop, start, restart, start-type, snapshot create, snapshot diff, kill, history, tool fix NAME
--notePo co snapshot został zrobiony - zapisane w środku pliku.snapshot create
--exit-codeKończy kodem 5, gdy różni się konfiguracja - wpis doszedł albo zniknął, albo jest ustawiony inaczej. Sam stan pracy się nie liczy. Domyślnie wyłączone, żeby skrypt, który chce tylko zobaczyć różnice, nie wywracał się na tym, że je znalazł.snapshot diff
--livePorównuje plik z tą maszyną w jej obecnym stanie, zamiast z drugim plikiem.snapshot diff
--timingIle trwała każda część odczytu, na wyjściu błędów.list, show, stop, start, restart, start-type, snapshot create, snapshot diff, kill, history, tool fix NAME
--dry-runDrukuje plan i nie zmienia niczego. To ten sam plan, który wykonuje się przy wykonaniu - nie ma drugiej ścieżki kodu dla wersji prawdziwej.stop, start, restart, start-type, kill, tool fix NAME
--dependentsWstawia do planu, jako osobne kroki, usługi, które przestaną działać.stop, restart, kill
--timeoutJak długo jeden krok może trwać bez postępu, zanim narzędzie przestanie czekać - liczone od nowa za każdym razem, gdy usługa zamelduje postęp. Sześćdziesiąt sekund, o ile nie powiesz inaczej. Usługa, która melduje postęp, jest obserwowana tak długo, jak trzeba. Wyczerpanie tego czasu jest końcem patrzenia, a nie porażką - raport mówi, w jakim stanie wpis został zostawiony.stop, start, restart, kill, tool fix NAME
--componentsPrzy license zamienia notę w pełną listę: każdy składnik wewnątrz tego pliku wykonywalnego, z wersją, licencją i adresem źródeł. Ten sam zestaw, który niesie spis składników publikowany obok pobrania, bo oba powstają z jednego rejestru.license

Kody wyjścia

6 zakończeń, a każde z nich jest dla skryptu czymś innym. Dane idą na wyjście standardowe, a cała reszta na wyjście błędów, więc bws list --json | jq działa, a ostrzeżenie nigdy nie ląduje w JSON-ie.

Każdy dokument JSON jest czystym ASCII: litera spoza niego idzie jako sześcioznakowa ucieczka, którą każdy czytnik JSON zamienia z powrotem na literę, więc bws list --json > file.json jest poprawnym UTF-8, a | ConvertFrom-Json czyta go dobrze przy każdej stronie kodowej konsoli. W tekście dla człowieka znak, który zamiast się wydrukować przestawiłby terminal - tabulator, koniec linii, sekwencja ucieczki, zmiana kierunku tekstu - jest pokazany jako swój numer, <U+001B>.

-- kończy przełączniki, więc usługę o nazwie zaczynającej się od łącznika da się nazwać: bws show -- -odd. Polecenia, które narzędzie podaje do skopiowania, są pisane dla PowerShella: nazwa ze spacją idzie w cudzysłowie, który cmd czyta tak samo, a nazwa, którą PowerShell rozwinąłby w cudzysłowie, na przykład MSSQL$SQLEXPRESS, w apostrofach.

KodZnaczenie
0Zrobione, i wszystko dotarło tam, gdzie miało dotrzeć.
1Narzędzie zawiodło - nie zrobiło tego, o co poproszono, z powodu dotyczącego samego narzędzia, a nie planu.
2Wiersz poleceń był zły. Przy literówce w komendzie program podpowiada tę, o którą prawdopodobnie chodziło.
3Plan był dobry, wykonał się, a coś w nim nie dotarło tam, gdzie miało - menedżer odmówił albo sesja nie miała do tego praw.
4Ktoś zatrzymał przebieg ręcznie. Niezerowy nawet wtedy, gdy każdy krok i tak dotarł, żeby skrypt nadrzędny nie potraktował przerwanego przebiegu jako czystego.
5Porównanie wykonało się i znalazło dryf konfiguracji - wpis doszedł albo zniknął, albo jest ustawiony inaczej. Sam stan pracy nie jest dryfem. Tylko z --exit-code, bo dryf jest tym, czego to narzędzie szuka, a znalezienie go nie jest porażką.

Ctrl+C ma trzy poziomy, a każdy mówi, ile kosztuje następny. Pierwszy przestaje iść naprzód i nadal oddaje to, co zabrał, drugi zostawia rzeczy jak są i nadal drukuje raport, trzeci kończy proces. Przebieg zatrzymany ręcznie kończy się kodem 4 nawet wtedy, gdy każdy krok i tak dotarł.

Zamknięcie okna konsoli liczy się jak pierwsze Ctrl+C. Windows daje programowi po nim pięć sekund, a ten w tym czasie przestaje iść naprzód i oddaje to, co zabrał. Wylogowanie i zamknięcie systemu kończą go bez ostrzeżenia, na które mógłby zareagować, a zerwana sesja zdalna może tak samo.

W zadaniu harmonogramu

Kształt, pod który ten program powstał: zamroź maszynę, gdy wiadomo, że jest dobra, a potem co noc pytaj, czy nadal jest.

# w dniu, w którym maszyna wchodzi do pracy
bws snapshot create C:\baselines\web01.json --note "after the build"

# co noc, z zadania harmonogramu
bws snapshot diff C:\baselines\web01.json --live --exit-code --json > C:\logs\drift.json
#   0 - konfiguracja się nie rozjechała
#   5 - konfiguracja się rozjechała, a drift.json mówi co
#   3 - wykonało się i nie wszystko dało się odczytać, więc odpowiedź jest częściowa

Okno jest drugą połową tego samego silnika: niesie je BetterWindowsServices-win-x64.zip, a strona pobierania mówi, co jest w którym archiwum.

Argument okna

BetterWindowsServices.exe przyjmuje jeden argument przeznaczony dla człowieka: --catalogue otwiera arkusz dla programisty, pokazujący każdy komponent okna w każdym stanie, i nie czyta niczego z Twojej maszyny. Drugi, --carry, służy oknu do przekazania tego, co pokazywało, swojej kopii uruchamianej ponownie jako administrator. Nikt go nie wpisuje, a wszystko, czego tamto okno nie mogło samo zapisać, jest odrzucane.