サイトやVPSの稼働を自分で見張る|PowerShellでHTTPの応答をCSVに記録する
VPSやWordPressのサイトが「今つながっているか」「どのくらいの時間で返ってくるか」は、監視サービスに登録しなくても、PowerShellのスクリプトを1つ書けば、自分のPCで記録できます。この記事では、URLに一定間隔でGETを送り、結果をCSVに残して、稼働率と応答時間の中央値・最大値を出すスクリプトを、実際に動かした結果とあわせて載せます。
(確認:筆者のWindows 11で、Windows PowerShell 5.1とPowerShell 7の両方で実行。対象は筆者のサイトのトップページに、5秒間隔で12回のGETです。短時間の試験なので、長期の稼働率を示すものではありません)
何を記録するか
- 時刻・URL・HTTPステータス・応答時間(ミリ秒)を、1回ごとに1行のCSVに追記する
- ステータスが200〜399なら「成功」、0は接続できない・名前が引けない・タイムアウト、404や500はそのまま記録する
- 最後に、回数・成功数・稼働率・応答時間の中央値と最大値を表示する
スクリプト(Watch-Http.ps1)
# 指定したURLに一定間隔でGETを送り、結果をCSVに追記して、最後に稼働率と応答時間の中央値・最大値を出す
# 日本語のコメントを入れるので、Windows PowerShell 5.1 で動かすには UTF-8(BOM付き)で保存する
param(
[string]$Url = "https://realine.net/",
[int]$Count = 12, # 回数
[int]$IntervalSec = 5, # 間隔(秒)
[int]$TimeoutSec = 10, # 1回あたりのタイムアウト
[string]$Csv = "$PSScriptRoot\watch_http.csv"
)
Add-Type -AssemblyName System.Net.Http
$client = New-Object System.Net.Http.HttpClient
$client.Timeout = [TimeSpan]::FromSeconds($TimeoutSec)
$client.DefaultRequestHeaders.CacheControl = New-Object System.Net.Http.Headers.CacheControlHeaderValue
$client.DefaultRequestHeaders.CacheControl.NoCache = $true
if (-not (Test-Path $Csv)) { "time,url,status,ms" | Out-File -FilePath $Csv -Encoding utf8 }
$results = @()
for ($i = 1; $i -le $Count; $i++) {
$sw = [System.Diagnostics.Stopwatch]::StartNew()
try {
$resp = $client.GetAsync($Url).GetAwaiter().GetResult() # 404や500でも例外にならず、ステータスが返る
$status = [int]$resp.StatusCode
$null = $resp.Content.ReadAsStringAsync().GetAwaiter().GetResult()
$resp.Dispose()
} catch {
$status = 0 # 0 = 接続できない・名前が引けない・タイムアウト
}
$sw.Stop()
$ms = [int]$sw.ElapsedMilliseconds
$now = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
"$now,$Url,$status,$ms" | Out-File -FilePath $Csv -Append -Encoding utf8
$results += [pscustomobject]@{ Status = $status; Ms = $ms }
if ($i -lt $Count) { Start-Sleep -Seconds $IntervalSec }
}
$client.Dispose()
$ok = @($results | Where-Object { $_.Status -ge 200 -and $_.Status -lt 400 }).Count
$sorted = @($results.Ms | Sort-Object)
$median = $sorted[[math]::Floor(($sorted.Count - 1) / 2)]
"回数: $Count 成功: $ok 稼働率: {0:P1} 中央値: {1}ms 最大: {2}ms" -f ($ok / $Count), $median, ($sorted | Select-Object -Last 1)
日本語のコメントを入れたファイルは、UTF-8(BOM付き)で保存してください。BOMがないと、Windows PowerShell 5.1では日本語が文字化けして、スクリプトが動きません(筆者の環境で実際に構文エラーになりました)。
実行例
.\Watch-Http.ps1 -Url "https://example.com/" -Count 12 -IntervalSec 5
筆者のサイトで実行した結果は、次のとおりです。
| 実行環境 | 回数 | 成功 | 稼働率 | 中央値 | 最大 |
|---|---|---|---|---|---|
| Windows PowerShell 5.1 | 12 | 12 | 100.0% | 298ミリ秒 | 788ミリ秒 |
| PowerShell 7 | 12 | 12 | 100.0% | 297ミリ秒 | 473ミリ秒 |
Windows PowerShell 5.1では1回目だけ788ミリ秒と遅く、ほかの回は264〜514ミリ秒でした。PowerShell 7は最大473ミリ秒です。1回目が遅い原因は調べていません。ここでの応答時間は、ヘッダーだけでなく、本文を最後まで読み終えるまでの時間です。ヘッダーが返るまでの時間(TTFB)だけを測る方法はcurlでTTFBを10回測る方法にあります。
中央値は、回数が偶数の時は、小さい方から数えて真ん中の2つのうち下側を使っています(通常の中央値とは、0.5〜1ミリ秒ずれる場合があります)。
失敗した時の記録も確かめた
| 対象 | 記録されたステータス |
|---|---|
| 存在しないページ(404) | 404(応答時間は約300ミリ秒) |
| 存在しないドメイン | 0(名前が引けず、約0〜120ミリ秒で失敗) |
Invoke-WebRequestを使わなかった理由
最初は Invoke-WebRequest で書きました。ところが、筆者の環境のWindows PowerShell 5.1では、存在しないページ(404)を取得した時に、例外にレスポンスが入らず、ステータスが取れませんでした(「接続が予期せずに閉じられました」という例外になりました)。JSONを返すAPIの404では取れたため、サーバーの応答の形に依存するようです。原因までは調べていません。そこで、404や500でも例外にならずステータスを返す HttpClient に変えました。
使う時の注意
- 間隔を短くしすぎない。他人のサイトに連続してアクセスするのは迷惑になります。自分のサイトか、許可されたサイトだけにします
- ブラウザのキャッシュは使わないので、毎回サーバーに取りに行く(
Cache-Control: no-cacheを付けています)。CDNやサーバーのキャッシュは残るため、キャッシュを通さない速度は別に測ります - 自宅のPCから測る値には、自宅の回線の状態も含まれる。サーバーだけの問題かどうかは、別の場所からも測って確かめる
- PCが止まっている間は記録されない。常時の監視が必要なら、別のサーバーや監視サービスを使う
この記事で確かめていないこと
- 数時間〜数日の長期の記録(今回は12回・約1分間のみ)
- 他のVPS・サーバー会社のサイトでの動作
- HTTPSの証明書の期限の確認(別の方法が必要です)
VPSの契約期間ごとの料金はXServer VPSの契約期間別の総額、鍵でのログインはSSH鍵の作り方にまとめています。
まとめ
- PowerShellの
HttpClientで、時刻・ステータス・応答時間をCSVに残し、稼働率と中央値・最大値を出せる - 筆者のサイトで12回測ると、稼働率100.0%・中央値は約300ミリ秒だった(短時間の試験)
- Windows PowerShell 5.1の
Invoke-WebRequestは、一部の404でステータスが取れなかったため、HttpClientを使った - 日本語のコメントを入れたスクリプトは、UTF-8(BOM付き)で保存する
本記事は記録の取り方の説明です。他人のサイトへ連続してアクセスしないでください。


