GUIで取得できる「サービス」の一覧をコマンドで取得する方法を考えてみます。
結論
先に結論から。実施するためのコードは下記のような感じになった。
#$ErrorActionPreference = "silentlycontinue"
$services = Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services\ | Where-Object { $_.GetValueNames().Contains("ObjectName")} | `
ForEach-Object {$_.Name.split("\")[-1]}
Out-File "out.csv"
foreach ($service in $services){
if (Test-Path "HKLM:\SYSTEM\CurrentControlSet\Services\$service\TriggerInfo"){
$Trig="トリガー開始"
} else {
$Trig=""
}
$Prop = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\$service)
$DName = (Get-Service $service).DisplayName
$Status = (Get-Service $service).Status
$OName = $Prop.ObjectName
Switch ($Prop.Start){
1 {$Start = "自動"}
2 {$Start = "自動(遅延開始)"}
3 {$Start = "手動"}
4 {$Start = "無効"}
default {$Start = $Prop.Start}
}
#$Desc = $Prop.Description
Write-Output ($DName + "`t" + $Status + "`t" + $Start + ":" + ${Trig} + "`t"+ $Oname) | Tee-Object -Append -FilePath "out.csv"
}
結果からすると思ったよりうまいこといったかなと。
詳細は「レジストリから探す」参照
今回の目的
システムの設計書なんかでOSの設定値として管理するパラメータシート的なものをコマンドで取得したい。
サービス一覧としてWindowsがGUIで表示するのは下記の内容。
つまりは「サービスの名前」、「説明」、「状態」、「スタートアップの種類」、「ログオン」の5項目を取得することが目的となる。
(「説明」は変更するようなものでもないので、パラメータシートに落とす必要もなく割愛してもよいものとする。)
“sc query”コマンド
コマンドプロンプトで「sc query」を実行する。
結果は下の通り。
対応した表示項目はGUIの「名前」と「状態」のみ。GUIに表示されていない出力はあるが、条件を満たすことはできない
”Get-Service”コマンド
PowerShell で「Get-Service」を実行する。
>get-service
Status Name DisplayName
—— —- ———–
Running AarSvc_1863cb Agent Activation Runtime_1863cb
Running AdobeARMservice Adobe Acrobat Update Service
Stopped AJRouter AllJoyn Router Service
・・・
デフォルトだと「状態」と「名前」しか表示されない。
PowerShellは他の項目の情報を持っていても表示しないという”クセ”がある。
下記のコマンドでほかの情報から探す。
>get-member | format-list
Name : XboxNetApiSvc
DisplayName : Xbox Live ネットワーキング サービス
Status : Stopped
DependentServices : {}
ServicesDependedOn : {KeyIso, IKEEXT, mpssvc, BFE}
CanPauseAndContinue : False
CanShutdown : False
CanStop : False
ServiceType : Win32ShareProcess
「DisplayName」、「Status」でそれぞれ「名前」、「状態」が確認可能。
全然GUIと一致しない。せめて「スタートアップの種類」ぐらいすんなり出力してくれないかな・・・
”Get-WmiObject win32_service”コマンド
Powershellで「Get-WmiObject win32_service」を実行
>Get-WmiObject win32_service
ExitCode : 0
Name : AdobeARMservice
ProcessId : 4476
StartMode : Auto
State : Running
Status : OK
お、やっと一歩進んだ。
「StartMode」という項目で「スタートアップの種類」が取得できました。
しかしこれだけ情報を取得する方法があるのになんでGUIと合わないのか。
GUIと同じ項目を表示してくれるだけでエンジニアの負担はかなり減って、Windowsの人気も上がる(かもしれない)のに。
レジストリから探す
結局、レジストリから探すしかないのか。めんどくさい・・・
レジストリを見て、いろいろ試行錯誤してできたPowershell はこちら
#$ErrorActionPreference = "silentlycontinue"
$services = Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services\ | Where-Object { $_.GetValueNames().Contains("ObjectName")} | `
ForEach-Object {$_.Name.split("\")[-1]}
Out-File "out.csv"
foreach ($service in $services){
if (Test-Path "HKLM:\SYSTEM\CurrentControlSet\Services\$service\TriggerInfo"){
$Trig="トリガー開始"
} else {
$Trig=""
}
$Prop = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\$service)
$DName = (Get-Service $service).DisplayName
$Status = (Get-Service $service).Status
$OName = $Prop.ObjectName
Switch ($Prop.Start){
1 {$Start = "自動"}
2 {$Start = "自動(遅延開始)"}
3 {$Start = "手動"}
4 {$Start = "無効"}
default {$Start = $Prop.Start}
}
#$Desc = $Prop.Description
Write-Output ($DName + "`t" + $Status + "`t" + $Start + ":" + ${Trig} + "`t"+ $Oname) | Tee-Object -Append -FilePath "out.csv"
}
出力結果はこんな感じ
Microsoft Edge の更新 サービス (edgeupdate) | Stopped | 自動(遅延開始): | LocalSystem |
Microsoft Edge の更新 サービス (edgeupdatem) | Stopped | 手動: | LocalSystem |
ActiveX Installer (AxInstSV) | Stopped | 手動: | LocalSystem |
タイトルも何もつけてないですが、「サービス名」、「状態」、「スタートアップの種類」、「ログオン」に相当する内容が出力できました。
下記が問題点。表記のブレなのでちゃんと整形する処理を追加すれば対応可能のはず。
- 「スタートアップの種類」のトリガー開始に相当する部分が別項目のため整形がいまいち
- 「ログオン」のところで「NT Authority\」などの表記がついたりする。
レジストリの「HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services」にいろいろ情報があるがいまいち or 情報がないものがあった。
「DisplayName」はものによってうまいこといかず、これは「Get-Service」側の情報を参照。
「Status」はレジストリにはなく、これも「Get-Service」から取得。
「Description」で一部は「説明」が表示できそうだったが、できないものが多くあきらめた。
ちなみに結果は「DisplayName」でソートすればGUIのものと一致しそう。
ということで思ったよりはなんとかなったかなと思う。
コメント