Windows 10 Proで「RDPで誰かがログオンした瞬間にメール通知したい」のに、タスク スケジューラのトリガー「ユーザー セッションへの接続時(リモートからの接続)」が“新規RDPログオン”では動かない――この挙動は珍しくありません。原因を整理しつつ、確実に拾うための現実的な回避策(GUI設定/PowerShell自動登録/RDPだけに絞る方法)までまとめます。
起きている現象を整理(再接続はOK、新規ログオンはNG)
質問の状況をもう少し正確に言い換えると、だいたい次の状態です。
- Windows 10 Pro(ホスト側)に対して、RDPで接続する
- タスク スケジューラのトリガーを「ユーザー セッションへの接続時」→「リモート コンピューターからの接続」に設定している
- いったんRDPセッションを「切断(Disconnect)」して残しておき、同じユーザーで同じセッションへ「再接続(Reconnect)」するとタスクが実行される
- ところが、ホストにそのユーザーの既存セッションがない状態(再起動後、ログオフ後、あるいは初回接続など)で“新規にRDPログオン”するとタスクが実行されない
この差がハマりポイントで、ここを理解すると回避策が一直線になります。
原因:「ユーザー セッションへの接続時」は“ログオン”ではなく“接続/再接続”寄りに振れることがある
タスク スケジューラのトリガーには、似ているようで目的が違うものが混在しています。
| トリガー | 拾うタイミングのイメージ | 得意なケース | 苦手になりやすいケース |
|---|---|---|---|
| ログオン時(At log on) | ユーザーのログオン セッションが作られた瞬間 | 新規ログオン(ローカル/Remote両方) | 「接続/再接続」と完全一致させたい用途(RDP限定など)は工夫が必要 |
| ユーザー セッションへの接続時(On connection to user session) | “セッションへ接続した/戻ってきた”瞬間 | 切断済みセッションへの再接続、ユーザー切替の戻り | 新規ログオン(セッション新規作成)の瞬間を取りこぼすことがある |
RDPは、ユーザー体験としては「接続してログオン」ですが、内部的には「認証」「セッション作成」「ログオン」「デスクトップ表示」「切断/再接続」など複数段階に分かれます。トリガー「ユーザー セッションへの接続時」が“既存セッションへの接続/再接続”のイベントに寄ってしまうと、「セッションが存在しない状態からの新規ログオン」を確実に拾えないことがあります。
また、「再起動後から挙動が変わったように見える」という点も説明がつきます。再起動直後は当然ながら“切断済みの既存セッション”が存在しないため、再接続イベントが発生しません。結果として「再接続なら動くのに、新規ログオンでは動かない」という差がはっきり観測されます。
最短の解決:目的が“RDPログオン検知”なら「ログオン時(At log on)」へ寄せる
結論として、狙いが「RDPでのログオン検知」なら、まずはトリガーを「ログオン時(At log on)」へ切り替えるのが堅いです。これで新規ログオンを取りこぼしにくくなります。
GUIでのおすすめ設定(失敗しにくい形)
タスク スケジューラ(taskschd.msc)で新規タスクを作る場合、以下の考え方が安定します。
| 項目 | 推奨 | 理由 |
|---|---|---|
| 全般 | 「ユーザーがログオンしているときのみ実行」 | RDP判定に環境変数(SESSIONNAME/CLIENTNAME)を使う場合、ユーザーコンテキストで動かした方が確実 |
| 全般 | 必要に応じて「最上位の特権で実行」 | ログ参照やネットワーク操作など、環境によっては権限が必要 |
| トリガー | 「ログオン時」 | 新規ログオンを確実に拾う |
| トリガー | 「タスクを開始するまでの遅延:30秒」 | ログオン直後はネットワークやプロファイルがまだ不安定な場合があるため(メール送信失敗の軽減) |
| 操作 | PowerShellスクリプトを起動 | メール送信やRDP判定など、柔軟に制御できる |
| 条件 | 「ネットワーク接続が利用可能な場合のみ開始」 | SMTP/Graph/Teams Webhook等、通知はネットワーク依存が多い |
| 設定 | 「既に実行中の場合:新しいインスタンスを開始しない」 | 短時間に複数回ログオンした場合の重複通知を抑制 |
タスク スケジューラには以前「電子メールの送信」アクションがありましたが、現在は非推奨の扱いです。現実的にはPowerShellで通知を送るのが安全です。
PowerShellで「ログオン時」タスクを作る例(ローカルPC向け)
ここでは「ログオン時にスクリプトを実行するタスク」をPowerShellで登録します。実運用では、実行するスクリプト(NotifyRdp.ps1など)を“メール通知処理”に差し替えます。
# 管理者として PowerShell を起動して実行する想定
$taskName = "Notify-Logon"
$scriptPath = "C:\Scripts\NotifyRdp.ps1"
# アクション:PowerShell でスクリプト実行
$action = New-ScheduledTaskAction `
-Execute "powershell.exe" `
-Argument "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`""
# トリガー:ログオン時(任意ユーザー)
$trigger = New-ScheduledTaskTrigger -AtLogOn
# 設定:重複起動を抑え、失敗時の再試行も設定
$settings = New-ScheduledTaskSettingsSet `
-AllowStartIfOnBatteries `
-DontStopIfGoingOnBatteries `
-StartWhenAvailable `
-MultipleInstances IgnoreNew `
-ExecutionTimeLimit (New-TimeSpan -Minutes 5) `
-RestartCount 3 `
-RestartInterval (New-TimeSpan -Minutes 1)
# タスク登録(現在のユーザーで「ログオン時に実行」)
Register-ScheduledTask `
-TaskName $taskName `
-Action $action `
-Trigger $trigger `
-Settings $settings `
-Description "Logon notification task (RDP判定はスクリプト側で実施)"
ポイントは、「ログオン時」自体はRDP/ローカル両方で発火するので、RDPだけ通知したい場合はスクリプト側で判定することです(次章)。
補足:リモートPCに同じタスクを一括配布したい場合(Invoke-Command)
複数台に仕込みたい場合、WinRM(PowerShell Remoting)が有効なら、同様の登録をリモートで流せます。運用上は、台数が増えるほど「手作業GUI」よりもミスが減ります。
$computers = @("PC-01","PC-02") # 対象PC名
$taskName = "Notify-Logon"
$scriptPath = "C:\Scripts\NotifyRdp.ps1"
Invoke-Command -ComputerName $computers -ScriptBlock {
param($taskName, $scriptPath)
New-Item -ItemType Directory -Path (Split-Path $scriptPath) -Force | Out-Null
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`""
$trigger = New-ScheduledTaskTrigger -AtLogOn
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -MultipleInstances IgnoreNew
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Settings $settings -Force | Out-Null
} -ArgumentList $taskName, $scriptPath
リモート実行では、事前にWinRM有効化(Enable-PSRemoting)やファイアウォール、認証方式の整備が必要です。ここが難しい環境では、GPOや構成管理(Intune等)で配布する方が現実的です。
RDP“だけ”に絞る方法A:ログオン時に動かし、スクリプト側でRDP判定して分岐
「ログオン時」トリガーは確実性が高い反面、ローカルログオンも拾います。そこで、スクリプトでRDPかどうかを判定して、RDPのときだけ通知します。
RDP判定の実用ライン(環境変数を使う)
ユーザーコンテキストで実行される場合、次の環境変数が判断材料になります。
| 環境変数 | RDP時の典型 | ローカル時の典型 | メモ |
|---|---|---|---|
| SESSIONNAME | RDP-Tcp#○○ | Console | 最も分かりやすい。RDPならだいたいRDP-Tcp系になる |
| CLIENTNAME | 接続元PC名 | Console / 空 | 「どの端末から来たか」を通知文面に入れたい場合に便利 |
注意点として、タスクをSYSTEMなど別アカウントで動かすと、これらの値が期待通りにならないことがあります。RDP判定を環境変数で行うなら、まずは“ログオンしたユーザーとして実行”が失敗しにくいです。
RDP時だけメール送信するPowerShell例(ひな形)
以下は「RDPなら通知、ローカルなら何もしない」最小構成の例です。SMTPの設定は環境に合わせて差し替えてください。
# C:\Scripts\NotifyRdp.ps1
# --- RDP判定 ---
$sessionName = $env:SESSIONNAME
$clientName = $env:CLIENTNAME
$userName = $env:USERNAME
$computer = $env:COMPUTERNAME
$isRdp = $false
if ($sessionName -and $sessionName -like "RDP*") {
$isRdp = $true
}
if (-not $isRdp) {
# ローカルログオンは通知しない
exit 0
}
# --- 通知内容 ---
$subject = "[RDPログオン] $computer / $userName"
$body = @"
RDPログオンを検知しました。
PC: $computer
ユーザー: $userName
SESSIONNAME: $sessionName
CLIENTNAME: $clientName
日時: $(Get-Date -Format "yyyy/MM/dd HH:mm:ss")
"@
# --- メール送信(例)---
# 注意:Send-MailMessage は将来的に非推奨扱いが強まっています。
# まずは動かす目的で例示し、運用では別方式(Graph、SMTPリレー、Webhook等)も検討してください。
$smtpServer = "smtp.example.com"
$smtpPort = 587
$from = "[email protected]"
$to = "[email protected]"
# 認証が必要なら、資格情報の安全な保管(Credential ManagerやDPAPI)を推奨
# ここでは例として対話入力を避け、あらかじめ暗号化保存したXMLを読む想定にしておく
$credPath = "C:\Scripts\smtp-cred.xml"
if (Test-Path $credPath) {
$cred = Import-Clixml -Path $credPath
} else {
# 初回だけ手動で作成し、ACLを絞って保存しておく(別途実施)
$cred = $null
}
try {
if ($cred) {
Send-MailMessage -SmtpServer $smtpServer -Port $smtpPort -UseSsl `
-From $from -To $to -Subject $subject -Body $body -Encoding UTF8 `
-Credential $cred
} else {
Send-MailMessage -SmtpServer $smtpServer -Port $smtpPort -UseSsl `
-From $from -To $to -Subject $subject -Body $body -Encoding UTF8
}
} catch {
# 失敗時にイベントログやファイルへ記録しておくと運用が楽
$log = "C:\Scripts\NotifyRdp-error.log"
"$(Get-Date -Format s) $($_.Exception.Message)" | Out-File -FilePath $log -Append -Encoding UTF8
}
資格情報をDPAPIで暗号化して保存する(運用で詰まりやすい所)
上の例ではImport-Clixmlで資格情報を読み込む形にしています。次のように一度だけ手動で作っておくと、以後は非対話で送れます(暗号化はWindowsの仕組みに依存します)。
# 1回だけ実行(ログオン通知を動かすユーザーで実行)
$cred = Get-Credential # SMTPユーザー/パスワードを入力
$cred | Export-Clixml -Path "C:\Scripts\smtp-cred.xml"
# 重要:ファイルのアクセス権(ACL)を絞る
# 例:Administrators と当該ユーザーのみ読み取り可能にするなど
組織のポリシーでSMTPが使いづらい場合は、Microsoft Graph(Outlook送信)、社内SMTPリレー、Teams/SlackのWebhookなどに寄せると運用が安定しやすいです。
RDP“だけ”に絞る方法B:セキュリティログのイベントをトリガーにする(ログオン種別10)
「ローカルは除外し、RDPログオンだけ確実に拾いたい」「ユーザーが複数いても一括で拾いたい」なら、イベントログトリガーが強力です。
代表的な考え方は、セキュリティログのログオン成功イベント(イベントID 4624)から、ログオン種別(LogonType)が10(RemoteInteractive)のものだけを拾う、という方法です。
手順の全体像
- (必要なら)監査ポリシーで「ログオン」の成功監査を有効化
- タスク スケジューラのトリガーを「イベント時」にする
- カスタムフィルター(XML)で「4624 かつ LogonType=10」に絞る
- アクションで通知スクリプトを実行(メール/Webhook等)
カスタムXMLフィルター例(4624かつLogonType=10)
タスク スケジューラの「トリガー」→「新規」→「イベント時」→「カスタム」→「新しいイベント フィルター」→「XML」タブで「クエリを手動で編集する」にチェックし、次のようなフィルターを入れます。
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">
*[System[(EventID=4624)]]
and
*[EventData[Data[@Name='LogonType']='10']]
</Select>
</Query>
</QueryList>
さらにユーザーを限定したい場合は、TargetUserName(または環境によりSubjectUserName)で絞る方法もあります。ただしイベントのData名は環境差が出ることがあるため、まずはイベントビューアで実際の4624を開き、「詳細」タブでフィールド名を確認してから詰めるのが安全です。
イベントログトリガー方式のメリット/デメリット
| 観点 | メリット | デメリット |
|---|---|---|
| 確実性 | RDPログオン(種別10)を狙い撃ちできる | 監査ポリシーやログ保持の影響を受ける |
| RDP限定 | ローカルログオンを自然に除外できる | 運用でフィルター調整が必要になることがある(例:NLAや追加イベント) |
| 管理 | ユーザーが増えても同じタスクで拾える | タスク実行ユーザーをどうするか(SYSTEMで通知する等)設計が必要 |
参考:RDP関連イベントは他にもある(目的別に使い分け)
「ログオンを検知したい」のか、「接続/再接続を検知したい」のか、「認証に成功した時点を拾いたい」のかで、見るログが変わります。運用で困ったときに切り替えられるよう、代表例だけ押さえておくと便利です。
| 目的 | 見る候補 | 特徴 |
|---|---|---|
| RDPログオン(成功) | Security:4624(LogonType=10) | 「実際にログオンした」を取りやすい。RDPだけに絞りやすい |
| RDPの再接続/切断 | Security:4778/4779(環境により) | 「切断した」「再接続した」を拾いやすい(監査設定に依存) |
| RDP認証(早い段階) | TerminalServices-RemoteConnectionManager(Operational) | 「認証が通った」段階を拾える場合がある。ログオンとはズレることがある |
| セッション状態(OS側) | TerminalServices-LocalSessionManager(Operational) | セッションの開始/切断/再接続など、状態変化の観察に向く |
今回のように「接続時トリガーが新規ログオンを拾わない」ケースでは、“ログオンを拾う仕組み(At log on / 4624)へ寄せる”のが安定します。
なぜ「再接続では動く」のかを再現して腹落ちさせる(切断とログオフの違い)
RDPでウィンドウを閉じたとき、ユーザーが意図せず“ログオフ”ではなく“切断”になっているケースが多いです。
- 切断(Disconnect):セッションはPC側に残る。再接続が可能(このとき“接続/再接続”系のイベントが出やすい)
- ログオフ(Sign out):セッションが終了する。再接続ではなく次回は新規ログオンになる
- 再起動:当然セッションは消える。次回は新規ログオンになる
つまり、「ユーザー セッションへの接続時」で動いていたのは、実は“新規ログオン”ではなく“切断セッションへの復帰”を拾っていた、という構図になりがちです。
トラブルシューティング:タスクが動かないときのチェックリスト
回避策に切り替えても、メール送信やスクリプト実行で詰まることがあります。ありがちな落とし穴を先に潰しておくと運用が楽です。
タスク スケジューラ側
- 履歴(History)を有効化:タスクが起動したか、どこで失敗したかが追える
- 「開始するプログラム」の引数のクォート:パスに空白がある場合、
-File "C:\Path With Space\script.ps1"のように必ず囲む - 実行ポリシー:
-ExecutionPolicy Bypassを付ける(社内ルールがある場合は署名運用へ) - 遅延開始:ログオン直後はネットワーク未確立で通知が失敗しやすい。まずは30秒遅延で安定することが多い
- 重複実行:短時間にログオンが重なると通知が連投される。複数インスタンス設定で抑制
スクリプト側
- RDP判定の前提:SYSTEM実行だと
SESSIONNAMEが期待通りにならないことがある。まずはユーザー実行に寄せて検証 - メール送信の失敗ログ:失敗時にファイルへ書く(例:
C:\Scripts\NotifyRdp-error.log)だけで原因究明が早くなる - SMTP要件:587/TLS必須、アプリパスワード必須、社内FWで外向きSMTP不可など環境差が大きい
イベントログ方式の場合
- 4624が記録されているか:実際にSecurityログに4624が出ていないと、当然タスクは発火しない
- LogonTypeが10か:RDPでも状況によって別の種別が混ざることがあるため、まずはフィルター無しで観察してから絞る
- ログ保持:ログがすぐローテートする環境では、追跡や原因調査が難しくなるため保持サイズも見直す
運用を“通知がうるさくない”形に整えるコツ(重複防止・情報量)
実運用では「検知できる」だけでなく「通知が役に立つ」ことが重要です。おすすめの工夫をまとめます。
- 重複通知の抑制:同一ユーザーが短時間に再ログオンした場合は抑制する(例:5分以内は通知しない)
- 通知本文に入れると便利な情報:
- PC名、ユーザー名、日時
- SESSIONNAME(RDP-Tcp#XX)
- CLIENTNAME(接続元端末名)
- 「切断」も把握したい場合:ログオン通知と別に、切断(Disconnect)通知タスクも作ると監視が一気に実用的になる
監視の目的が「不正ログオン検知」寄りなら、メールだけでなく、Teamsへの投稿、Syslog/SIEMへの転送、アカウントのロックアウト連携なども視野に入ります。ただし、いきなり盛ると壊れやすいので、まずはログオン時(At log on)で確実に拾う→RDP判定を追加→イベントログ方式へ移行、の順が失敗しにくいです。
まとめ:最短は「ログオン時」へ、RDP限定は“判定かイベント”で詰める
- 「ユーザー セッションへの接続時(リモートからの接続)」は、再接続に強いが新規ログオンを取りこぼすことがある
- RDPログオンの“確実な検知”が目的なら、まずは「ログオン時(At log on)」へ切り替えるのが最短ルート
- RDPだけ通知したい場合は、
- 方法A:ログオン時に動かして、スクリプトで
SESSIONNAME等からRDP判定 - 方法B:Securityログの4624(LogonType=10)をトリガーにしてRDPログオンを狙い撃ち
- 方法A:ログオン時に動かして、スクリプトで

コメント