Systems Admin

Track User Logon and Logoff to a Shared Text File via Group Policy Scripts

The Windows event log already records every interactive logon and logoff — events 4624 and 4634 are sitting on every domain-joined client right now. The catch is that those events live on the client, scattered across dozens or hundreds of machines, with the Security log rolling over after a few days under the default size limits. For a quick, centralised “who’s been on which workstation and when” report that’s readable without an event-collector or a SIEM, the cheapest answer is two batch scripts and a Group Policy that runs them at logon and logoff. Lines append to a single shared text file on the DC, indexed by computer + user + timestamp; tail the file or grep it from anywhere with read access. This post walks the build — scripts, share, GPO — and the gotchas that come with the simple approach.

What you need before starting

  • An AD domain — the lab uses techpro.local with DC1 (192.168.0.1) as the controller and Client1 (192.168.0.72) as a domain-joined Windows machine
  • A test user account — the lab uses henry
  • Local administrator rights on the DC and on the management workstation
  • Domain Admin (or equivalent) rights to create + link the GPO
  • An understanding that this is a soft-audit pattern — useful for “quick visibility” questions, not a substitute for proper Security-event auditing or a real SIEM

Why this isn’t event ID 4624

The Security log captures every logon natively (event 4624 for success, 4625 for failure, 4634 for logoff, 4647 for explicit logoff) with rich metadata: logon type, source workstation, authentication package, security ID, full timestamp. Event-log subscriptions can forward those events to a central collector. That is the right answer for compliance auditing and security investigation.

The script-based approach this post covers is a different shape. It produces a flat, human-readable text file with one line per logon and one line per logoff. The advantages: one file, no event-log filtering needed, readable by anyone with a text editor, trivially greppable. The disadvantages: no logon-failure recording (only successful logons trigger the script), no per-process detail, and the user’s session can in principle stop the script before it writes (uncommon but possible). For environments that need both, run the script-based approach as a quick visibility layer alongside event-collector forwarding to a SIEM — they answer different questions.

Step 1 — Create the staging folder on the DC

From elevated PowerShell on DC1:

New-Item -ItemType Directory -Path 'C:\Log Data' -Force

The folder name is conventional, not required. Log Data with the space is what the source uses; Logs or UserActivity or anything else works equally well. The space in the name does mean the UNC path needs quoting in any script that refers to it — "\\DC1\Log Data\login.txt".

C:\Log Data folder created on the domain controller DC1 with empty contents shown in File Explorer ready to receive the login.bat and logoff.bat batch script files
Empty C:\Log Data staging folder on DC1. The two batch scripts and the log files all live here; the share ACL controls who can write to them.

Step 2 — Write the two batch scripts

The batch scripts are intentionally minimal — one echo per script, redirected to a file. The four environment variables Windows populates for every interactive session (%COMPUTERNAME%, %USERNAME%, %DATE%, %TIME%) are exactly the columns we want.

login.bat

In C:\Log Data\login.bat:

@echo off
echo %COMPUTERNAME% %USERNAME% %DATE% %TIME% >> "\\DC1\Log Data\login.txt"

@echo off at the top suppresses the noisy “C:\Log Data>echo…” that would otherwise flash on the user’s screen during logon. The append redirect (>>) is critical — > would overwrite the file every logon, defeating the entire purpose. The UNC path is hard-coded to the DC because the script runs on the client, not on the DC; it has to write across the network to land in a single shared file.

login.bat batch script open in Notepad showing the echo command that writes COMPUTERNAME, USERNAME, DATE, and TIME environment variables redirected to the login.txt file on the DC UNC share
login.bat — one line of echo that captures the four environment variables every Windows session populates and appends them to login.txt on the DC.

logoff.bat

In C:\Log Data\logoff.bat:

@echo off
echo %COMPUTERNAME% %USERNAME% %DATE% %TIME% >> "\\DC1\Log Data\logoff.txt"

Mirror of login.bat. Same fields, different output file, fired by the logoff trigger instead of the logon trigger. Splitting into two files (rather than one with a tag column) keeps the files small and lets you tail one or the other depending on the question being asked.

logoff.bat batch script open in Notepad showing the parallel echo command that writes the same four environment variables redirected to the logoff.txt file on the DC UNC share
logoff.bat — mirror of login.bat, writing to logoff.txt. Same fields, different file, fired by the logoff trigger.

Step 3 — Share the folder so clients can write to it

The scripts run in the user’s context on the client, then write to a network share on the DC. Two ACLs have to permit the write — the share-level ACL and the NTFS ACL. Get one wrong and the script silently fails (the redirect produces no error, just an empty file).

Share permissions

  1. Right-click C:\Log DataPropertiesSharing tab → Advanced Sharing.
  2. Tick Share this folder. Share name defaults to Log Data.
  3. Click Permissions. Add Authenticated Users with Change permission (lets them write but not change ACLs). Remove Everyone if it’s in the list.
  4. Click OK to apply.
C:\Log Data folder Sharing tab in the Properties dialog with Authenticated Users granted Change permission so any domain-joined client can append to the log files
Sharing tab on the Log Data folder — Authenticated Users with Change permission. Required so the user’s session running the batch can write to the share.

NTFS permissions

  1. Same Properties dialog → Security tab.
  2. Add Authenticated Users with Modify permission. Modify includes the necessary write + delete-own-file permissions.
  3. Apply.
C:\Log Data folder Security tab in the Properties dialog with Authenticated Users granted Modify NTFS permission to align with the share-level Change permission
Security tab on the same folder — Authenticated Users with Modify NTFS rights. Both layers must permit write or the script silently fails.

Combined effect: any authenticated user in the domain can write to \\DC1\Log Data\. The narrowest defensible permission for this pattern is “Authenticated Users / append-only,” but Modify is what the source recommends and what the script needs — the redirect’s append behaviour relies on Modify-level rights.

Step 4 — Create the GPO

Open Group Policy Management on DC1.

  1. Right-click the techpro.local domain (or whichever OU you want to scope to) and pick Create a GPO in this domain, and Link it here.
  2. Name it Log Tracking (or any descriptive name). Click OK.
  3. Right-click the new GPO and pick Edit.
Group Policy Management Console showing the new Log Tracking GPO created at the domain root linked to the techpro.local domain
New Log Tracking GPO linked at the domain root — applies to every authenticated user in the domain, not scoped to a specific OU.

Step 5 — Attach the scripts to the GPO

The Logon and Logoff script triggers live under User Configuration, not Computer Configuration. This matters — the same GPO has separate Computer-side startup/shutdown script slots; we don’t want those.

  1. In the Group Policy Management Editor, navigate to User Configuration > Policies > Windows Settings > Scripts (Logon/Logoff).
  2. Double-click Logon in the right pane.
  3. Click Add.
  4. For Script Name, paste the UNC path: \\DC1\Log Data\login.bat. Leave Script Parameters blank.
  5. Click OK.
Group Policy Management Editor with the User Configuration Policies Windows Settings Scripts node selected showing the Logon and Logoff script policy entries
Group Policy Management Editor on the GPO. User Configuration > Policies > Windows Settings > Scripts exposes the Logon and Logoff entry points where the .bat files attach.
Logon Properties dialog with the Add Script dialog open and the UNC path to login.bat entered for execution at user logon
Logon Properties dialog — Add button used to register \\DC1\Log Data\login.bat as the user-logon script. Same flow on the Logoff entry for the logoff.bat side.
  1. Repeat for Logoff — same dialog, point it at \\DC1\Log Data\logoff.bat.
  2. Click OK to close. The GPO now has both scripts attached.

Step 6 — Apply the GPO and verify

Force a refresh on the DC:

gpupdate /force

The GPO is now active across the domain. The clients pick it up on the next user logon (or on their next 90-minute background refresh, whichever comes first). To verify immediately, sign out of the test client and sign back in as Henry — the login.bat fires invisibly during logon, and a single line should appear in \\DC1\Log Data\login.txt:

CLIENT1 henry  Sat 05/09/2026  09:14:22.13

Sign out and a corresponding line lands in logoff.txt. From the DC, Get-Content '\\DC1\Log Data\login.txt' -Tail 10 tails the file across the network; Get-Content '\\DC1\Log Data\login.txt' -Wait follows it in real time the way tail -f does on Linux.

Things that bite people in production

The script doesn’t run if the file isn’t reachable at GPO load time

If the client is off-network when the user signs in (e.g., a remote laptop without VPN), the UNC path is unreachable, and the script fails silently. The user logs in fine; no log entry is produced. The fix for environments where this matters is to use a local cache + sync pattern instead — have the script write to %APPDATA%\Logs\local-login.txt and a separate scheduled task copy that to the share when the network is available. More moving parts; more reliability.

The append redirect is racy under fast-logon storms

>> in cmd.exe opens the file, seeks to end, writes, closes. Two clients hitting the redirect within the same millisecond can produce interleaved or truncated lines. For a 50-user environment this is theoretical; for a 5000-user environment it’s a real source of corrupted log lines. The mitigation is either a tiny custom logger (PowerShell with file locking, or a small Win32 service running on the DC accepting submissions over HTTP), or accepting that 1 in 10000 lines may be malformed and writing the parser to skip them.

Logoff scripts can race the session teardown

The logoff trigger fires after the user-initiated logoff but before the session fully closes. If the script writes to a slow network share and the session teardown happens to win the race, the script gets killed mid-write. Mitigation: keep logoff scripts as short as possible (the single echo here is fine), and accept that a small percentage of logoff entries may be missing.

Both ACLs need to permit writing

Share-level Change + NTFS Modify is the supported pair. Forgetting one or the other produces a silent no-op — the script runs, the redirect succeeds locally (no error returned to the script), but no line lands in the file. The diagnostic: from a client, manually echo test >> "\\DC1\Log Data\login.txt" — if it doesn’t append, fix the ACL. icacls "\\DC1\Log Data" from a client lists the effective ACL.

Domain-wide GPO link is overly broad for production

Linking Log Tracking at the domain root means it applies to every user, including service accounts that may sign in to do non-interactive work. The Notion source links at the domain for simplicity; in production, link to a specific OU like Workstations\Sales or Workstations\Engineering — you’ll get the user-activity tracking without polluting the log file with service-account or scheduled-task “logons.”

The log file grows without rotation

One line per logon per user adds up. A 500-user environment with three logons per day per user produces 1500 lines a day, or roughly half a million lines a year. The file stays small (text is cheap), but plain text files of any size become slow to grep for recent entries. The fix: a scheduled task on the DC that runs nightly, archives login.txt to login-YYYYMMDD.txt, and starts a fresh empty file. Move-Item + New-Item in PowerShell is a 3-line scheduled task.

Where this fits

For more rigorous user-activity auditing, see configure advanced audit policies in Active Directory and enable Active Directory auditing — those cover the proper Security-event-log path with categorisation, success-vs-failure logging, and per-OU scoping. For Group Policy itself, the Group Policy pathway covers the broader configuration surface; the Windows Server administration pathway covers the rest of the surface area.

Leave a Reply