1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

監視ノードからWindowsサービスを確認し、停止していたらメール通知するPowerShell

1
Last updated at Posted at 2026-06-15

監視ノードからWindowsサービスを確認し、停止していたらメール通知するPowerShell

はじめに

Windows Serverを運用していると、

  • 特定のサービスが落ちていないか確認したい
  • 監視製品を入れる前に、最低限の状態確認だけしたい
  • 移行期間中だけ、暫定的にサービス状態を見たい
  • 複数サーバのサービス状態を1か所から確認したい

という場面があります。

もちろん、Zabbixなどの監視製品を利用できるなら、それを使うのが本筋です。

ただ、現場では

監視製品に載せる前に、とりあえず最低限見たい

という場面もあります。

この記事では、管理用端末や監視ノードから複数サーバのWindowsサービス状態を確認し、停止していた場合にメール通知するPowerShellスクリプトを紹介します。

このスクリプトの考え方

このスクリプトは、監視対象サーバ自身に配置するものではありません。

想定している構成は以下です。

[監視ノード]
    |
    | net use で監視対象へ認証接続
    |
    | Get-Service -ComputerName でサービス状態確認
    |
    | 結果をログ出力
    |
    | NGがあればメール通知
    v
[監視対象サーバ]

つまり、各サーバにスクリプトやタスクを配置するのではなく、監視ノード側から複数サーバをまとめて確認する方式です。

この方式にすると、監視対象を増やす場合も、監視ノード側の定義を追加するだけで済みます。

やりたいこと

今回やりたいことは以下です。

  • 複数サーバのWindowsサービス状態を確認する
  • 確認前に net use で対象サーバへ認証接続する
  • サービスが起動していればOK
  • サービスが停止、または取得失敗したらNG
  • 結果をログファイルに保存する
  • NGがあった場合のみメール通知する

前提

この記事のサンプルでは、以下のような環境を想定します。

項目 内容
実行元 管理用Windows端末または監視ノード
監視対象 Windows Server
確認方法 Get-Service -ComputerName
認証 net use による一時接続
通知 SMTPサーバ経由のメール送信
実行方法 タスクスケジューラなどで定期実行

スクリプト例

以下は、監視ノードから複数サーバのサービス状態を確認し、NGがあった場合のみメール通知するサンプルです。

# ==========================================
# Windowsサービス簡易監視スクリプト
# 監視ノードから複数サーバのサービス状態を確認する
# ==========================================

# ログ出力先
$savePath = "C:\Surveillance\Services\SERVICES.txt"

# 日時
$nowDate = Get-Date -Format "yyyy-MM-dd"
$nowTime = Get-Date -Format "HH:mm:ss"

# 監視対象定義
# ServerName  : 監視対象サーバ名
# ServiceName : 確認するサービスの表示名
# UserName    : 接続に使用するユーザー
# Password    : 接続に使用するパスワード
$targets = @(
    @{
        ServerName  = "SERVER01"
        ServiceName = "Sample Service"
        UserName    = "Administrator"
        Password    = "password"
    },
    @{
        ServerName  = "SERVER02"
        ServiceName = "Another Service"
        UserName    = "Administrator"
        Password    = "password"
    }
)

# メール設定
$to      = @("alert@example.com")
$from    = "monitor@example.com"
$smtp    = "smtp.example.com"
$subject = "[NG] Windows Service Check $nowDate $nowTime"

# ログ初期化
"Windows Service Check" | Out-File $savePath -Encoding UTF8
"Date : $nowDate" | Out-File $savePath -Append -Encoding UTF8
"Time : $nowTime" | Out-File $savePath -Append -Encoding UTF8
"========================================" | Out-File $savePath -Append -Encoding UTF8

# NG結果格納
$ngList = @()

foreach ($target in $targets) {

    $serverName  = $target.ServerName
    $serviceName = $target.ServiceName
    $userName    = $target.UserName
    $password    = $target.Password

    "[$serverName] $serviceName check start" | Out-File $savePath -Append -Encoding UTF8

    try {
        # 監視対象サーバへ一時的に認証接続
        # ドメイン環境の場合は domain\user の形式に変更する
        net use "\\$serverName" /user:"$serverName\$userName" "$password" | Out-File $savePath -Append -Encoding UTF8

        # サービス状態取得
        $service = Get-Service -ComputerName $serverName |
            Where-Object { $_.DisplayName -eq $serviceName }

        if ($null -eq $service) {
            $message = "NG : Service not found. Server=$serverName Service=$serviceName"
            $ngList += $message
            $message | Out-File $savePath -Append -Encoding UTF8
        }
        elseif ($service.Status -eq "Running") {
            "OK : Server=$serverName Service=$serviceName Status=$($service.Status)" |
                Out-File $savePath -Append -Encoding UTF8
        }
        else {
            $message = "NG : Server=$serverName Service=$serviceName Status=$($service.Status)"
            $ngList += $message
            $message | Out-File $savePath -Append -Encoding UTF8
        }
    }
    catch {
        $message = "NG : Failed to check service. Server=$serverName Service=$serviceName Error=$($_.Exception.Message)"
        $ngList += $message
        $message | Out-File $savePath -Append -Encoding UTF8
    }
    finally {
        # 接続を削除
        net use "\\$serverName" /delete /yes | Out-File $savePath -Append -Encoding UTF8
    }

    "----------------------------------------" | Out-File $savePath -Append -Encoding UTF8
}

# 最終結果
if ($ngList.Count -eq 0) {
    $checkResult = "ALL OK"
}
else {
    $checkResult = "NG"
}

"Result : $checkResult" | Out-File $savePath -Append -Encoding UTF8
"========================================" | Out-File $savePath -Append -Encoding UTF8

# NG時のみメール送信
if ($ngList.Count -gt 0) {

    $body = @"
Windows Service Check Result : NG

Date : $nowDate
Time : $nowTime

NG List:
$($ngList -join "`r`n")

Please check attached log file.
"@

    Send-MailMessage `
        -To $to `
        -From $from `
        -SmtpServer $smtp `
        -Subject $subject `
        -Body $body `
        -Attachments $savePath `
        -Encoding UTF8
}

出力ログ例

すべてのサービスが起動している場合は、以下のようなログになります。

Windows Service Check
Date : 2026-06-15
Time : 10:00:00
========================================
[SERVER01] Sample Service check start
OK : Server=SERVER01 Service=Sample Service Status=Running
----------------------------------------
[SERVER02] Another Service check start
OK : Server=SERVER02 Service=Another Service Status=Running
----------------------------------------
Result : ALL OK
========================================

サービスが停止していた場合は、以下のようになります。

Windows Service Check
Date : 2026-06-15
Time : 10:00:00
========================================
[SERVER01] Sample Service check start
OK : Server=SERVER01 Service=Sample Service Status=Running
----------------------------------------
[SERVER02] Another Service check start
NG : Server=SERVER02 Service=Another Service Status=Stopped
----------------------------------------
Result : NG
========================================

タスクスケジューラで定期実行する

定期的に確認したい場合は、監視ノード側のタスクスケジューラから実行します。

プログラム

powershell.exe

引数

-ExecutionPolicy Bypass -File "C:\script\Check-Service.ps1"

開始フォルダー

C:\script

たとえば、5分ごと、10分ごと、1時間ごとなど、用途に応じて実行間隔を設定します。

なぜ監視ノード方式にするのか

単体サーバで自分自身のサービスを確認するだけであれば、各サーバ上で Get-Service を実行すれば済みます。

ただし、監視対象が複数ある場合、各サーバにスクリプトやタスクを配置すると管理が分散します。

監視ノード方式にすると、以下のようなメリットがあります。

  • スクリプトを監視ノード側に集約できる
  • 対象サーバの追加・削除を1か所で管理できる
  • メール通知元を監視ノードに集約できる
  • 対象サーバ側にタスクスケジューラを作らなくてよい
  • 一時的な移行期間や小規模環境の暫定監視に使いやすい

一方で、リモート接続の権限やファイアウォール、名前解決などを考慮する必要があります。

このスクリプトでできること

このスクリプトでは、以下のようなことができます。

  • 監視ノードから複数サーバのサービス状態を確認する
  • サービス停止時のみメール通知する
  • 確認結果をログファイルに残す
  • タスクスケジューラで定期実行する
  • 監視製品導入前の暫定監視として使う

注意点

監視製品の代替ではない

このスクリプトは、Zabbixなどの監視製品の代替ではありません。

以下のような用途には、監視製品を利用した方がよいです。

  • 多数サーバの一元管理
  • しきい値監視
  • 死活監視
  • リソース監視
  • ログ監視
  • 障害履歴の管理
  • 通知抑止
  • メンテナンス時間帯の制御
  • グラフ化

あくまで、暫定監視や小規模環境での簡易確認として使う想定です。

net useの認証情報に注意する

サンプルでは説明を分かりやすくするため、対象定義の中にユーザー名とパスワードを書いています。

ただし、実運用でスクリプト内に平文パスワードを直接書くのは推奨しません。

可能であれば、

  • タスクスケジューラの実行ユーザーに必要権限を付与する
  • 管理用アカウントの権限設計で対応する
  • 資格情報を安全に扱う仕組みを使う
  • 閉域環境に限定する

など、環境に合わせて検討してください。

net useが失敗した場合もNG扱いにする

監視対象サーバに接続できない場合、サービス状態も確認できません。

このサンプルでは、例外が発生した場合もNGとしてログに残すようにしています。

サービス停止だけでなく、

  • 名前解決失敗
  • ネットワーク疎通不可
  • 認証失敗
  • 権限不足
  • ファイアウォール
  • 対象サーバ停止

なども、確認失敗として扱う必要があります。

DisplayNameとNameの違いに注意する

Windowsサービスには、表示名とサービス名があります。

このサンプルでは、表示名で確認しています。

Where-Object { $_.DisplayName -eq $serviceName }

環境によっては、表示名よりサービス名で確認した方が確実な場合があります。

その場合は、以下のように変更します。

Where-Object { $_.Name -eq $serviceName }

Send-MailMessageについて

このサンプルでは Send-MailMessage を使用しています。

既存の閉域環境や、社内SMTPサーバを使う簡易通知では利用しやすい場合があります。

一方で、新しく仕組みを作る場合は、環境のセキュリティ方針や利用可能なメール送信方式に合わせて検討してください。

ログファイルの肥大化に注意する

定期実行する場合、ログファイルが増え続けることがあります。

必要に応じて、

  • 日次でログを分ける
  • 月次でローテーションする
  • 古いログを圧縮する
  • 保存期間を決める

などを検討してください。

まとめ

PowerShellを使うことで、監視ノードから複数サーバのWindowsサービス状態を確認し、停止していた場合のみメール通知する簡易監視を作ることができます。

監視製品の代替にはなりませんが、

  • 監視製品導入前の暫定確認
  • 小規模環境の簡易監視
  • 移行期間中の一時監視
  • 特定サービスだけの死活確認

といった場面では役に立つことがあります。

大事なのは、

何となく動いているはず

で終わらせず、

確認した結果をログに残し、異常時に気づけるようにする

ことだと思います。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?