PowerShell
Windows Server
Security
SSL/TLS
📋 O skrypcie
Skrypt PowerShell do kompleksowej inwentaryzacji wszystkich certyfikatów SSL/TLS na serwerach Windows. Generuje szczegółowe raporty w formatach CSV i HTML, automatycznie wykrywa wygasające certyfikaty i identyfikuje gdzie są one używane.
✨ Optymalizacje wydajnościowe: Skrypt został zoptymalizowany do pracy z dużymi środowiskami (500-2000+ certyfikatów). Pre-loading danych eliminuje problemy O(n²) i zapewnia szybkie działanie.
🎯 Główne funkcje
Skanowanie magazynów
- Personal (Computer) - Cert:\LocalMachine\My
- Trusted Root Certification Authorities
- Intermediate Certification Authorities
- Web Hosting - Cert:\LocalMachine\WebHosting
- Current User stores
Detekcja użycia certyfikatów
- IIS Bindings - pokazuje konkretne bindingi (site:port:hostname)
- Remote Desktop (RDP) - certyfikat używany do połączeń RDP
- LDAPS Candidates - certyfikaty z Server Authentication EKU
- Port 636 detection - wykrywa czy LDAPS nasłuchuje
Raportowanie
- Automatyczne ostrzeżenia o wygasających certyfikatach (30/90 dni)
- Wykrywanie certyfikatów self-signed
- Informacje o kluczu prywatnym
- Subject Alternative Names (SAN) count
- Enhanced Key Usage (EKU)
- Algorytmy i długość klucza
- AllDomains - wszystkie domeny z certyfikatu (CN + SAN, bez duplikatów)
- Deduplikacja - ten sam certyfikat w wielu magazynach pokazany raz
🚀 Szybki start
1. Pobierz skrypt
Invoke-WebRequest -Uri "https://work-public.grzywaczewski.net/certificate-inventory/Get-CertificateInventory.ps1" -OutFile "Get-CertificateInventory.ps1"
2. Odblokuj plik (jeśli pobrano z internetu)
Unblock-File -Path ".\Get-CertificateInventory.ps1"
3. Uruchom skrypt
# Podstawowe użycie - raport w bieżącym katalogu
.\Get-CertificateInventory.ps1
# Określ ścieżkę do raportu
.\Get-CertificateInventory.ps1 -OutputPath "C:\Reports\CertInventory.csv"
📊 Formaty raportów
CSV Report
Pełny raport zawierający wszystkie dane do dalszej analizy:
- ServerName, CertificateName, SubjectCN, AllDomains
- Issuer, SerialNumber, Thumbprint
- NotBefore, NotAfter, DaysUntilExpiry, ExpiryStatus
- UsedIn, StoreLocation, StorePath
- HasPrivateKey, IsSelfSigned
- KeyAlgorithm, KeyLength, SignatureAlgorithm
- EnhancedKeyUsage, DNSNames, SANCount
HTML Report
Interaktywny raport HTML z:
- Kolorowym oznaczeniem statusów (czerwony = wygasły, żółty = wygasa wkrótce)
- Sticky header (przewijanie tabeli)
- HTML-escaped wartości (bezpieczne wyświetlanie)
- Podsumowanie statystyk (total, self-signed, private keys)
- Wykryte usługi (LDAPS port 636, WAC port 6516)
⚙️ Wymagania
| Komponent | Wymaganie |
|---|---|
| System operacyjny | Windows Server 2016+ lub Windows 10+ |
| PowerShell | 5.1 lub nowszy |
| Uprawnienia | Administrator (dla pełnego dostępu do magazynów) |
| Moduł IIS | WebAdministration (opcjonalny, dla skanowania IIS) |
⚡ Optymalizacje wydajnościowe
Problem: Oryginalne podejście miało O(n²) w pętli - dla każdego certyfikatu wywoływało Get-WebBinding, Get-NetTCPConnection, etc.
Rozwiązanie: Pre-loading wszystkich danych raz na początku:
- IIS bindings → hashtable (thumbprint → bindings)
- RDP thumbprint → single value
- LDAPS candidates → hashtable (thumbprint → bool)
- Port checks (636, 6516) → single check
🔧 Poprawki detekcji
IIS Certificate Hash
Poprawiona normalizacja: byte[] → uppercase hex string przed porównaniem
RDP Thumbprint
Poprawna konwersja z rejestru: byte[] → hex → uppercase comparison
LDAPS Detection
Zamiast false-positive "LDAPS/Active Directory":
- "LDAPS Candidate (port 636 listening)" - jeśli LDAPS nasłuchuje
- "LDAPS Candidate (has Server Auth EKU)" - jeśli tylko ma odpowiedni EKU
Windows Admin Center
Wykrycie globalne (port 6516), bez przypisywania do konkretnego certyfikatu
🛡️ Obsługa błędów
Skrypt bezpiecznie obsługuje "dziwne" certyfikaty:
- Try/catch dla każdego certyfikatu osobno (jeden zły cert nie wyrzuci całego skanu)
- Bezpieczne accessory dla KeySize (sprawdzanie czy .Key istnieje)
- Bezpieczne accessory dla DnsNameList + fallback na Extension 2.5.29.17
- Bezpieczne EnhancedKeyUsageList z ForEach-Object
📝 Przykładowe wyjście
Console Output
=== Certificate Inventory Script ===
Server: SERVER01
Date: 01/18/2026 13:45:22
Pre-loading system configuration...
Loading IIS bindings...
Found 15 IIS bindings
Checking RDP certificate...
RDP cert thumbprint: A1B2C3D4E5F6...
Identifying LDAPS certificate candidates...
Found 3 LDAPS candidates
LDAPS (port 636) is listening
Scanning certificate stores...
Checking: Personal (Computer)...
Checking: Trusted Root Certification Authorities...
...
=== SUMMARY ===
Total certificates found: 147
Self-signed: 12
With private key: 23
EXPIRED: 2
EXPIRING SOON: 5
WARNING: 8
OK: 132
=== CERTIFICATES REQUIRING ATTENTION ===
[EXPIRED] CN=oldserver.domain.com
Expires: 2025-12-15 (in -34 days)
Used in: IIS: *:443:oldserver.domain.com
Performance notes:
- Pre-loaded IIS bindings: 15 certificates mapped
- LDAPS candidates identified: 3
- Processed 147 certificates