こんにちは!現場でバリバリ自動化ツールを作っていると、「Active Directoryを入れるほどでもない小規模な環境なんだけど、ローカルユーザーのパスワード有効期限が切れて突然ログインできなくなるトラブルを防ぎたい」という相談を本当によく受けます。
GUIをポチポチクリックして確認するなんて、エンジニアの仕事じゃありませんよね。
今回は、Windowsに標準で備わっているWSH(Windows Script Host)とWinNTプロバイダを駆使し、ローカルユーザーのパスワード年齢(経過日数)を自動算出して事前警告を出す、実用的な管理スクリプトを一緒に作っていきましょう。
ここをクリアすれば、OSの深部(COMコンポーネントとADSI)を操作するVBScriptの本質がバッチリ見えてきますよ。さあ、知的な自動化の旅へ出発しましょう!
—
なぜWinNTプロバイダなのか?
Windowsのユーザー管理というと難しく聞こえますが、実はVBScriptからOSのデータベース(SAM)に直接アクセスする強力な仕組みが標準で用意されています。それが ADSI(Active Directory Service Interfaces) の WinNTプロバイダ です。
これを使うと、ローカルコンピューターのユーザー情報をまるで「ファイルやフォルダ」を扱うかのように、オブジェクトとして美しく操作できます。
押さえておくべきポイント
- PasswordAge(パスワードエイジ): パスワードが変更されてからの「秒数」が格納されています。これを日数に換算するのが今回のキモです。
- UserFlags(ユーザーフラグ): 「パスワード無期限」「アカウント無効」などの状態がビット演算で格納されています。ここを無視すると、すでに退職した人のアカウントまで警告対象になってしまいます。
—
全体設計:何を作るのか?
今回作成するVBScriptは、以下のロジックで動作します。
1. 対象マシンのローカルSAMに接続(WinNTプロバイダ使用)
2. 全ユーザーをループ処理し、オブジェクトの種類が「User」のものだけを抽出
3. 各ユーザーの「パスワード無期限」フラグをチェック(無期限なら除外)
4. PasswordAge(経過秒数)を「日」に換算
5. 設定した警告閾値(例: 45日以上経過)を超えていたら、コンソールやポップアップで警告!
—
実装コード(コピペで使える実用スクリプト)
メモ帳を開き、以下のコードを貼り付けて `CheckPasswordAge.vbs` という名前で保存してください。(文字コードは `Shift-JIS` または `BOM付きUTF-8` が安全です)
‘ ==============================================================================
‘ ツール名: ローカルユーザー パスワード有効期限チェック・警告スクリプト
‘ 概要 : WinNTプロバイダを用いてローカルユーザーのパスワード経過日数を算出し、
‘ 有効期限切れが迫っているアカウントを検知します。
‘ ==============================================================================
Option Explicit
‘ — 設定エリア —
Const WARNING_DAYS = 45 ‘ 警告を発動するパスワード経過日数(環境に合わせて変更してください)
‘ ——————
Dim objComputer, objUser
Dim strComputerName
Dim intPasswordAgeDays, dblPasswordAgeSeconds
Dim intUserFlags
Dim lngCount : lngCount = 0
‘ 自マシンのコンピューター名を取得
strComputerName = CreateObject(“WScript.Network”).ComputerName
WScript.Echo “=== ” & strComputerName & ” のローカルユーザー パスワード状況を調査中… ===”
On Error Resume Next
‘ WinNTプロバイダ経由でコンピュータオブジェクトにバインド
Set objComputer = GetObject(“WinNT://” & strComputerName & “,computer”)
If Err.Number <> 0 Then
WScript.Echo “[エラー] コンピューターへの接続に失敗しました: ” & Err.Description
WScript.Quit 1
End If
On Error GoTo 0
‘ フィルターを「User」に設定してループ効率を上げる
objComputer.Filter = Array(“User”)
For Each objUser in objComputer
‘ アカウントが無効化されている場合はスキップ
‘ UF_ACCOUNT_DISABLED = &H0002 (2)
If (objUser.UserFlags AND 2) = 0 Then
‘ 「パスワードを無期限にする」が有効かチェック
‘ UF_DONT_EXPIRE_PASSWD = &H10000 (65536)
If (objUser.UserFlags AND 65536) = 0 Then
‘ PasswordAgeは「秒」で帰ってくるため、日(Day)に変換 (秒 / 60 / 60 / 24)
On Error Resume Next
dblPasswordAgeSeconds = objUser.PasswordAge
If Err.Number = 0 Then
intPasswordAgeDays = Int(dblPasswordAgeSeconds / 86400)
‘ 警告日数を超えているか判定
If intPasswordAgeDays >= WARNING_DAYS Then
WScript.Echo “【警告】ユーザー [” & objUser.Name & “] のパスワード変更から ” & intPasswordAgeDays & ” 日が経過しています。(閾値: ” & WARNING_DAYS & “日)”
lngCount = lngCount + 1
End If
End If
On Error GoTo 0
End If
End If
Next
WScript.Echo “————————————————–”
If lngCount > 0 {
WScript.Echo “判定完了: 警告対象のアカウントが ” & lngCount & ” 件見つかりました。速やかにパスワード変更を行ってください。”
} Else {
WScript.Echo “判定完了: 警告対象のアカウントはありませんでした。すべて正常です。”
}
‘ オブジェクトの解放
Set objUser = Nothing
Set objComputer = Nothing
—
コードの深掘り:ここがエンジニアの腕の見せ所
初心者の方が「おっ」と躓きやすいポイントや、VBScript特有のメモリ管理・エラーハンドリングの極意を解説します。
1. `GetObject(“WinNT://…”)` の魔力
VBScriptの真骨頂は、OSの内部コンポーネントをCOM経由で直接叩ける点です。`WinNT://マシン名,computer` と指定することで、ローカルOSのデータベースへ直接パイプを繋ぎます。
ここでエラー(ネットワーク切断や権限不足など)が起きる可能性があるため、`On Error Resume Next` で優しくトラップしてあげるのがプロの作法です。
2. ビット演算 (`AND` 演算子) によるフラグ判定
ここが一番のハイライトです。`objUser.UserFlags` には、アカウントの状態がすべて足し算(ビット和)されて格納されています。
- アカウントが無効 (`2`)
- パスワード無期限 (`65536`)
これらを調べるために、算術の `AND` ではなく、論理演算の `AND` を使っています。
`(objUser.UserFlags AND 65536) = 0` という式は、「パスワード無期限フラグが立っていない(0である)か?」を正確に判定するイケてる書き方です。
3. 秒から日への変換 (`86400` の意味)
`PasswordAge` プロパティが返す値は「秒」です。
1日は `24時間 × 60分 × 60秒 = 86400秒` なので、取得した秒数を `86400` で割ることで「経過日数」を算出しています。`Int()` 関数で小数点以下を切り捨てるのも忘れずに。
—
陥りやすい罠とエラー対策
現場でこのスクリプトを動かす際、以下の罠にハマりがちです。
- 管理者権限の不足
ローカルSAMを覗きに行くため、管理者権限(Administrator権限)を持ったプロンプトで実行する必要があります。権限がないと `GetObject` の段階で「アクセスが拒否されました (Permission denied)」というエラーになります。
- 一度もパスワードを変更していないビルトインアカウント
OS標準のAdministratorやGuestなどで、パスワードが一度も変更されていない場合、`PasswordAge` プロパティの取得自体に失敗してエラーになることがあります。そのため、プロパティ取得の前にも `On Error Resume Next` を挟んで安全性を担保しています。
—
発展:実運用に向けたアイデア
このスクリプトをそのままタスクスケジューラに組み込み、週に1回自動実行させれば、立派なセキュリティ監査ツールになります。
さらに発展させるなら、コンソールに出力するだけでなく、以下のように拡張するのもおすすめです。
- `WScript.Echo` の代わりに `WshShell.Popup` を使って、ログイン中のユーザーの画面に直接ポップアップ警告を出す。
- 警告対象が見つかった場合のみ、メール送信COM(CDO.Messageなど)を使って管理者にアラートメールを飛ばす。
VBScriptはレガシーだと言われることもありますが、「追加のランタイムインストールの必要がなく、どのWindows端末でも即座に動く」という圧倒的な機動力は、他のどの言語にも代えがたい最大の武器です。
この知見をマスターしたあなたなら、日常の面倒な監視作業をスマートに自動化できるはずです。ぜひ日々の業務に役立ててくださいね!
