#Requires -Version 5.1
<#
.SYNOPSIS
Automatyczny test wdrozenia certyfikatow i konfiguracji Wi-Fi/LAN (TEAP/802.1X).
Wersja NON-ADMIN v3.0
.NOTES
Wymagania: Windows 10/11, PowerShell 5.1+
#>
# ================================================================
# KONFIGURACJA
# ================================================================
$Config = @{
ExpectedSSID = "WIFI_USERS"
ComputerCertSubject = "LAP-"
UserCertSubject = ""
ExpectedIssuer = "InPost-SUB01-CA"
ExpectedRootCA = "INPOST-ROOT-CA"
ExpectedSubCA = "InPost-SUB01-CA"
MinValidDaysWarning = 30
MinValidDaysError = 7
ExpectedEAPType = 55 # 55=TEAP, 13=EAP-TLS, 25=PEAP
AcceptableEAPTypes = @(55, 13) # Typy EAP ktore sa akceptowalne (TEAP lub EAP-TLS jako outer)
ExportDir = "C:\Temp"
}
# ================================================================
$Results = [System.Collections.Generic.List[PSCustomObject]]::new()
$Passed = 0; $Failed = 0; $Warnings = 0
$LINE = "=" * 70
$LINE2 = "-" * 70
# ----------------------------------------------------------------
# Funkcje pomocnicze
# ----------------------------------------------------------------
function Write-Header {
param([string]$Text)
Write-Host "`n$LINE" -ForegroundColor Cyan
Write-Host " $Text" -ForegroundColor White
Write-Host $LINE -ForegroundColor Cyan
}
function Write-SubHeader {
param([string]$Text)
Write-Host "`n $LINE2" -ForegroundColor DarkCyan
Write-Host " >> $Text" -ForegroundColor DarkCyan
Write-Host " $LINE2" -ForegroundColor DarkCyan
}
function Add-Result {
param(
[string]$Category,
[string]$TestName,
[ValidateSet("PASS","FAIL","WARN","INFO","SKIP")]
[string]$Status,
[string]$Detail = ""
)
$color = switch ($Status) {
"PASS" { "Green" }
"FAIL" { "Red" }
"WARN" { "Yellow" }
"SKIP" { "Magenta" }
"INFO" { "Cyan" }
}
$icon = switch ($Status) {
"PASS" { "[ OK ]" }
"FAIL" { "[FAIL]" }
"WARN" { "[WARN]" }
"SKIP" { "[SKIP]" }
"INFO" { "[INFO]" }
}
Write-Host " $icon $TestName" -ForegroundColor $color
if ($Detail) { Write-Host " --> $Detail" -ForegroundColor DarkGray }
$script:Results.Add([PSCustomObject]@{
Nr = $script:Results.Count + 1
Kategoria = $Category
Test = $TestName
Status = $Status
Szczegoly = $Detail
Czas = (Get-Date -Format "yyyy-MM-dd HH:mm:ss")
})
switch ($Status) {
"PASS" { $script:Passed++ }
"FAIL" { $script:Failed++ }
"WARN" { $script:Warnings++ }
}
}
function Get-CertCN {
param($Subject)
if ($Subject -match "CN=([^,]+)") { return $Matches[1] } else { return $Subject }
}
function Get-EAPName {
param([int]$Type)
switch ($Type) { 55 {"TEAP"} 13 {"EAP-TLS"} 25 {"PEAP"} 21 {"TTLS"} default {"Typ $Type"} }
}
# ================================================================
# TEST 1: Certyfikat uzytkownika
# ================================================================
function Test-UserCertificate {
Write-Header "TEST 1: Certyfikat UZYTKOWNIKA [CurrentUser\My]"
$allCerts = Get-ChildItem "Cert:\CurrentUser\My" -ErrorAction SilentlyContinue
if ($null -eq $allCerts) { Add-Result "1-Cert-User" "Dostep do magazynu CurrentUser\My" "FAIL" "Nie mozna otworzyc magazynu certyfikatow."; return }
Add-Result "1-Cert-User" "Dostep do magazynu CurrentUser\My" "PASS" "Magazyn dostepny. Wszystkich certyfikatow: $($allCerts.Count)"
$certs = $allCerts | Where-Object { $_.Issuer -like "*$($Config.ExpectedIssuer)*" }
if ($Config.UserCertSubject) { $certs = $certs | Where-Object { $_.Subject -like "*$($Config.UserCertSubject)*" } }
if ($certs.Count -eq 0) {
Add-Result "1-Cert-User" "Certyfikat wystawiony przez $($Config.ExpectedIssuer)" "FAIL" "Brak certyfikatow uzytkownika wystawionych przez '$($Config.ExpectedIssuer)'."; return
}
Add-Result "1-Cert-User" "Certyfikaty wystawione przez $($Config.ExpectedIssuer)" "PASS" "Znaleziono: $($certs.Count) certyfikat(ow)"
$now = Get-Date; $i = 0
foreach ($cert in $certs) {
$i++
$daysLeft = ($cert.NotAfter - $now).Days
Write-SubHeader "Certyfikat uzytkownika #$i z $($certs.Count)"
Add-Result "1-Cert-User" "Subject (pelna nazwa)" "INFO" $cert.Subject
Add-Result "1-Cert-User" "Issuer (wystawca)" "INFO" $cert.Issuer
Add-Result "1-Cert-User" "Thumbprint" "INFO" $cert.Thumbprint
Add-Result "1-Cert-User" "Numer seryjny" "INFO" $cert.SerialNumber
Add-Result "1-Cert-User" "Wazny OD" "INFO" $cert.NotBefore.ToString('yyyy-MM-dd HH:mm')
Add-Result "1-Cert-User" "Wazny DO" "INFO" $cert.NotAfter.ToString('yyyy-MM-dd HH:mm')
$waznoscLabel = "Waznosc certyfikatu [$($cert.NotAfter.ToString('yyyy-MM-dd'))]"
if ($daysLeft -lt 0) { Add-Result "1-Cert-User" $waznoscLabel "FAIL" "WYGASL $([Math]::Abs($daysLeft)) dni temu!" } elseif ($daysLeft -lt $Config.MinValidDaysError) { Add-Result "1-Cert-User" $waznoscLabel "FAIL" "Wygasa za $daysLeft dni – krytyczne!" } elseif ($daysLeft -lt $Config.MinValidDaysWarning) { Add-Result "1-Cert-User" $waznoscLabel "WARN" "Wygasa za $daysLeft dni – ostrzezenie." } else { Add-Result "1-Cert-User" $waznoscLabel "PASS" "Pozostalo $daysLeft dni waznosci." }
$sanExt = $cert.Extensions | Where-Object { $_.Oid.FriendlyName -eq "Subject Alternative Name" }
if ($sanExt) { Add-Result "1-Cert-User" "Subject Alternative Names (SAN)" "INFO" $sanExt.Format($false) }
if ($cert.HasPrivateKey) { Add-Result "1-Cert-User" "Klucz prywatny" "PASS" "Dostepny – uwierzytelnienie 802.1X mozliwe." } else { Add-Result "1-Cert-User" "Klucz prywatny" "FAIL" "BRAK – uwierzytelnienie 802.1X NIEMOZLIWE!" }
$ekuExt = $cert.Extensions | Where-Object { $_.Oid.FriendlyName -eq "Enhanced Key Usage" }
if ($ekuExt) {
$ekuVal = $ekuExt.Format($false)
$hasClient = $ekuVal -match "1\.3\.6\.1\.5\.5\.7\.3\.2|Client Authentication"
Add-Result "1-Cert-User" "EKU – Client Authentication" $(if ($hasClient) {"PASS"} else {"FAIL"}) $(if ($hasClient) {"Client Authentication (1.3.6.1.5.5.7.3.2) – OK"} else {"BRAK EKU Client Authentication – certyfikat nie nadaje sie do 802.1X!"})
}
$chain = [System.Security.Cryptography.X509Certificates.X509Chain]::new()
$chain.ChainPolicy.RevocationMode = [System.Security.Cryptography.X509Certificates.X509RevocationMode]::NoCheck
if ($chain.Build($cert)) {
$chainPath = ($chain.ChainElements | ForEach-Object { Get-CertCN $_.Certificate.Subject }) -join " --> "
Add-Result "1-Cert-User" "Lancuch zaufania" "PASS" "Poprawny ($($chain.ChainElements.Count) elementow)"
Add-Result "1-Cert-User" "Sciezka certyfikatu" "INFO" $chainPath
} else {
$errs = ($chain.ChainStatus | ForEach-Object { $_.StatusInformation.Trim() }) -join "; "
Add-Result "1-Cert-User" "Lancuch zaufania" "WARN" "Problemy: $errs"
}
}
}
# ================================================================
# TEST 2: Certyfikat komputerowy
# ================================================================
function Test-ComputerCertificate {
Write-Header "TEST 2: Certyfikat KOMPUTEROWY [LocalMachine\My]"
Add-Result "2-Cert-Computer" "Klucze prywatne LocalMachine\My" "SKIP" "Weryfikacja kluczy prywatnych wymaga uprawnien administratora."
$allCerts = Get-ChildItem "Cert:\LocalMachine\My" -ErrorAction SilentlyContinue
if ($null -eq $allCerts) { Add-Result "2-Cert-Computer" "Dostep do magazynu LocalMachine\My" "WARN" "Brak dostepu – moze wymagac admina."; return }
Add-Result "2-Cert-Computer" "Dostep do magazynu LocalMachine\My" "PASS" "Magazyn dostepny. Wszystkich certyfikatow: $($allCerts.Count)"
$certs = $allCerts | Where-Object { $_.Issuer -like "*$($Config.ExpectedIssuer)*" }
if ($Config.ComputerCertSubject) { $certs = $certs | Where-Object { $_.Subject -like "*$($Config.ComputerCertSubject)*" } }
if ($certs.Count -eq 0) {
Add-Result "2-Cert-Computer" "Certyfikat wystawiony przez $($Config.ExpectedIssuer)" "FAIL" "Brak certyfikatow pasujacych do konfiguracji (Issuer: $($Config.ExpectedIssuer), Subject zawiera: '$($Config.ComputerCertSubject)')."; return
}
Add-Result "2-Cert-Computer" "Certyfikaty wystawione przez $($Config.ExpectedIssuer)" "PASS" "Znaleziono: $($certs.Count) certyfikat(ow)"
$now = Get-Date; $i = 0
foreach ($cert in $certs) {
$i++
$daysLeft = ($cert.NotAfter - $now).Days
Write-SubHeader "Certyfikat komputerowy #$i z $($certs.Count)"
Add-Result "2-Cert-Computer" "Subject (pelna nazwa)" "INFO" $cert.Subject
Add-Result "2-Cert-Computer" "Issuer (wystawca)" "INFO" $cert.Issuer
Add-Result "2-Cert-Computer" "Thumbprint" "INFO" $cert.Thumbprint
Add-Result "2-Cert-Computer" "Numer seryjny" "INFO" $cert.SerialNumber
Add-Result "2-Cert-Computer" "Wazny OD" "INFO" $cert.NotBefore.ToString('yyyy-MM-dd HH:mm')
Add-Result "2-Cert-Computer" "Wazny DO" "INFO" $cert.NotAfter.ToString('yyyy-MM-dd HH:mm')
$waznoscLabel = "Waznosc certyfikatu [$($cert.NotAfter.ToString('yyyy-MM-dd'))]"
if ($daysLeft -lt 0) { Add-Result "2-Cert-Computer" $waznoscLabel "FAIL" "WYGASL $([Math]::Abs($daysLeft)) dni temu!" } elseif ($daysLeft -lt $Config.MinValidDaysError) { Add-Result "2-Cert-Computer" $waznoscLabel "FAIL" "Wygasa za $daysLeft dni – krytyczne!" } elseif ($daysLeft -lt $Config.MinValidDaysWarning) { Add-Result "2-Cert-Computer" $waznoscLabel "WARN" "Wygasa za $daysLeft dni." } else { Add-Result "2-Cert-Computer" $waznoscLabel "PASS" "Pozostalo $daysLeft dni waznosci." }
$sanExt = $cert.Extensions | Where-Object { $_.Oid.FriendlyName -eq "Subject Alternative Name" }
if ($sanExt) { Add-Result "2-Cert-Computer" "Subject Alternative Names (SAN)" "INFO" $sanExt.Format($false) }
$ekuExt = $cert.Extensions | Where-Object { $_.Oid.FriendlyName -eq "Enhanced Key Usage" }
if ($ekuExt) {
$ekuVal = $ekuExt.Format($false)
$hasClient = $ekuVal -match "1\.3\.6\.1\.5\.5\.7\.3\.2|Client Authentication"
Add-Result "2-Cert-Computer" "EKU – Client Authentication" $(if ($hasClient) {"PASS"} else {"FAIL"}) $(if ($hasClient) {"Client Authentication (1.3.6.1.5.5.7.3.2) – OK"} else {"BRAK EKU Client Authentication!"})
}
Add-Result "2-Cert-Computer" "Klucz prywatny" "SKIP" "Weryfikacja klucza prywatnego wymaga uprawnien administratora."
}
}
# ================================================================
# TEST 3: Urzedy certyfikacji
# ================================================================
function Test-CertificateAuthorities {
Write-Header "TEST 3: URZEDY CERTYFIKACJI (CA)"
Write-SubHeader "Zaufane Glowne Urzedy Certyfikacji [LocalMachine\Root]"
$rootStore = Get-ChildItem "Cert:\LocalMachine\Root" -ErrorAction SilentlyContinue
if ($null -eq $rootStore) {
Add-Result "3-CA" "Dostep do LocalMachine\Root" "WARN" "Brak dostepu do magazynu Root CA."
} else {
$rootCAs = $rootStore | Where-Object { $_.Subject -like "*$($Config.ExpectedRootCA)*" }
if ($rootCAs) {
Add-Result "3-CA" "ROOT CA: $($Config.ExpectedRootCA)" "PASS" "Znaleziono $($rootCAs.Count) certyfikat(ow) w Zaufanych Glownych CA."
foreach ($ca in $rootCAs) {
$days = ($ca.NotAfter - (Get-Date)).Days
Add-Result "3-CA" "Subject ROOT CA" "INFO" $ca.Subject
Add-Result "3-CA" "Thumbprint ROOT CA" "INFO" $ca.Thumbprint
Add-Result "3-CA" "Wazny DO (ROOT CA)" $(if ($days -gt 30) {"PASS"} elseif ($days -gt 0) {"WARN"} else {"FAIL"}) "$($ca.NotAfter.ToString('yyyy-MM-dd')) (pozostalo $days dni)"
}
} else {
Add-Result "3-CA" "ROOT CA: $($Config.ExpectedRootCA)" "FAIL" "NIE ZNALEZIONO '$($Config.ExpectedRootCA)' w Zaufanych Glownych Urzedach Certyfikacji! Klienci nie beda ufac certyfikatom tej CA."
}
}
Write-SubHeader "Posrednie Urzedy Certyfikacji [LocalMachine\CA]"
$subStore = Get-ChildItem "Cert:\LocalMachine\CA" -ErrorAction SilentlyContinue
if ($null -eq $subStore) {
Add-Result "3-CA" "Dostep do LocalMachine\CA" "WARN" "Brak dostepu do magazynu posrednich CA."
} else {
$subCAs = $subStore | Where-Object { $_.Subject -like "*$($Config.ExpectedSubCA)*" }
if ($subCAs) {
Add-Result "3-CA" "SUB CA: $($Config.ExpectedSubCA)" "PASS" "Znaleziono $($subCAs.Count) certyfikat(ow) w Posrednich CA."
foreach ($ca in $subCAs) {
$days = ($ca.NotAfter - (Get-Date)).Days
Add-Result "3-CA" "Subject SUB CA" "INFO" $ca.Subject
Add-Result "3-CA" "Issuer SUB CA" "INFO" $ca.Issuer
Add-Result "3-CA" "Thumbprint SUB CA" "INFO" $ca.Thumbprint
Add-Result "3-CA" "Wazny DO (SUB CA)" $(if ($days -gt 30) {"PASS"} elseif ($days -gt 0) {"WARN"} else {"FAIL"}) "$($ca.NotAfter.ToString('yyyy-MM-dd')) (pozostalo $days dni)"
}
} else {
Add-Result "3-CA" "SUB CA: $($Config.ExpectedSubCA)" "FAIL" "NIE ZNALEZIONO '$($Config.ExpectedSubCA)' w Posrednich Urzedach Certyfikacji! Lancuch zaufania bedzie niekompletny."
}
}
Write-SubHeader "Magazyn uzytkownika [CurrentUser\Root]"
$userRoot = Get-ChildItem "Cert:\CurrentUser\Root" -ErrorAction SilentlyContinue | Where-Object { $_.Subject -like "*$($Config.ExpectedRootCA)*" }
if ($userRoot) { Add-Result "3-CA" "ROOT CA w CurrentUser\Root" "INFO" "Takze obecny w magazynie uzytkownika." } else { Add-Result "3-CA" "ROOT CA w CurrentUser\Root" "INFO" "Nieobecny w CurrentUser\Root (normalnie wystarczy LocalMachine\Root)." }
}
# ================================================================
# TEST 4: Profil Wi-Fi i konfiguracja EAP
# ================================================================
function Test-WiFiProfile {
Write-Header "TEST 4: PROFIL WI-FI i KONFIGURACJA EAP [netsh wlan]"
$netshOutput = netsh wlan show profiles 2>&1
if ($LASTEXITCODE -ne 0) { Add-Result "4-WiFi" "Usluga WLAN AutoConfig" "FAIL" "Nie mozna pobrac listy profili."; return }
$profiles = ($netshOutput | Select-String "Profil uzytkownika\s*:\s*(.+)|All User Profile\s*:\s*(.+)" |
ForEach-Object { if ($_.Matches[0].Groups[1].Value) { $_.Matches[0].Groups[1].Value.Trim() } else { $_.Matches[0].Groups[2].Value.Trim() } })
if ($profiles.Count -eq 0) { Add-Result "4-WiFi" "Lista profili Wi-Fi" "FAIL" "Brak zapisanych profili WLAN."; return }
Add-Result "4-WiFi" "Lista profili Wi-Fi" "INFO" "Dostepne: $($profiles -join ' | ')"
$matchedProfile = $profiles | Where-Object { $_ -like "*$($Config.ExpectedSSID)*" } | Select-Object -First 1
if (-not $matchedProfile) { Add-Result "4-WiFi" "Profil SSID: $($Config.ExpectedSSID)" "FAIL" "Profil '$($Config.ExpectedSSID)' NIE ISTNIEJE. Dostepne: $($profiles -join ', ')"; return }
Add-Result "4-WiFi" "Profil SSID: $($Config.ExpectedSSID)" "PASS" "Profil '$matchedProfile' znaleziony."
$profileDetails = netsh wlan show profile name="$matchedProfile" 2>&1
$authLine = $profileDetails | Select-String "Uwierzytelnienie|Authentication" | Select-Object -First 1
if ($authLine) {
$authValue = ($authLine -split ":")[1].Trim()
Add-Result "4-WiFi" "Typ uwierzytelnienia" $(if ($authValue -match "WPA2|WPA3") {"PASS"} else {"WARN"}) "Uwierzytelnienie: $authValue"
}
$encLine = $profileDetails | Select-String "Szyfrowanie|Cipher" | Select-Object -First 1
if ($encLine) { Add-Result "4-WiFi" "Szyfrowanie" "INFO" "Szyfrowanie: $(($encLine -split ':')[1].Trim())" }
$dot1xLine = $profileDetails | Select-String "802\.1X|OneX" | Select-Object -First 1
if ($dot1xLine) {
$dot1xValue = ($dot1xLine -split ":")[1].Trim()
Add-Result "4-WiFi" "802.1X wlaczone" $(if ($dot1xValue -match "Wlaczon|Enabled|Yes") {"PASS"} else {"FAIL"}) "802.1X: $dot1xValue"
} else { Add-Result "4-WiFi" "802.1X w profilu" "WARN" "Nie wykryto wpisu 802.1X w detalach profilu." }
# EAP Type z XML
$xmlFile = $null
try { $null = netsh wlan export profile name="$matchedProfile" folder="$env:TEMP" key=clear 2>&1; $xmlFile = Get-ChildItem "$env:TEMP\*.xml" | Sort-Object LastWriteTime -Descending | Select-Object -First 1 } catch {}
if ($xmlFile) {
[xml]$profileXml = Get-Content $xmlFile.FullName -Encoding UTF8 -ErrorAction SilentlyContinue
Remove-Item $xmlFile.FullName -Force -ErrorAction SilentlyContinue
if ($profileXml) {
$eapTypeRaw = $profileXml.InnerXml | Select-String '
| NR | STATUS | TEST | SZCZEGOLY | CZAS |
|---|