PowerShellで起動中のサービスを一覧表示する方法

PowerShellで起動中のWindowsサービスを一覧表示する基本は、Get-Service | Where-Object Status -eq Runningです。ただし、サービス名と表示名、現在の状態とスタートアップ種類、サービスとプロセス、取得時点の一時的な状態を区別しないと、誤った停止判断につながります。本記事では、Get-Serviceで素早く一覧を作り、必要に応じてWin32_Serviceの構成やプロセスID、依存関係、イベントログを読み取り専用で照合する方法を解説します。サービスを止めたり設定を変えたりせず、現在の観測結果を再現可能に残すことを目的にします。

目次

Get-Serviceで現在Runningのサービスを抽出する

Get-Serviceはローカルコンピューター上のサービスをServiceControllerオブジェクトとして返します。StatusがRunningのものだけを選び、NameとDisplayNameを表示します。Nameはコマンドや構成で使うサービス名、DisplayNameは管理画面向けの表示名です。問い合わせでは両方を残すと、言語や製品資料との照合が容易になります。

Get-Service |
    Where-Object Status -eq Running |
    Sort-Object DisplayName |
    Select-Object Status, Name, DisplayName

一覧は実行した瞬間の状態です。トリガー開始のサービスや短時間の保守サービスは、数秒後に停止することがあります。反対にStoppedでも、必要なときだけ起動する設計なら異常ではありません。「Runningが正常、Stoppedが故障」という一律の判定は避け、対象製品の設計、スタートアップ種類、トリガー、依存関係、障害時刻を確認します。サービス状態を更新するために再起動する必要はありません。

名前や表示名で安全に絞り込む

特定サービスを確認するならGet-Service -Name Spoolerのようにサービス名を指定します。表示名から探す場合は-DisplayNameが使え、ワイルドカードも利用できます。広い語で検索すると無関係なサービスまで一致するため、まず候補を表示して正式なNameを確認します。存在しない名前ではエラーになることがあるので、自動化では未検出とコマンド失敗を分けます。

Get-Service -DisplayName "*Update*" |
    Select-Object Status, Name, DisplayName

表示名はWindowsの表示言語や製品バージョンで変わる可能性があり、スクリプトの識別子にはNameの方が安定しています。それでも製品更新でサービス構成やNameが変わる場合があるため、固定リストだけで準拠判定をしません。利用中製品の公式資料と端末上のインストール情報を照合します。検索結果が空でも、アプリがサービスを使わない構成、ユーザー単位サービス、別名、権限不足の可能性があります。

Win32_Serviceで起動種類と実行情報を照合する

Get-CimInstance -ClassName Win32_Serviceでは、State、StartMode、ProcessId、StartName、PathNameなどの構成を確認できます。現在Runningのものに絞る場合はCIM側のFilterを使うと、取得後に全件を絞るより効率的です。StartModeはAutomatic、Manual、Disabledなどの構成であり、現在のStateとは別です。

Get-CimInstance -ClassName Win32_Service -Filter "State = 'Running'" |
    Select-Object Name, DisplayName, State, StartMode, ProcessId, StartName

Automaticでも遅延開始やトリガー、依存関係によりログオン直後は状態が変化します。ManualでRunningなら、アプリやイベントを契機に開始した可能性があります。PathNameには実行ファイルと引数が含まれる場合があり、内部パスや製品構成を外部へ出さないようにします。StartNameはサービスアカウント情報なので、共有範囲を限定します。認証情報そのものは表示されませんが、アカウント名も管理情報です。

サービスとプロセスをProcessIdで関連付ける

Win32_ServiceのProcessIdをGet-Process -Idへ渡すと、実行中プロセスの名前、開始時刻、CPU時間、メモリなどを確認できます。ただし、複数サービスが同じsvchost.exeプロセスを共有する場合があり、プロセス名だけではサービスを一意に特定できません。まずサービス側のNameとProcessIdを基準にして、同じIDを共有するサービスがないか確認します。

$service = Get-CimInstance Win32_Service -Filter "Name = 'Spooler'"
$process = Get-Process -Id $service.ProcessId -ErrorAction SilentlyContinue
[pscustomobject]@{
    ServiceName = $service.Name
    State       = $service.State
    ProcessId   = $service.ProcessId
    ProcessName = $process.ProcessName
    StartedAt   = $process.StartTime
}

状態取得とプロセス取得の間にサービスが停止すると、ProcessIdが変わる、またはGet-Processが見つからないことがあります。これは必ずしも障害ではなく、観測の競合です。実行時刻を記録して再取得します。期待しないプロセス名や高いCPU使用率を見つけても、その場でStop-Processを実行しません。共有プロセスや依存サービスを巻き込み、データ損失や認証・ネットワーク停止を招く可能性があります。

依存サービスを確認して単独で判断しない

Get-Service -Name 対象名 -RequiredServicesは対象サービスが必要とするサービス、-DependentServicesは対象へ依存するサービスを表示します。通常のServiceControllerオブジェクトでもServicesDependedOnとDependentServicesを参照できます。Runningの一覧に目的のサービスがない場合、依存先の停止や起動順序が関係していないかを確認します。

$service = Get-Service -Name Spooler
$service | Select-Object Name, Status, ServicesDependedOn, DependentServices

依存関係が表示されないから他機能へ影響しないとは限りません。アプリケーション独自の依存、ネットワーク、データベース、証明書、ファイル共有、負荷分散などはService Control Managerの依存関係へ登録されていない場合があります。サービスの停止や再起動を検討するときは、製品手順、利用者、冗長化、処理中ジョブ、復旧方法を確認します。本記事では依存関係の読み取りだけを行います。

自動サービスなのに停止している候補を探す

「起動中サービス一覧」とは逆に、Automatic構成なのに現在Stoppedのサービスを候補として抽出すると、障害調査の入口になります。Win32_ServiceでStartMode = 'Auto'かつState != 'Running'を確認します。ただし、遅延開始、トリガー開始、更新作業、意図した停止、フェールオーバー待機など正当な理由があるため、候補を異常一覧と呼ばないようにします。

Get-CimInstance Win32_Service |
    Where-Object { $_.StartMode -eq "Auto" -and $_.State -ne "Running" } |
    Select-Object Name, DisplayName, State, StartMode, ExitCode

サービスによっては起動して仕事を終えると停止する設計や、トリガーが来るまで待つ設計があります。ExitCodeが0でない場合も、製品固有コードや前回状態を確認します。組織の正常端末と同じ時点で比較し、イベントログと製品ログを照合します。自動開始へ変更する、回復動作を変更する、サービスアカウントを置き換えるといった操作は、根拠と承認なしに行いません。

イベントログで状態変化の時刻と理由を追う

サービスの開始・停止・失敗は、SystemログのService Control Managerソースに記録されることがあります。Get-WinEventで障害時刻の前後へ絞り、対象サービス名、イベントID、LevelDisplayName、Messageを確認します。イベントIDの意味はWindows版や事象に応じて公式情報と照合し、番号だけで結論付けません。同じ時刻のアプリケーションログや製品ログも確認します。

Get-WinEvent -FilterHashtable @{
    LogName      = "System"
    ProviderName = "Service Control Manager"
    StartTime    = (Get-Date).AddHours(-2)
} -MaxEvents 50 |
    Select-Object TimeCreated, Id, LevelDisplayName, Message

ログメッセージにはサービス名、実行ファイル、アカウント、内部パスなどが含まれる場合があります。外部へ共有するときは必要な箇所だけを伏せて提示します。ログが見つからない場合は、保持期間、ログサイズ、取得権限、実際の障害時刻、別チャネルを確認します。ログを消去したり、監査やセキュリティ製品を無効化したりすると調査証拠を失うため行いません。

リモート確認では権限と接続失敗を状態から分ける

許可された管理環境ではCIMセッションを使い、Win32_Serviceをリモート端末から取得できます。Get-Serviceのリモート機能はPowerShell版によって差があるため、対象環境の公式仕様を確認し、統一するならCIMやPowerShell Remotingの組織標準を使います。接続資格情報をコードへ平文で埋め込まず、最小権限の管理経路を利用します。

端末が停止、VPN外、名前解決失敗、認証失敗、ファイアウォール、WinRM/CIM無効、権限不足の場合、サービス一覧を取得できません。これを「サービス0件」として集計すると重大な誤判定になります。収集結果にはSuccess、NoMatch、AccessDenied、Offline、Timeoutなどの取得状態を別列で残します。大量端末へ同時接続すると管理基盤へ負荷を掛けるため、許可された対象と同時数に限定します。

CSVへ残す列と比較方法を設計する

一覧をCSVへ保存する場合、Name、DisplayName、State、StartMode、ProcessId、StartName、取得時刻、端末名を必要性に応じて選びます。ServiceControllerとCIMのオブジェクトを混在させるなら、StatusとStateなど列名の違いを統一します。表示用のFormat-Tableを先に通すと書式オブジェクトになり、CSVとして扱いにくくなるため、Select-Objectの後にExport-Csvを使います。

前回との差分では、追加、削除、Name変更、StartMode変更、State変更を分けます。ProcessIdは再起動ごとに変わるため、構成差分の主キーにしません。Windows Updateや製品アップグレードで正当に追加・削除されるサービスもあります。差分だけで不正プログラムや障害と断定せず、署名、インストール履歴、製品情報、イベント時刻を確認します。CSVは端末構成情報としてアクセス制御と保管期限を設けます。

実務で使う確認チェックリスト

  • Get-ServiceでRunningを抽出し、NameとDisplayNameを両方残したか
  • 現在StateとStartModeを別の情報として扱ったか
  • Win32_ServiceでProcessId、StartName、PathNameの必要な範囲だけ確認したか
  • 共有プロセスと依存関係を考慮し、プロセス名だけでサービスを断定していないか
  • AutomaticかつStoppedを直ちに異常と判断せず、トリガーやイベントを確認したか
  • 取得失敗と0件を分離し、ログや構成情報を必要以上に公開していないか
  • 停止、再起動、スタートアップ種類変更を読み取り確認から分離したか

結果を保存するときは、実行日時、端末名、Windowsのビルド、PowerShellの版、実行ユーザー、対象範囲を添えます。値が取得できなかった場合は「存在しない」とせず、権限、モジュール、リモート接続、対象OS、実行セッションを確認します。設定変更、停止、削除、再起動が必要になった場合は、読み取り確認とは別の作業として影響範囲、承認、バックアップ、戻し方を決めてから行います。

公式情報・参考資料

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次