PowerShell Certificates
Certificate management for enterprise 802.1X. Machine and user certificate stores, EAP-TEAP validation, AD CS auto-enrollment, WLAN profile certificate extraction, and event log troubleshooting — the commands you need when a workstation fails authentication against ISE/RADIUS.
|
Certificate Stores You’ll Touch Daily
|
Certificates Quick Reference
Machine Certificates (802.1X Machine Auth)
List all machine certs with expiry countdown
Get-ChildItem Cert:\LocalMachine\My |
Select-Object Subject, Issuer, NotAfter,
@{N='DaysLeft';E={($_.NotAfter - (Get-Date)).Days}},
Thumbprint | Sort-Object NotAfter | Format-Table
Find the machine cert used for 802.1X (Client Authentication EKU)
Get-ChildItem Cert:\LocalMachine\My | Where-Object {
$_.EnhancedKeyUsageList.FriendlyName -contains "Client Authentication"
} | Select-Object Subject, Issuer, NotAfter, Thumbprint
Find certs by issuing CA
Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Issuer -match "CHLASUBCA" } |
Format-List Subject, Issuer, NotBefore, NotAfter, Thumbprint, EnhancedKeyUsageList
Identify Intune MDM vs AD CS vs Entra certs
Get-ChildItem Cert:\LocalMachine\My | ForEach-Object {
$source = switch -Regex ($_.Issuer) {
'CHLASUBCA' { 'AD CS (Enterprise)' }
'Microsoft Intune' { 'Intune MDM' }
'MS-Organization-Access' { 'Entra ID (AAD)' }
'Device Management' { 'Intune Device' }
default { 'Other' }
}
[PSCustomObject]@{
Source = $source
Subject = $_.Subject.Substring(0, [Math]::Min(60, $_.Subject.Length))
Expires = $_.NotAfter
EKU = ($_.EnhancedKeyUsageList.FriendlyName -join ', ')
}
} | Sort-Object Source | Format-Table -AutoSize
Expiry Monitoring
Certs expiring within 30 days (alert threshold)
$threshold = (Get-Date).AddDays(30)
Get-ChildItem Cert:\LocalMachine\My |
Where-Object { $_.NotAfter -lt $threshold -and $_.NotAfter -gt (Get-Date) } |
Select-Object Subject, NotAfter, @{N='DaysLeft';E={($_.NotAfter - (Get-Date)).Days}}
Already expired certs (both stores)
'LocalMachine','CurrentUser' | ForEach-Object {
Get-ChildItem "Cert:\$_\My" | Where-Object { $_.NotAfter -lt (Get-Date) } |
Select-Object @{N='Store';E={$_}}, Subject, NotAfter
} | Format-Table
Certificate Details
Full cert inspection (by subject match)
Get-ChildItem Cert:\LocalMachine\My | Where-Object Subject -like "*chla*" |
Format-List Subject, Issuer, NotBefore, NotAfter, Thumbprint,
HasPrivateKey, EnhancedKeyUsageList, SerialNumber
Check certificate template (AD CS)
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Issuer -match "CHLASUBCA" } | Select-Object -First 1
$templateExt = $cert.Extensions | Where-Object { $_.Oid.Value -eq "1.3.6.1.4.1.311.21.7" }
if ($templateExt) { $templateExt.Format($true) }
Validate certificate chain (is the full chain trusted?)
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Issuer -match "CHLASUBCA" } | Select-Object -First 1
$chain = New-Object Security.Cryptography.X509Certificates.X509Chain
$valid = $chain.Build($cert)
Write-Host "Chain valid: $valid"
if (-not $valid) { $chain.ChainStatus | ForEach-Object { Write-Host " Error: $($_.Status)" -ForegroundColor Red } }
Check private key exists (required for EAP-TLS)
Get-ChildItem Cert:\LocalMachine\My | Where-Object {
$_.EnhancedKeyUsageList.FriendlyName -contains "Client Authentication"
} | Select-Object Subject, HasPrivateKey, NotAfter
If HasPrivateKey is $false, 802.1X authentication will fail even if the certificate is otherwise valid. The private key is needed to prove identity during the TLS handshake.
|
Trust Chain
Trusted Root CAs (is your enterprise root CA here?)
Get-ChildItem Cert:\LocalMachine\Root | Where-Object { $_.Subject -match "CHLA" } |
Select-Object Subject, Thumbprint, NotAfter
Intermediate CAs (is your subordinate CA here?)
Get-ChildItem Cert:\LocalMachine\CA | Where-Object { $_.Subject -match "CHLA" } |
Select-Object Subject, Thumbprint, NotAfter
EAP-TEAP WiFi Profile Inspection
Inspect enterprise WiFi profile (802.1X settings)
netsh wlan show profile name="CHLA_Staff" (1)
netsh wlan show profile name="CHLA-Remote" (2)
| 1 | Look for: Authentication=WPA2-Enterprise, EAP type=TEAP, 802.1X=Enabled |
| 2 | Check Cache user information — No means re-auth every connect |
Extract EAP-TEAP config from exported WLAN profile XML
netsh wlan export profile name="CHLA_Staff" folder="$env:TEMP" key=clear
[xml]$profile = Get-Content "$env:TEMP\Wi-Fi-CHLA_Staff.xml"
$profile.WLANProfile.MSM.security.OneX.EAPConfig.OuterXml
Inspect wired 802.1X profile
netsh lan show profiles interface="Ethernet"
netsh lan export profile folder="$env:TEMP" interface="Ethernet"
Enrollment and Renewal
Trigger machine cert auto-enrollment (AD CS)
certutil -pulse (1)
gpupdate /force (2)
| 1 | Triggers certificate auto-enrollment cycle immediately |
| 2 | Forces Group Policy refresh which also triggers auto-enrollment |
Request cert from specific template
certreq -enroll -q "Workstation Authentication"
Check CA availability
certutil -config - -ping
Event Viewer — 802.1X Troubleshooting
WiFi 802.1X authentication events
Get-WinEvent -LogName "Microsoft-Windows-WLAN-AutoConfig/Operational" -MaxEvents 30 |
Where-Object { $_.Message -match "802.1X|EAP|TEAP|authentication|fail|success" } |
Select-Object TimeCreated, Id, LevelDisplayName,
@{N='Summary';E={$_.Message.Split("`n")[0]}} | Format-Table -Wrap
Wired 802.1X authentication events
Get-WinEvent -LogName "Microsoft-Windows-Wired-AutoConfig/Operational" -MaxEvents 30 |
Select-Object TimeCreated, Id, LevelDisplayName,
@{N='Summary';E={$_.Message.Split("`n")[0]}} | Format-Table -Wrap
SCHANNEL errors (TLS handshake failures)
Get-WinEvent -LogName "System" -MaxEvents 100 |
Where-Object { $_.ProviderName -eq "Schannel" } |
Select-Object TimeCreated, LevelDisplayName,
@{N='Summary';E={$_.Message.Split("`n")[0]}} | Format-Table -Wrap
Enable and read CAPI2 logging (certificate chain validation)
# Enable (one-time, Admin):
wevtutil set-log Microsoft-Windows-CAPI2/Operational /enabled:true
# Read:
Get-WinEvent -LogName "Microsoft-Windows-CAPI2/Operational" -MaxEvents 20 |
Select-Object TimeCreated, @{N='Summary';E={$_.Message.Split("`n")[0]}}
Export / Import
Export cert (no private key — for sharing with ISE admin)
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Issuer -match "CHLASUBCA" } | Select-Object -First 1
Export-Certificate -Cert $cert -FilePath "$env:TEMP\machine-cert.cer"
Export with private key (PFX — for migration, Admin)
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Issuer -match "CHLASUBCA" } | Select-Object -First 1
$password = ConvertTo-SecureString -String "ExportP@ss!" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath "$env:TEMP\machine-cert.pfx" -Password $password
Import certificate to trusted root
Import-Certificate -FilePath "C:\certs\enterprise-root-ca.cer" -CertStoreLocation Cert:\LocalMachine\Root
certutil Quick Reference
certutil commands for field work
certutil -store My (1)
certutil -store My "THUMBPRINT" (2)
certutil -verify "C:\certs\cert.cer" (3)
certutil -dump "C:\certs\cert.cer" (4)
certutil -pulse (5)
certutil -config - -ping (6)
certutil -CATemplates (7)
certutil -viewstore "REQUEST" (8)
certutil -repairstore My "THUMBPRINT" (9)
| 1 | List all certs in Personal store with full details |
| 2 | View specific cert by thumbprint |
| 3 | Verify cert file against chain |
| 4 | Dump raw cert contents (ASN.1) |
| 5 | Trigger auto-enrollment |
| 6 | Ping enterprise CA (check availability) |
| 7 | List available certificate templates |
| 8 | Check pending cert requests |
| 9 | Repair private key permissions (Admin) |
Machine Certificates (LocalMachine Store)
List all machine certificates (Personal store)
Get-ChildItem Cert:\LocalMachine\My | Select-Object Thumbprint, Subject, NotAfter, Issuer
List machine certs with expiration status
Get-ChildItem Cert:\LocalMachine\My | Select-Object Subject, NotAfter,
@{N='DaysLeft';E={($_.NotAfter - (Get-Date)).Days}},
@{N='Status';E={if($_.NotAfter -lt (Get-Date)){'EXPIRED'}elseif(($_.NotAfter - (Get-Date)).Days -lt 30){'EXPIRING'}else{'OK'}}}
Find machine cert by subject (hostname)
Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Subject -match $env:COMPUTERNAME }
Find machine cert by thumbprint
Get-ChildItem Cert:\LocalMachine\My | Where-Object Thumbprint -eq "ABC123..."
Find machine certs issued by specific CA
Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Issuer -match "Enterprise-CA" }
Find machine certs with Client Authentication EKU (for EAP-TLS)
Get-ChildItem Cert:\LocalMachine\My | Where-Object {
$_.EnhancedKeyUsageList.FriendlyName -contains "Client Authentication"
} | Select-Object Subject, Thumbprint, NotAfter
Get machine cert details (full)
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Subject -match $env:COMPUTERNAME } | Select-Object -First 1
$cert | Format-List *
Check machine cert chain validity
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Subject -match $env:COMPUTERNAME } | Select-Object -First 1
$chain = New-Object Security.Cryptography.X509Certificates.X509Chain
$chain.Build($cert)
$chain.ChainStatus | Select-Object Status, StatusInformation
Check machine cert private key exists
Get-ChildItem Cert:\LocalMachine\My | Select-Object Subject, HasPrivateKey, NotAfter |
Where-Object { $_.Subject -match $env:COMPUTERNAME }
List Trusted Root CAs (machine)
Get-ChildItem Cert:\LocalMachine\Root | Select-Object Subject, Thumbprint, NotAfter | Sort-Object Subject
List Intermediate CAs (machine)
Get-ChildItem Cert:\LocalMachine\CA | Select-Object Subject, Thumbprint, NotAfter | Sort-Object Subject
Find specific Root CA
Get-ChildItem Cert:\LocalMachine\Root | Where-Object { $_.Subject -match "Enterprise-Root-CA" }
Export machine cert to file (no private key)
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Subject -match $env:COMPUTERNAME } | Select-Object -First 1
Export-Certificate -Cert $cert -FilePath "$env:TEMP\machine-cert.cer"
Export machine cert with private key (PFX) - requires admin
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Subject -match $env:COMPUTERNAME } | Select-Object -First 1
$password = ConvertTo-SecureString -String "ExportP@ss!" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath "$env:TEMP\machine-cert.pfx" -Password $password
Import certificate to machine store (Admin)
Import-Certificate -FilePath "C:\Certs\ca-root.cer" -CertStoreLocation Cert:\LocalMachine\Root
Import PFX to machine store (Admin)
$password = ConvertTo-SecureString -String "ImportP@ss!" -Force -AsPlainText
Import-PfxCertificate -FilePath "C:\Certs\machine.pfx" -CertStoreLocation Cert:\LocalMachine\My -Password $password
Delete machine certificate (Admin)
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object Thumbprint -eq "ABC123..."
Remove-Item $cert.PSPath
User Certificates (CurrentUser Store)
List all user certificates (Personal store)
Get-ChildItem Cert:\CurrentUser\My | Select-Object Thumbprint, Subject, NotAfter, Issuer
List user certs with expiration status
Get-ChildItem Cert:\CurrentUser\My | Select-Object Subject, NotAfter,
@{N='DaysLeft';E={($_.NotAfter - (Get-Date)).Days}},
@{N='Status';E={if($_.NotAfter -lt (Get-Date)){'EXPIRED'}elseif(($_.NotAfter - (Get-Date)).Days -lt 30){'EXPIRING'}else{'OK'}}}
Find user cert by UPN/email
Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.Subject -match $env:USERNAME }
Find user certs with Client Authentication EKU
Get-ChildItem Cert:\CurrentUser\My | Where-Object {
$_.EnhancedKeyUsageList.FriendlyName -contains "Client Authentication"
} | Select-Object Subject, Thumbprint, NotAfter
Find user certs with Smart Card Logon EKU
Get-ChildItem Cert:\CurrentUser\My | Where-Object {
$_.EnhancedKeyUsageList.FriendlyName -contains "Smart Card Logon"
} | Select-Object Subject, Thumbprint, NotAfter
Get user cert SAN (Subject Alternative Name)
$cert = Get-ChildItem Cert:\CurrentUser\My | Select-Object -First 1
$san = $cert.Extensions | Where-Object { $_.Oid.FriendlyName -eq "Subject Alternative Name" }
$san.Format($true)
Check user cert chain validity
$cert = Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.Subject -match $env:USERNAME } | Select-Object -First 1
$chain = New-Object Security.Cryptography.X509Certificates.X509Chain
$chain.Build($cert)
$chain.ChainStatus | Select-Object Status, StatusInformation
Check user cert private key exists
Get-ChildItem Cert:\CurrentUser\My | Select-Object Subject, HasPrivateKey, NotAfter
List Trusted Root CAs (user store)
Get-ChildItem Cert:\CurrentUser\Root | Select-Object Subject, Thumbprint | Sort-Object Subject
Export user cert to file (no private key)
$cert = Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.Subject -match $env:USERNAME } | Select-Object -First 1
Export-Certificate -Cert $cert -FilePath "$env:TEMP\user-cert.cer"
Export user cert with private key (PFX)
$cert = Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.Subject -match $env:USERNAME } | Select-Object -First 1
$password = ConvertTo-SecureString -String "ExportP@ss!" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath "$env:TEMP\user-cert.pfx" -Password $password
Import certificate to user store
Import-Certificate -FilePath "C:\Certs\ca-root.cer" -CertStoreLocation Cert:\CurrentUser\Root
Import PFX to user store
$password = ConvertTo-SecureString -String "ImportP@ss!" -Force -AsPlainText
Import-PfxCertificate -FilePath "C:\Certs\user.pfx" -CertStoreLocation Cert:\CurrentUser\My -Password $password
Delete user certificate
$cert = Get-ChildItem Cert:\CurrentUser\My | Where-Object Thumbprint -eq "ABC123..."
Remove-Item $cert.PSPath
802.1X / EAP-TEAP Certificate Validation
Validate machine cert for EAP-TLS (Client Auth EKU + valid chain)
$certs = Get-ChildItem Cert:\LocalMachine\My | Where-Object {
$_.EnhancedKeyUsageList.FriendlyName -contains "Client Authentication" -and
$_.NotAfter -gt (Get-Date) -and
$_.HasPrivateKey
}
foreach ($cert in $certs) {
$chain = New-Object Security.Cryptography.X509Certificates.X509Chain
$valid = $chain.Build($cert)
[PSCustomObject]@{
Subject = $cert.Subject
Thumbprint = $cert.Thumbprint
Expires = $cert.NotAfter
ChainValid = $valid
ChainErrors = ($chain.ChainStatus | ForEach-Object { $_.Status }) -join ","
}
}
Validate user cert for EAP-TLS
$certs = Get-ChildItem Cert:\CurrentUser\My | Where-Object {
$_.EnhancedKeyUsageList.FriendlyName -contains "Client Authentication" -and
$_.NotAfter -gt (Get-Date) -and
$_.HasPrivateKey
}
foreach ($cert in $certs) {
$chain = New-Object Security.Cryptography.X509Certificates.X509Chain
$valid = $chain.Build($cert)
[PSCustomObject]@{
Subject = $cert.Subject
Thumbprint = $cert.Thumbprint
Expires = $cert.NotAfter
ChainValid = $valid
}
}
Check if ISE/RADIUS server cert is trusted
$iseCA = "Enterprise-Root-CA" # Your ISE cert issuer
Get-ChildItem Cert:\LocalMachine\Root | Where-Object { $_.Subject -match $iseCA } |
Select-Object Subject, Thumbprint, NotAfter
Get certificate EKU OIDs
$cert = Get-ChildItem Cert:\LocalMachine\My | Select-Object -First 1
$cert.EnhancedKeyUsageList | Select-Object FriendlyName, ObjectId
# Client Auth: 1.3.6.1.5.5.7.3.2
# Server Auth: 1.3.6.1.5.5.7.3.1
# Smart Card Logon: 1.3.6.1.4.1.311.20.2.2
Check certificate template used
$cert = Get-ChildItem Cert:\LocalMachine\My | Select-Object -First 1
$templateExt = $cert.Extensions | Where-Object { $_.Oid.Value -eq "1.3.6.1.4.1.311.21.7" }
if ($templateExt) {
$templateExt.Format($true)
}
Full 802.1X machine cert diagnostic
Write-Host "=== Machine Certificates for 802.1X ===" -ForegroundColor Cyan
$certs = Get-ChildItem Cert:\LocalMachine\My | Where-Object {
$_.EnhancedKeyUsageList.FriendlyName -contains "Client Authentication"
}
if (-not $certs) {
Write-Host "ERROR: No Client Authentication certificates found!" -ForegroundColor Red
} else {
foreach ($cert in $certs) {
Write-Host "`nSubject: $($cert.Subject)" -ForegroundColor Yellow
Write-Host "Thumbprint: $($cert.Thumbprint)"
Write-Host "Issuer: $($cert.Issuer)"
Write-Host "Expires: $($cert.NotAfter) ($(($cert.NotAfter - (Get-Date)).Days) days)"
Write-Host "Has Private Key: $($cert.HasPrivateKey)"
$chain = New-Object Security.Cryptography.X509Certificates.X509Chain
$chainValid = $chain.Build($cert)
Write-Host "Chain Valid: $chainValid"
if (-not $chainValid) {
$chain.ChainStatus | ForEach-Object { Write-Host " Chain Error: $($_.Status)" -ForegroundColor Red }
}
}
}
Full 802.1X user cert diagnostic
Write-Host "=== User Certificates for 802.1X ===" -ForegroundColor Cyan
$certs = Get-ChildItem Cert:\CurrentUser\My | Where-Object {
$_.EnhancedKeyUsageList.FriendlyName -contains "Client Authentication"
}
if (-not $certs) {
Write-Host "ERROR: No Client Authentication certificates found!" -ForegroundColor Red
} else {
foreach ($cert in $certs) {
Write-Host "`nSubject: $($cert.Subject)" -ForegroundColor Yellow
Write-Host "Thumbprint: $($cert.Thumbprint)"
Write-Host "Issuer: $($cert.Issuer)"
Write-Host "Expires: $($cert.NotAfter) ($(($cert.NotAfter - (Get-Date)).Days) days)"
Write-Host "Has Private Key: $($cert.HasPrivateKey)"
$chain = New-Object Security.Cryptography.X509Certificates.X509Chain
$chainValid = $chain.Build($cert)
Write-Host "Chain Valid: $chainValid"
}
}
Certificate Enrollment (AD CS / Auto-Enrollment)
Check auto-enrollment status
gpresult /h "$env:TEMP\gpresult.html" /f
Start-Process "$env:TEMP\gpresult.html"
Trigger machine certificate auto-enrollment
certutil -pulse
Trigger user certificate auto-enrollment
certreq -enroll -q
Force Group Policy update (triggers auto-enrollment)
gpupdate /force
List available certificate templates
certutil -CATemplates
Request certificate from specific template (interactive)
certreq -enroll -q "Workstation Authentication"
Create CSR (Certificate Signing Request)
$inf = @"
[Version]
Signature = "`$Windows NT`$"
[NewRequest]
Subject = "CN=$env:COMPUTERNAME.$env:USERDNSDOMAIN"
KeySpec = 1
KeyLength = 2048
Exportable = TRUE
MachineKeySet = TRUE
SMIME = FALSE
PrivateKeyArchive = FALSE
UserProtected = FALSE
UseExistingKeySet = FALSE
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
ProviderType = 12
RequestType = PKCS10
KeyUsage = 0xa0
[EnhancedKeyUsageExtension]
OID = 1.3.6.1.5.5.7.3.2 ; Client Authentication
"@
$inf | Out-File "$env:TEMP\cert-request.inf"
certreq -new "$env:TEMP\cert-request.inf" "$env:TEMP\cert-request.csr"
Submit CSR to CA
certreq -submit -config "CA-SERVER\Enterprise-CA" "$env:TEMP\cert-request.csr" "$env:TEMP\cert-response.cer"
Install certificate response
certreq -accept "$env:TEMP\cert-response.cer"
Check pending certificate requests
certutil -viewstore "REQUEST"
WLAN Profile Certificate Configuration
Inspect Enterprise WiFi Profiles
View 802.1X WiFi profile — verify EAP-TEAP config
netsh wlan show profile name="CHLA_Staff" (1)
netsh wlan show profile name="CHLA-Remote" (2)
| 1 | Look for: Authentication: WPA2-Enterprise, EAP type: Microsoft: Tunnel EAP (TEAP), 802.1X: Enabled, 802.1X auth credential: Machine or user credential |
| 2 | Check Cache user information — CHLA-Remote has No, meaning fresh auth every connect |
Compare Group Policy vs User profiles
netsh wlan show profiles
# Group Policy profiles (read only) — pushed by GPO, can't delete locally
# User profiles — locally created, can export/delete
Export and Parse EAP-TEAP XML Config
Export enterprise profile to XML for analysis
netsh wlan export profile name="CHLA_Staff" folder="$env:TEMP" key=clear
Parse the OneX / EAP-TEAP configuration from exported XML
[xml]$profile = Get-Content "$env:TEMP\Wi-Fi-CHLA_Staff.xml"
# Authentication method
$auth = $profile.WLANProfile.MSM.security.authEncryption
Write-Host "Authentication: $($auth.authentication)"
Write-Host "Cipher: $($auth.encryption)"
Write-Host "Use 802.1X: $($auth.useOneX)"
# EAP config (TEAP Type=55, TLS Type=13, MSCHAPv2 Type=26)
$eapConfig = $profile.WLANProfile.MSM.security.OneX.EAPConfig
if ($eapConfig) {
Write-Host "`nEAP Configuration:"
$eapConfig.OuterXml
}
Check EAP method type in profile
[xml]$profile = Get-Content "$env:TEMP\Wi-Fi-CHLA_Staff.xml"
$eapType = $profile.WLANProfile.MSM.security.OneX.EAPConfig.EapHostConfig.EapMethod.Type.'#text'
$eapName = switch ($eapType) {
'13' { 'EAP-TLS (certificate only)' }
'21' { 'EAP-TTLS' }
'25' { 'PEAP' }
'26' { 'MSCHAPv2' }
'55' { 'EAP-TEAP (tunnel, multiple inner methods)' }
default { "Unknown ($eapType)" }
}
Write-Host "EAP Method: $eapName (Type $eapType)"
Wired 802.1X Profile Inspection
View and export wired 802.1X profile
netsh lan show profiles interface="Ethernet"
netsh lan export profile folder="$env:TEMP" interface="Ethernet"
Parse wired profile XML
$wiredProfiles = Get-ChildItem "$env:TEMP" -Filter "Ethernet*.xml"
if ($wiredProfiles) {
[xml]$wired = Get-Content $wiredProfiles[0].FullName
$wired.LANProfile.MSM.security | Format-List
}
Verify Cert Matches Profile Requirements
Check machine cert against EAP-TEAP requirements
Write-Host "=== EAP-TEAP requires ===" -ForegroundColor Cyan
Write-Host "1. Machine cert with Client Authentication EKU"
Write-Host "2. Issued by trusted CA (in Root/CA stores)"
Write-Host "3. Private key present"
Write-Host "4. Not expired"
Write-Host "5. Trust chain complete (Root CA → Sub CA → Machine cert)"
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object {
$_.EnhancedKeyUsageList.FriendlyName -contains "Client Authentication" -and
$_.HasPrivateKey -and
$_.NotAfter -gt (Get-Date)
} | Select-Object -First 1
if ($cert) {
Write-Host "`nCandidate cert found:" -ForegroundColor Green
Write-Host " Subject: $($cert.Subject)"
Write-Host " Issuer: $($cert.Issuer)"
Write-Host " Expires: $($cert.NotAfter) ($(($cert.NotAfter - (Get-Date)).Days) days)"
$chain = New-Object Security.Cryptography.X509Certificates.X509Chain
$valid = $chain.Build($cert)
Write-Host " Chain: $(if($valid){'VALID'}else{'BROKEN'})" -ForegroundColor $(if($valid){'Green'}else{'Red'})
} else {
Write-Host "`nNO VALID CERT FOUND — EAP-TEAP will fail" -ForegroundColor Red
Write-Host "Run: certutil -pulse (to trigger auto-enrollment)"
}
Certificate Troubleshooting
Open Certificate Manager (MMC snap-in)
certmgr.msc # User certs
certlm.msc # Machine certs (Admin)
Check certificate services status
certutil -ping
Check CA availability
certutil -config - -ping
View certificate in detail (by thumbprint)
certutil -store My "THUMBPRINT_HERE"
Verify certificate file
certutil -verify "C:\Certs\cert.cer"
Dump certificate file contents
certutil -dump "C:\Certs\cert.cer"
Check private key container
$cert = Get-ChildItem Cert:\LocalMachine\My | Select-Object -First 1
$cert.PrivateKey.CspKeyContainerInfo | Select-Object *
Repair private key permissions (Admin)
certutil -repairstore My "THUMBPRINT_HERE"
List all certificate stores
Get-ChildItem Cert:\LocalMachine
Get-ChildItem Cert:\CurrentUser
Find expired certificates (all stores)
Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.NotAfter -lt (Get-Date) } |
Select-Object Subject, NotAfter, Thumbprint
Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.NotAfter -lt (Get-Date) } |
Select-Object Subject, NotAfter, Thumbprint
Find certificates expiring in 30 days
$threshold = (Get-Date).AddDays(30)
Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.NotAfter -lt $threshold -and $_.NotAfter -gt (Get-Date) } |
Select-Object Subject, NotAfter, @{N='DaysLeft';E={($_.NotAfter - (Get-Date)).Days}}
Clear SSL state (helps with cert selection issues)
# Opens Internet Options, go to Content > Clear SSL State
rundll32.exe inetcpl.cpl,ClearMyTracksByProcess 32
Reset 802.1X authentication state
netsh lan reconnect interface="Ethernet"
netsh wlan reconnect interface="Wi-Fi"
Check SCHANNEL event logs (TLS handshake failures)
Get-WinEvent -LogName "System" -MaxEvents 100 |
Where-Object { $_.ProviderName -eq "Schannel" } |
Select-Object TimeCreated, LevelDisplayName,
@{N='Summary';E={$_.Message.Split("`n")[0]}} | Format-Table -Wrap
Check CAPI2 event logs (certificate chain validation)
# Enable CAPI2 logging first (one-time, Admin):
wevtutil set-log Microsoft-Windows-CAPI2/Operational /enabled:true
# Read certificate validation events:
Get-WinEvent -LogName "Microsoft-Windows-CAPI2/Operational" -MaxEvents 20 |
Select-Object TimeCreated, @{N='Summary';E={$_.Message.Split("`n")[0]}} |
Format-Table -Wrap
802.1X Authentication Event Logs
WiFi 802.1X events (EAP-TEAP authentication)
Get-WinEvent -LogName "Microsoft-Windows-WLAN-AutoConfig/Operational" -MaxEvents 50 |
Where-Object { $_.Id -in @(8001,8002,8003,11001,11002,11004,11010) } |
Select-Object TimeCreated, Id,
@{N='Event';E={switch($_.Id){8001{'Connected'}8002{'ConnFailed'}8003{'Disconnected'}11001{'AuthStarted'}11002{'AuthSuccess'}11004{'AuthFailed'}11010{'NotAvailable'}}}},
@{N='Summary';E={$_.Message.Split("`n")[0]}} | Format-Table -Wrap
Wired 802.1X events
Get-WinEvent -LogName "Microsoft-Windows-Wired-AutoConfig/Operational" -MaxEvents 50 |
Where-Object { $_.Id -in @(15500,15501,15503) } |
Select-Object TimeCreated, Id,
@{N='Event';E={switch($_.Id){15500{'AuthStarted'}15501{'AuthSuccess'}15503{'AuthFailed'}}}},
@{N='Summary';E={$_.Message.Split("`n")[0]}} | Format-Table -Wrap
Filter for failures only (last 24 hours)
$since = (Get-Date).AddHours(-24)
Get-WinEvent -LogName "Microsoft-Windows-WLAN-AutoConfig/Operational" |
Where-Object { $_.TimeCreated -gt $since -and $_.Id -in @(8002,11004) } |
Select-Object TimeCreated, Id, Message | Format-List
NPS/RADIUS events (if running NPS locally — rare on workstations)
Get-WinEvent -LogName "Security" -MaxEvents 100 |
Where-Object { $_.Id -in @(6272,6273,6274,6278) } |
Select-Object TimeCreated, Id,
@{N='Event';E={switch($_.Id){6272{'NPS Granted'}6273{'NPS Denied'}6274{'NPS Discarded'}6278{'NPS Extension DLL'}}}},
@{N='Summary';E={$_.Message.Split("`n")[0]}} | Format-Table -Wrap
Full 802.1X Diagnostic Script
One-shot diagnostic — run when a workstation can’t authenticate
Write-Host "`n=== dot3svc / Wlansvc Status ===" -ForegroundColor Cyan
Get-Service -Name dot3svc, Wlansvc | Select-Object Name, Status, StartType | Format-Table
Write-Host "=== Machine Cert (Client Auth EKU) ===" -ForegroundColor Cyan
$certs = Get-ChildItem Cert:\LocalMachine\My | Where-Object {
$_.EnhancedKeyUsageList.FriendlyName -contains "Client Authentication"
}
if (-not $certs) { Write-Host " NO CLIENT AUTH CERT FOUND" -ForegroundColor Red }
else {
$certs | ForEach-Object {
$chain = New-Object Security.Cryptography.X509Certificates.X509Chain
$valid = $chain.Build($_)
[PSCustomObject]@{
Subject = $_.Subject.Substring(0, [Math]::Min(50, $_.Subject.Length))
Issuer = $_.Issuer.Substring(0, [Math]::Min(40, $_.Issuer.Length))
Expires = $_.NotAfter
DaysLeft = ($_.NotAfter - (Get-Date)).Days
PrivateKey = $_.HasPrivateKey
ChainValid = $valid
}
} | Format-Table
}
Write-Host "=== Enterprise Root CA in Trust Store ===" -ForegroundColor Cyan
Get-ChildItem Cert:\LocalMachine\Root | Where-Object { $_.Subject -match "CHLA" } |
Select-Object Subject, NotAfter | Format-Table
Write-Host "=== Wired 802.1X Status ===" -ForegroundColor Cyan
netsh lan show interfaces
Write-Host "`n=== WiFi 802.1X Status ===" -ForegroundColor Cyan
netsh wlan show interfaces | Select-String -Pattern "State|SSID|Authentication|802.1X"
Write-Host "`n=== Recent Auth Failures (last 24h) ===" -ForegroundColor Cyan
$since = (Get-Date).AddHours(-24)
$failures = @()
try {
$failures += Get-WinEvent -LogName "Microsoft-Windows-WLAN-AutoConfig/Operational" -ErrorAction SilentlyContinue |
Where-Object { $_.TimeCreated -gt $since -and $_.Id -in @(8002,11004) }
} catch {}
try {
$failures += Get-WinEvent -LogName "Microsoft-Windows-Wired-AutoConfig/Operational" -ErrorAction SilentlyContinue |
Where-Object { $_.TimeCreated -gt $since -and $_.Id -eq 15503 }
} catch {}
if ($failures) {
$failures | Select-Object TimeCreated, Id, @{N='Summary';E={$_.Message.Split("`n")[0]}} | Format-Table -Wrap
} else { Write-Host " No auth failures in last 24 hours" -ForegroundColor Green }