In this post lets look to automate the monitoring of Proofpoint Email Protection queues, I initially underestimated how many hurdles existed with Selenium and Edge automation in PowerShell — particularly on Windows Server. What started as a simple “check and alert” script quickly evolved into a more complex exercise in browser automation reliability, driver management, and version alignment.
This post documents the full working setup — from Selenium configuration to professional email notifications — so the process can be replicated without the same level of frustration.
This post can be adapted to check any website, but in this example we are scraping the queue management in Proofpoint.
Environment and Requirements
You need to use PowerShell 7.5.3 rather than Windows PowerShell 5.1, because Selenium 4 and modern Edge automation simply do not work consistently under the legacy environment.
The prerequisites are:
- PowerShell 7.5.3 or later
- Microsoft Edge (Chromium-based) installed
- Matching Edge WebDriver version
- Internet access to download the Selenium .NET assemblies
Note : All operations are performed in pwsh.exe not powershell.exe
Download and Install WebDriver
I would recommend that you download and install the WebDriver.exe from the site here
When the driver has been downloaded extract it to the location C:\WebDriver which should look like this:
If you then look at the properties of that file you need to ensure this matches the version of Edge you have installed correctly for this to work as below, if you need to check the version of Edge you type edge://settings/help in the address bar.
Aligning Edge WebDriver
Selenium can throw a “session not created” error because the Edge WebDriver version didn’t match the installed Edge version.
To fix that, I added an automatic version alignment function to the setup script. This checks the local Edge version and compares it to the driver version, downloading a matching build if required.
function Get-EdgeVersion {
$edgePath = "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"
if (Test-Path $edgePath) {
(Get-Item $edgePath).VersionInfo.ProductVersion.Split('.')[0]
} else {
throw "Microsoft Edge not found at $edgePath"
}
}
function Get-EdgeDriverVersion {
param($DriverPath)
if (Test-Path $DriverPath) {
& $DriverPath --version | Select-String -Pattern "ChromeDriver ([\d\.]+)" | ForEach-Object { $_.Matches.Groups[1].Value.Split('.')[0] }
} else {
throw "EdgeDriver not found at $DriverPath"
}
}
$driverPath = "C:\WebDriver\msedgedriver.exe"
$browserVersion = Get-EdgeVersion
$driverVersion = Get-EdgeDriverVersion -DriverPath $driverPath
if ($browserVersion -ne $driverVersion) {
Write-Host "Version mismatch detected. Downloading correct EdgeDriver..."
$url = "https://msedgedriver.azureedge.net/$browserVersion.0/edgedriver_win64.zip"
$temp = "$env:TEMP\edgedriver.zip"
Invoke-WebRequest -Uri $url -OutFile $temp -UseBasicParsing
Expand-Archive -Path $temp -DestinationPath "C:\WebDriver" -Force
Remove-Item $temp
}
This ensures compatibility between the browser and driver — the single most common failure point with Selenium.
Setting Up Selenium 4 in PowerShell
Next, I needed a modern Selenium assembly. PowerShell 7 can load the .NET DLLs directly without an imported module.
The script automatically downloads and extracts the required libraries from the NuGet package:
$seleniumPath = "C:\ProgramData\ProofpointMonitor\Selenium"
$nugetUrl = "https://www.nuget.org/api/v2/package/Selenium.WebDriver"
$packageFile = "$env:TEMP\Selenium.WebDriver.zip"
if (-not (Test-Path $seleniumPath)) { New-Item -ItemType Directory -Path $seleniumPath -Force | Out-Null }
if (-not (Test-Path "$seleniumPath\WebDriver.dll")) {
Write-Host "Downloading Selenium.WebDriver..."
Invoke-WebRequest -Uri $nugetUrl -OutFile $packageFile -UseBasicParsing
Expand-Archive -Path $packageFile -DestinationPath $seleniumPath -Force
Copy-Item -Path (Get-ChildItem -Path $seleniumPath -Recurse -Filter "WebDriver.dll" | Select-Object -First 1).FullName `
-Destination "$seleniumPath\WebDriver.dll" -Force
}
Add-Type -Path "$seleniumPath\WebDriver.dll"
This avoids any need for manual extraction or dependency management.
Launching Edge in Headless Mode
To support automation on both Windows 11 and Windows Server, you need to configure EdgeOptions to run headless and suppress pop-ups, infobars, and extensions:
$options = New-Object OpenQA.Selenium.Edge.EdgeOptions
$options.AddArgument("--headless")
$options.AddArgument("--no-sandbox")
$options.AddArgument("--disable-dev-shm-usage")
$options.AddArgument("--disable-extensions")
$options.AddArgument("--disable-popup-blocking")
$options.AddArgument("--window-size=1920,1080")
$edgeService = [OpenQA.Selenium.Edge.EdgeDriverService]::CreateDefaultService("C:\WebDriver")
$edgeService.LogPath = "C:\ProgramData\ProofpointMonitor\msedgedriver.log"
$driver = New-Object OpenQA.Selenium.Edge.EdgeDriver($edgeService, $options)
$driver.Manage().Timeouts().ImplicitWait = [TimeSpan]::FromSeconds(15)
I can comment out the --headless argument when debugging to see browser activity.
Navigating to Proofpoint and Extracting Data
The automation process begins by visiting the Proofpoint Email Protection console and checking for a login field.
$driver.Navigate().GoToUrl("https://admin.proofpoint.com/auth")
try {
$emailFields = $driver.FindElements([OpenQA.Selenium.By]::XPath("//input[@name='email']"))
if ($emailFields.Count -gt 0) {
$emailFields[0].SendKeys("broken.hanger@bythepowerofgreyskull.com")
}
} catch {
Write-Warning "Login field not found or page structure changed."
}
Once authenticated (either automatically or interactively), the script searches for queue names and their numeric values:
$attachmentValue = ($driver.FindElement([OpenQA.Selenium.By]::XPath("//div[text()='Attachment Defense Timeout']/following::a[1]")).Text) -as [int]
$messageValue = ($driver.FindElement([OpenQA.Selenium.By]::XPath("//div[text()='Message Defense Timeout']/following::a[1]")).Text) -as [int]
Conditional Alerting and HTML Email
If both queues are zero, the script exits silently. Otherwise, it generates and sends a professional, minimalist HTML notification.
if ($attachmentValue -gt 0 -or $messageValue -gt 0) {
$htmlBody = @"
<html>
<body style="font-family:Segoe UI, Arial; background-color:#f5f6f7; padding:20px;">
<div style="max-width:450px; margin:auto; background:white; border-radius:10px; box-shadow:0 0 8px rgba(0,0,0,0.1); padding:20px;">
<h3 style="color:#24292e; text-align:center;">Proofpoint Queue Status</h3>
<div style="margin-top:20px;">
<p><strong>Attachment Defense Timeout:</strong> <span style="color:#0078D7;">$attachmentValue</span></p>
<p><strong>Message Defense Timeout:</strong> <span style="color:#0078D7;">$messageValue</span></p>
</div>
<p style="text-align:center; color:#666; font-size:12px; margin-top:20px;">This is an automated notification from the Proofpoint monitoring script.</p>
</div>
</body>
</html>
"@
Send-MailMessage -To "broken.hanger@bythepowerofgreyskull.com" -From "proofpoint-monitor@bythepowerofgreyskull.com" `
-Subject "Proofpoint Queue Alert" -BodyAsHtml -Body $htmlBody `
-SmtpServer "smtp.bear.local" -Port 25
}
The layout is mobile-friendly and renders cleanly in Outlook, Gmail, and iOS Mail.
Cleaning up Sessions
Selenium can leave processes running if a session crashes to prevent this lets explicitly shut down both the driver and its service at the end:
$driver.Quit()
$edgeService.Dispose()
Troubleshooting Notes
- Session errors → Always confirm the Edge and driver versions match.
- Missing DLLs → Ensure WebDriver.dll exists in your
$seleniumPath. - Blank values → Proofpoint UI structure may change; recheck your XPath queries.
- Email not received → Confirm your relay allows unauthenticated SMTP submissions.
This is the workflow of the script:
- Checks and downloads matching EdgeDriver
- Installs Selenium libraries automatically
- Launches Edge in headless mode
- Reads Proofpoint queue metrics
- Sends a formatted email only when values are greater than zero
The script can be initialised with this command:
.\ProofpointMonitor.ps1 -ProofpointUrl "https://admin.proofpoint.com/auth" -SmtpServer smtp.bear.local
Script : ProofpointMonitor.ps1
# =============================
# Proofpoint Queue Monitor Script
# =============================
# Paths
$edgeDriverFolder = "C:\WebDriver"
$msedgedriverExe = Join-Path $edgeDriverFolder "msedgedriver.exe"
$webDriverDll = "C:\ProgramData\ProofpointMonitor\Selenium\WebDriver.dll"
# SMTP Settings
$smtpServer = "mail.bear.local"
$from = "proofpoint.queue@bythepowerofgreyskull.com"
$to = "broken.hanger@bythepowerofgreyskull.com"
$subject = "Proofpoint Queue Notification"
# Proofpoint URL
$proofpointUrl = "https://admin.proofpoint.com/auth"
# =============================
# Validate files
# =============================
if (-not (Test-Path $msedgedriverExe)) {
throw "EdgeDriver not found at $msedgedriverExe"
}
if (-not (Test-Path $webDriverDll)) {
throw "WebDriver.dll not found at $webDriverDll"
}
# Load Selenium DLL
Add-Type -Path $webDriverDll
# =============================
# Start EdgeDriver
# =============================
Write-Host "[INFO] Starting EdgeDriver..."
$edgeService = [OpenQA.Selenium.Edge.EdgeDriverService]::CreateDefaultService($edgeDriverFolder)
$edgeOptions = New-Object OpenQA.Selenium.Edge.EdgeOptions
$edgeOptions.AddArgument("--headless")
$driver = New-Object OpenQA.Selenium.Edge.EdgeDriver($edgeService, $edgeOptions)
try {
# Navigate to Proofpoint
Write-Host "[INFO] Navigating to $proofpointUrl ..."
$driver.Navigate().GoToUrl($proofpointUrl)
Start-Sleep -Seconds 5
# Check for login email input
Write-Host "[INFO] Checking for login email input..."
$emailFields = $driver.FindElements([OpenQA.Selenium.By]::XPath("//input[@name='email']"))
if ($emailFields.Count -gt 0) {
$emailFields[0].SendKeys("broken.hanger@bythepowerofgreyskull.com")
$emailFields[0].SendKeys([OpenQA.Selenium.Keys]::Enter)
Start-Sleep -Seconds 8
Write-Host "[INFO] Login email entered."
} else {
Write-Host "[INFO] No login email input found; continuing."
}
# =============================
# Scrape queue values
# =============================
$attachmentValue = 0
$messageValue = 0
$attachmentElement = $driver.FindElements([OpenQA.Selenium.By]::XPath("//div[text()='Attachment Defense Timeout']"))
if ($attachmentElement.Count -gt 0) {
$attachmentValueElement = $attachmentElement[0].FindElement([OpenQA.Selenium.By]::XPath("following::a[1]"))
$attachmentValue = [int]$attachmentValueElement.Text
}
$messageElement = $driver.FindElements([OpenQA.Selenium.By]::XPath("//div[text()='Message Defense Timeout']"))
if ($messageElement.Count -gt 0) {
$messageValueElement = $messageElement[0].FindElement([OpenQA.Selenium.By]::XPath("following::a[1]"))
$messageValue = [int]$messageValueElement.Text
}
Write-Host "[INFO] Attachment Defense Timeout: $attachmentValue"
Write-Host "[INFO] Message Defense Timeout: $messageValue"
# =============================
# Send email if values > 0
# =============================
if ($attachmentValue -gt 0 -or $messageValue -gt 0) {
$body = @"
Proofpoint Queue Summary:
Attachment Defense Timeout: $attachmentValue
Message Defense Timeout: $messageValue
"@
Send-MailMessage -From $from -To $to -Subject $subject -Body $body -SmtpServer $smtpServer
Write-Host "[INFO] Notification sent."
} else {
Write-Host "[INFO] No queues with non-zero values; email not sent."
}
} catch {
Write-Host "[ERROR] Exception: $_"
} finally {
Write-Host "[INFO] Shutting down EdgeDriver..."
if ($driver) { $driver.Quit() }
Write-Host "[INFO] Finished."
}
Script Execution
This is what the script should do when it executes correctly, in this example the queues are empty:
What happens when the queues rise?
Well good questions, when the queues do actually rise based on the selenium script, you will get a colour coded system, of if the queues are queuing messages lets look at the different status notification you can get to your inbox:
First, lets start with Critial:
Then you have your normal e-mail which will not actually we send if both queues are zero but its more for illustrative purposes:
What initially appeared to be a straightforward Selenium automation turned out to be an exercise in dependency control. PowerShell 7, Selenium 4, and EdgeDriver must all be perfectly aligned — once they are, the rest of the workflow runs reliably.
The result is a minimalistic, fully self-contained Proofpoint monitor that integrates seamlessly into a Windows environment and alerts only when action is required.