Building a Windows Laptop Monitoring Agent with Webex and Email Alerts
I wanted to build a small security and device-monitoring tool for my Windows laptop.
The idea is simple:
- When someone unlocks my laptop using a Windows PIN or password, I should receive a Webex message and an email.
- When the laptop battery reaches 50% or lower while it is not charging, I should receive a Webex alert.
- I should also be notified about important events such as failed login attempts, charger disconnection, sleep, resume, restart and shutdown.
Instead of creating a heavy employee-monitoring application, I decided to design a lightweight Windows background agent focused only on device security and power events.
What the System Should Do
The first version will monitor one Windows laptop.
It will detect the following events:
| Event | Webex Alert | Email Alert |
|---|---|---|
| Laptop unlocked | Yes | Yes |
| Laptop locked | Yes | Yes |
| Battery reaches 50% or lower | Yes | No |
| Charger disconnected | Yes | No |
| Failed Windows login attempts | Yes | Yes |
| Laptop started | Yes | Optional |
| Laptop restarted | Yes | Optional |
| Laptop shut down | Yes | Optional |
| Laptop entered sleep mode | Yes | Optional |
| Laptop resumed from sleep | Yes | Optional |
| Unexpected shutdown detected | Yes | Yes |
For battery monitoring, the alert should be sent only when:
Battery percentage <= 50%
AND
Laptop is not charging
The notification must not repeat every few seconds while the battery remains below 50%.
Example Unlock Notification
When the laptop is unlocked, the Webex and email notification could look like this:
π LAPTOP UNLOCKED
Device: LENOVO-LAPTOP
Windows User: Sam
Date: 15 July 2026
Time: 11:35 AM
Battery: 76%
Power Status: Not charging
Local IP: 192.168.1.25
Network: Office Wi-Fi
Event: Windows PIN/password unlock
This gives enough information to understand when, where and under which Windows account the laptop was accessed.
Example Battery Notification
πͺ« BATTERY WARNING
Device: LENOVO-LAPTOP
Windows User: Sam
Battery: 49%
Charging: No
Charger: Disconnected
Time: 3:20 PM
Please connect the laptop charger.
I may also add secondary thresholds later:
50% - Warning
20% - Critical
10% - Emergency
Proposed Architecture
The system will contain two main parts:
- A Windows monitoring agent installed on the laptop
- A backend API connected to Webex, email and PostgreSQL
ββββββββββββββββββββββββββββββββββββ
β Windows Laptop β
β β
β ββββββββββββββββββββββββββββββ β
β β Windows Monitoring Agent β β
β β β β
β β - Unlock and lock events β β
β β - Battery monitoring β β
β β - Charger monitoring β β
β β - Sleep and resume events β β
β β - Failed login detection β β
β β - Local retry queue β β
β ββββββββββββββββ¬ββββββββββββββ β
βββββββββββββββββββΌβββββββββββββββββ
β HTTPS
βΌ
ββββββββββββββββββββββββββββββββββββ
β Backend API β
β β
β - Validate device API key β
β - Store event in PostgreSQL β
β - Prevent duplicate alerts β
β - Send Webex direct message β
β - Send email notification β
βββββββββββββ¬βββββββββββββββ¬ββββββββ
β β
βΌ βΌ
Webex Bot SMTP Server
β β
βΌ βΌ
Direct Message Email Alert
Why Use a C# Windows Service?
The laptop-side agent could technically be built using Node.js or Python.
However, I prefer C# and .NET for this part because it provides better native integration with Windows.
A .NET Windows Service can handle:
- Windows session events
- Automatic startup with Windows
- Power mode changes
- Sleep and resume events
- Windows Event Log monitoring
- Battery and charger information
- Service recovery when the process crashes
The agent should run quietly in the background without requiring the user to manually start it.
Why Keep Notifications in the Backend?
The Windows agent should not directly contain sensitive credentials such as:
- Webex bot access token
- SMTP username
- SMTP password
- Database credentials
Instead, the agent should call a protected backend endpoint.
POST /api/device-alerts
The backend will handle all external integrations.
This also makes it easier to change notification providers later without reinstalling the laptop agent.
For example, Webex could later be replaced or extended with:
- Microsoft Teams
- Slack
- Telegram
- Push notifications
- SMS
Example Event Payload
The Windows agent can send a JSON payload like this:
{
"deviceId": "laptop-sam-001",
"deviceName": "LENOVO-LAPTOP",
"windowsUser": "Sam",
"eventType": "DEVICE_UNLOCKED",
"eventTime": "2026-07-15T11:35:00+05:30",
"batteryPercentage": 76,
"isCharging": false,
"localIp": "192.168.1.25",
"networkName": "Office Wi-Fi",
"agentVersion": "1.0.0",
"metadata": {
"authenticationType": "WINDOWS_CREDENTIAL"
}
}
The backend can then store the event and decide which notification channels should be used.
Event Types
The first version may support these event types:
DEVICE_UNLOCKED
DEVICE_LOCKED
BATTERY_LOW
BATTERY_CRITICAL
CHARGER_CONNECTED
CHARGER_DISCONNECTED
DEVICE_SLEEP
DEVICE_RESUMED
DEVICE_STARTED
DEVICE_RESTARTED
DEVICE_SHUTDOWN
UNEXPECTED_SHUTDOWN
FAILED_LOGIN
AGENT_STARTED
AGENT_STOPPED
Using standard event names will make the system easier to maintain and extend.
Battery Alert Logic
Battery alerts need careful state management.
Without it, the agent may send the same warning every 30 seconds.
A better approach is:
1. Check battery status every 30 seconds.
2. Check whether the laptop is charging.
3. If the laptop is not charging and battery is 50% or lower:
- Check whether the 50% alert was already sent.
- If not, send the alert.
- Save the alert state locally.
4. Do not send the same alert again while the battery remains below 50%.
5. Reset the warning state after the battery charges above 55%.
Pseudocode:
if (!battery.IsCharging && battery.Percentage <= 50)
{
if (!state.LowBatteryAlertSent)
{
await alertService.SendAsync("BATTERY_LOW");
state.LowBatteryAlertSent = true;
await stateStore.SaveAsync(state);
}
}
if (battery.IsCharging && battery.Percentage >= 55)
{
state.LowBatteryAlertSent = false;
await stateStore.SaveAsync(state);
}
This avoids notification spam.
Detecting Failed Login Attempts
Failed Windows sign-in attempts should also be monitored.
However, sending an alert for every incorrect password attempt may create too many notifications.
A better rule would be:
First failed attempt:
Store it in the log.
Three failed attempts within five minutes:
Send a Webex and email warning.
Five or more failed attempts:
Send a high-priority security alert.
Example:
π¨ MULTIPLE FAILED WINDOWS SIGN-INS
Device: LENOVO-LAPTOP
Attempted User: Sam
Failed Attempts: 3
Period: 5 minutes
Time: 2:14 AM
Multiple failed login attempts were detected.
Handling Internet Disconnection
The laptop may be unlocked while the internet is unavailable.
The alert should not be lost.
The agent should maintain a small local offline queue.
Event detected
|
v
Is internet available?
|
βββββ΄ββββ
β β
Yes No
β β
Send Save locally
β β
β Retry later
β β
βββββ¬ββββ
v
Mark as delivered
SQLite or an encrypted local JSON store could be used for the first version.
When connectivity returns, pending alerts can be sent automatically.
Securing the Agent API
Every laptop should receive its own identity and API key.
Example agent configuration:
HEIDI_API_URL=https://heidi.example.com/api/device-alerts
DEVICE_ID=laptop-sam-001
DEVICE_API_KEY=generated-long-random-key
The backend should implement:
- HTTPS-only communication
- One API key per device
- Rate limiting
- Request timestamp validation
- Request signing
- Duplicate-event protection
- Device enable and disable controls
- API-key rotation
- Audit logging
A stronger implementation can sign each request using HMAC.
signature = HMAC_SHA256(
requestBody + timestamp,
deviceSecret
)
The backend can reject requests with invalid signatures or old timestamps.
Database Structure
A basic PostgreSQL design could contain three tables.
Devices
CREATE TABLE devices (
id UUID PRIMARY KEY,
device_code VARCHAR(100) UNIQUE NOT NULL,
device_name VARCHAR(255),
assigned_user VARCHAR(255),
api_key_hash TEXT NOT NULL,
is_active BOOLEAN DEFAULT TRUE,
last_seen_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW()
);
Device Events
CREATE TABLE device_events (
id UUID PRIMARY KEY,
device_id UUID REFERENCES devices(id),
event_type VARCHAR(100) NOT NULL,
windows_user VARCHAR(255),
battery_percentage INTEGER,
is_charging BOOLEAN,
local_ip VARCHAR(100),
network_name VARCHAR(255),
event_time TIMESTAMPTZ NOT NULL,
metadata JSONB,
created_at TIMESTAMPTZ DEFAULT NOW()
);
Notification Logs
CREATE TABLE notification_logs (
id UUID PRIMARY KEY,
device_event_id UUID REFERENCES device_events(id),
channel VARCHAR(50) NOT NULL,
recipient TEXT,
status VARCHAR(50),
provider_response JSONB,
sent_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW()
);
Separating device events and notification logs helps track cases where the event was recorded successfully but the Webex or email delivery failed.
Backend Processing Flow
When the backend receives an event:
1. Validate the device ID.
2. Validate the API key or HMAC signature.
3. Reject expired requests.
4. Check for duplicate event IDs.
5. Store the event in PostgreSQL.
6. Load notification rules for the event type.
7. Send a Webex direct message.
8. Send email when required.
9. Store the delivery result.
10. Return the processing status to the laptop agent.
Example response:
{
"success": true,
"eventId": "d25183bb-8f74-4623-9884-a291a5c82102",
"notifications": {
"webex": "sent",
"email": "sent"
}
}
Future Admin Dashboard
Although the first release will monitor only one laptop, I want the database and API to support multiple company devices.
The dashboard could eventually show:
- Online and offline devices
- Current battery percentage
- Charging status
- Last unlock time
- Current Windows username
- Last IP address
- Failed login attempts
- Recent security alerts
- Agent version
- Notification delivery status
- Device activation and deactivation
- Per-device Webex recipients
- Per-device email recipients
Example dashboard layout:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Laptop Monitoring Dashboard β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Online Devices: 8 Offline Devices: 2 Alerts: 4 β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Device User Battery Status Last Eventβ
β--------------------------------------------------------------β
β Sam-Laptop Sam 74% Online Unlocked β
β Sales-Laptop-1 Arjun 48% Warning Battery β
β HR-Laptop-2 Priya 91% Charging Online β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Privacy Considerations
This project should remain a device-security tool, not hidden surveillance software.
It should not capture:
- Keystrokes
- Screenshots
- Webcam images
- Microphone audio
- Personal files
- Browser history
- Application content
- Private messages
For employee devices, it should be installed only on company-owned laptops with a clear monitoring policy and employee consent.
The goal is to monitor device health and security events, not private user activity.
Proposed Technology Stack
Windows Agent
C#
.NET 8
Windows Service
Windows Event Log
WMI or Windows Management APIs
SQLite for offline queue
HttpClient for API communication
Backend
Node.js
Express or NestJS
PostgreSQL
Webex Bot API
SMTP or Microsoft 365 email
JWT or HMAC device authentication
Dashboard
Next.js
React
Tailwind CSS
Recharts
Role-based access control
Development Phases
Phase 1: Personal Laptop Agent
- Detect Windows unlock and lock
- Send Webex direct messages
- Send email alerts
- Detect battery level
- Detect charger state
- Add local logs
- Start automatically with Windows
Phase 2: Security Events
- Detect failed login attempts
- Detect repeated failed logins
- Detect sleep and resume
- Detect startup and shutdown
- Detect unexpected shutdowns
- Add local retry queue
Phase 3: Multi-Device Backend
- Device registration
- Per-device API keys
- PostgreSQL event storage
- Notification rules
- Delivery logs
- Device heartbeat
Phase 4: Admin Dashboard
- Device list
- Battery and online status
- Security alert history
- Notification history
- Device controls
- Per-device settings
Phase 5: Enterprise Features
- Remote configuration
- Agent auto-update
- Department-based devices
- Alert escalation rules
- Microsoft Teams and Slack support
- Reporting and analytics
- Device health score
Final Thoughts
This started as a simple requirement:
Send me a Webex message and an email when my laptop is unlocked.
But it can grow into a useful lightweight device security and monitoring platform.
The most important design decision is keeping the Windows agent simple.
The agent should only detect events, collect limited device information and securely send data to the backend. All notification logic, credentials, logging and administration should remain on the server.
This provides better security, easier maintenance and a clear path from monitoring one personal laptop to managing multiple company devices.
I plan to start with the Windows unlock and battery monitoring features, then gradually add the security events, backend dashboard and multi-device support.
Tags
#windows
#dotnet
#csharp
#node
#webex
#security
#automation
#postgresql
#devops
#programming
Top comments (0)