Skip to content

About

PowerShell scripts that send individual email notifications for Active Directory user accounts with an approaching account expiration date. Includes an encrypted SMTP credential helper and a Scheduled Task installer for automated recurring execution.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

AD-ExpiringAccounts

PowerShell scripts that send individual email notifications for Active Directory user accounts with an approaching account expiration date. Includes an encrypted SMTP credential helper and a Scheduled Task installer for automated recurring execution.


Files

File Description
Get-ExpiringADAccounts.ps1 Main script — queries Active Directory and sends per-account email notifications
Save-SmtpCredential.ps1 Saves SMTP credentials to a DPAPI-encrypted file for authenticated sending
Install-ScheduledTask.ps1 Registers or removes a Windows Scheduled Task for the main script

Requirements

  • Windows PowerShell 5.1 or PowerShell 7+
  • RSAT: Active Directory module installed, or run directly on a domain controller
  • Read access to Active Directory
  • Administrator privileges (required for the Scheduled Task installer only)
  • Access to an SMTP server

Quick start

# 1. (Optional) Save SMTP credentials for authenticated sending.
#    Run as the same user that will execute the main script.
.\Save-SmtpCredential.ps1

# 2. Run the notification script.
.\Get-ExpiringADAccounts.ps1 -SmtpServer "smtp.example.com" -Recipient "tickets@example.com"

# 3. (Optional) Install a Scheduled Task for daily execution (run as Administrator).
.\Install-ScheduledTask.ps1 -Action Install -SmtpServer "smtp.example.com" -Recipient "tickets@example.com"

Save-SmtpCredential.ps1

Prompts for an SMTP username and password and stores them in a DPAPI-encrypted file (smtp-credential.xml) next to the script. The main script loads this file automatically to authenticate with the SMTP server.

  • DPAPI encryption ties the file to the current user and machine. It must be created by the same account (and on the same machine) that runs Get-ExpiringADAccounts.ps1.
  • If the main script runs under a different identity than the one that saved the file, decryption fails and authentication is skipped.

Usage

# Save credentials for the interactive user
.\Save-SmtpCredential.ps1

# Save credentials for the SYSTEM account (so a SYSTEM-run Scheduled Task can use them)
psexec -s -i powershell -File "C:\Dev\Powershell\AD-expiring-accounts\Save-SmtpCredential.ps1"

If no credential file is present, the main script sends email without authentication and emits a warning.


Get-ExpiringADAccounts.ps1

Parameters

Parameter Type Default Description
-DaysUntilExpiration int 30 Upper boundary: accounts expiring within this many days are included
-SmtpServer string (required) SMTP server hostname or IP
-SmtpPort int 25 SMTP server port
-Sender string (optional) FROM email address. If omitted and a credential file is loaded, the credential username is used as the sender
-Recipient string (required) TO email address (ticketing system)
-UseSsl switch — Enable SSL for SMTP connection
-CredentialFilePath string (auto) Path to the DPAPI-encrypted credential file. Defaults to smtp-credential.xml in the script directory
-StateFilePath string (auto) Path to the JSON state file tracking sent notifications. Defaults to SentNotifications.json in the script directory

Filtering logic

  • Only enabled accounts are included.
  • Only accounts with AccountExpirationDate between today and today + DaysUntilExpiration are included.
  • Accounts with no expiration date are automatically excluded.

Per-account email

For each expiring account not yet notified, the script sends an email with:

  • Subject: AD Account Expiring: <UserPrincipalName> (<ExpirationDate>)
  • Body: Plain text with account and manager details
  • Attachments: Single-row CSV and XML files for the account

Email body fields

Field Description
Login Name User logon name (SamAccountName)
First Name Given name
Last Name Surname
Email Email address
Company Company attribute
Expires Expiration date (yyyy-MM-dd)
Days Left Days until expiration (0 = expires today)
Manager — Login Name Manager's logon name
Manager — First Name Manager's first name
Manager — Last Name Manager's last name
Manager — Email Manager's email address

Manager fields are empty if no manager is assigned or the manager object cannot be resolved.

Attachment fields (CSV / XML)

The attached exports contain the same fields as the body plus UserPrincipalName: SamAccountName, UserPrincipalName, GivenName, Surname, Mail, Company, AccountExpirationDate, DaysRemaining, ManagerSamAccountName, ManagerGivenName, ManagerSurname, ManagerMail.

State tracking

The script maintains a JSON state file (SentNotifications.json by default) that tracks which SamAccountName + AccountExpirationDate combinations have already been notified. This prevents duplicate notifications. A unique key is formed from the account name and expiration date, so the same user with a changed expiration date will still receive a new notification.

Usage

# Send with defaults (30 days, port 25, no SSL); sender taken from saved credential
.\Get-ExpiringADAccounts.ps1 -SmtpServer "smtp.example.com" -Recipient "tickets@example.com"

# Explicit sender address
.\Get-ExpiringADAccounts.ps1 -SmtpServer "smtp.example.com" -Sender "ad-alerts@example.com" -Recipient "tickets@example.com"

# 60-day window with SSL on port 587
.\Get-ExpiringADAccounts.ps1 -SmtpServer "smtp.example.com" -SmtpPort 587 -Recipient "tickets@example.com" -UseSsl -DaysUntilExpiration 60

# Custom credential and state file locations
.\Get-ExpiringADAccounts.ps1 -SmtpServer "smtp.example.com" -Recipient "tickets@example.com" `
    -CredentialFilePath "C:\Secure\smtp-credential.xml" `
    -StateFilePath "C:\State\SentNotifications.json"

# Verbose output with progress details
.\Get-ExpiringADAccounts.ps1 -SmtpServer "smtp.example.com" -Recipient "tickets@example.com" -Verbose

Output summary

After processing, the script prints a summary to the console:

========================================
 Notification Summary
========================================
 Window          : Today to +30 days
 Total found     : 12
 Notified        : 8
 Already sent    : 4
 State file      : C:\Dev\Powershell\AD-expiring-accounts\SentNotifications.json
========================================

Install-ScheduledTask.ps1

Registers (or removes) a Windows Scheduled Task that runs Get-ExpiringADAccounts.ps1 on a recurring schedule. Must be run as Administrator.

The task does not pass a credential path; the main script falls back to its default smtp-credential.xml next to the script. Make sure the credential file is saved by the same account the task runs as (see Save-SmtpCredential.ps1).

Parameters

Parameter Type Default Description
-Action string Install Install or Uninstall
-ScriptPath string (same folder) Path to Get-ExpiringADAccounts.ps1. Defaults to same directory as installer
-DaysUntilExpiration int 30 Days window passed to the main script
-SmtpServer string (required) SMTP server hostname or IP
-SmtpPort int 25 SMTP server port
-Sender string (optional) Sender email address (falls back to credential username if omitted)
-Recipient string (required) Recipient email address
-UseSsl switch — Enable SSL for SMTP connection
-TaskName string AD-ExpiringAccounts Name of the Scheduled Task
-TaskDescription string (auto) Description shown in Task Scheduler
-RunAsUser string SYSTEM Account to run the task as. Use SYSTEM or DOMAIN\ServiceAccount
-RunAsPassword string Password for -RunAsUser (not required for SYSTEM)
-TriggerTime string 07:00 Daily run time in HH:mm format
-TriggerDaysInterval int 1 Run every N days

Usage

# Install with required SMTP params
.\Install-ScheduledTask.ps1 -Action Install -SmtpServer "smtp.example.com" -Recipient "tickets@example.com"

# Install with SSL, custom schedule, and service account
.\Install-ScheduledTask.ps1 -Action Install `
    -SmtpServer "smtp.example.com" `
    -SmtpPort 587 `
    -Sender "ad-alerts@example.com" `
    -Recipient "tickets@example.com" `
    -UseSsl `
    -RunAsUser "DOMAIN\svc_reports" `
    -RunAsPassword "P@ssw0rd!" `
    -TriggerTime "06:30" `
    -DaysUntilExpiration 60

# Preview without making changes
.\Install-ScheduledTask.ps1 -Action Install -SmtpServer "smtp.example.com" -Recipient "tickets@example.com" -WhatIf

# Run the task immediately after installing
Start-ScheduledTask -TaskName "AD-ExpiringAccounts"

# Uninstall the task
.\Install-ScheduledTask.ps1 -Action Uninstall

# Uninstall a custom-named task
.\Install-ScheduledTask.ps1 -Action Uninstall -TaskName "MyCustomTaskName"

Task settings

The registered task is configured with:

  • Execution time limit: 1 hour
  • Multiple instances: Ignore new (prevents overlap)
  • Start when available: Yes (catches up if the machine was off at trigger time)
  • Run only if network available: Yes
  • Run level: Highest (elevated)

Notes

  • The LDAP query runs against the domain controller directly using file-time integer comparisons, so only matching accounts are transferred — no full user enumeration.
  • Exports use UTF-8 encoding.
  • The state file is created automatically if it does not exist.
  • The credential file is per-user and per-machine (DPAPI); recreate it if you change the account or move machines.
  • Get built-in help with Get-Help .\Get-ExpiringADAccounts.ps1 -Full.

About

PowerShell scripts that send individual email notifications for Active Directory user accounts with an approaching account expiration date. Includes an encrypted SMTP credential helper and a Scheduled Task installer for automated recurring execution.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages