🔐 Certificate Inventory

Kompleksowy skrypt do inwentaryzacji certyfikatów SSL/TLS na Windows Server

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
W pętli tylko lookups w hashtable = O(1)

🔧 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