Windows 10 nach Inplace-Upgrade absichern: BSI-Hardening, Firewall & Killer-WLAN mit PowerShell automatisieren

Minimalistische Grafik zum Thema Windows 10 BSI Hardening, Firewall-Schutz und Dienst-Deaktivierung
Minimalistische-Grafik-zum-Thema-Windows-10-BSI-Hardening-Firewall-Schutz-und-Dienst-Deaktivierung-Gemini_Generated_Image Gemini_Generated_Image

Ein Windows 10 Inplace-Upgrade ist oft das beste Werkzeug, um ein beschädigtes Betriebssystem ohne Datenverlust zu reparieren. Was viele Anwender – insbesondere im privaten Umfeld – jedoch nicht bedenken: Eine Inplace-Reparatur setzt nahezu alle Sicherheitseinstellungen, Dienste und Firewall-Profilregeln auf den Microsoft-Standardzustand zurück.

Plötzlich funken Telemetriedienste wieder nach Hause, unnötige Remote-Schnittstellen werden geöffnet und ungeliebte Softwarepakete wie das Killer Network Center auf MSI-Notebooks (z. B. MSI GT80) übernehmen wieder die Regie über den Netzwerk-Stack.

In den meisten Haushalten läuft ein PC nach dem Motto: „Hauptsache, das Internet geht.“ Aber Sicherheit im Netz gilt für jeden. Das Bundesamt für Sicherheit in der Informationstechnik (BSI) hat umfangreiche Sicherheitsempfehlungen herausgegeben, um Windows 10 zu härten. Leider stellt das BSI kein fertiges PowerShell-Skript zur Verfügung, um diese Empfehlungen rasch umzusetzen.

In diesem Beitrag zeige ich Schritt für Schritt, wie ich mein System nach dem Inplace-Upgrade nach BSI-Vorgaben gehärtet habe – inklusive aller von mir entwickelten Skripte zur Diagnose, Automatisierung und Deaktivierung störender Dienste.

Das Problem: Nach der Reparatur steht das Scheunentor wieder offen

Nach dem Inplace-Upgrade auf meinem MSI GT80 fielen mir direkt mehrere Schwachstellen und Performance-Killer auf:

  1. Killer WLAN Bloatware: Das mit installierte Software-Paket von Killer Networking (Analytics, Dynamic Bandwidth Management etc.) führt auf MSI-Geräten häufiger zu Paketverlusten und Systembremsen, als dass es hilft. Der reine Treiber reicht völlig aus!

  2. Telemetrie & Datenerfassung: Microsoft-Dienste wie DiagTrack oder der Windows-Insider-Dienst wurden wieder auf automatischen Start gesetzt.

  3. Remote-Schnittstellen: Dienste wie Remote Desktop (RDP), WinRM und Remote Registry liefen im Hintergrund oder waren erreichbar.

  4. Veraltete / Unsichere Netzwerkprotokolle: LLMNR (Link-Local Multicast Name Resolution) und NetBIOS over TCP/IP waren wieder aktiv – im lokalen Netz ein bekanntes Risiko für LLMNR-Poisoning-Angriffe.

Da ich diese Konfiguration nicht jedes Mal manuell über Dutzende Menüs durchklicken wollte, habe ich mir eine Skript-Sammlung aufgebaut.

Schritt 1: Das Starter-Skript (FirewallSecurity.bat) zur Rechteausweitung

Um PowerShell-Skripte sicher und ohne administrative Komplikationen auszuführen, nutze ich eine Batch-Datei als Starter. Sie prüft automatisch, ob administrative Rechte vorliegen, fordert diese bei Bedarf an und startet das eigentliche PowerShell-Hardening-Skript mit angepasster Execution-Policy.

DOS
 
@echo off
setlocal EnableExtensions DisableDelayedExpansion

REM ============================================================
REM WINDOWS FIREWALL SECURITY CENTER
REM BAT STARTER
REM Windows 10 Home / Pro
REM ============================================================

title Windows Firewall Security Center

REM Eigenen Ordner absolut bestimmen
set "SCRIPT_DIR=%~dp0"
set "PS1_FILE=%SCRIPT_DIR%FirewallSecurity.ps1"

echo.
echo ============================================================
echo WINDOWS FIREWALL SECURITY CENTER
echo ============================================================
echo.
echo Sichere Windows-Firewall-Konfiguration
echo Windows 10 Home / Pro
echo.
echo ============================================================
echo.

REM ------------------------------------------------------------
REM Pruefen, ob die PowerShell-Datei vorhanden ist
REM ------------------------------------------------------------

if not exist "%PS1_FILE%" (
echo.
echo FEHLER:
echo.
echo Die PowerShell-Datei wurde nicht gefunden:
echo.
echo "%PS1_FILE%"
echo.
echo Bitte pruefen, ob FirewallSecurity.ps1 im selben
echo Ordner wie diese BAT-Datei liegt.
echo.
pause
exit /b 10
)

REM ------------------------------------------------------------
REM Administratorrechte pruefen
REM ------------------------------------------------------------

net session >nul 2>&1

if %ERRORLEVEL% NEQ 0 (

echo [INFO] Administratorrechte werden angefordert...
echo.

powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass ^
    -Command "Start-Process -FilePath '%~f0' -Verb RunAs"

exit /b


)

REM ------------------------------------------------------------
REM PowerShell-Skript starten
REM ------------------------------------------------------------

echo [INFO] PowerShell-Sicherheitskonfiguration wird gestartet...
echo.
echo Skript:
echo "%PS1_FILE%"
echo.

powershell.exe ^
-NoLogo ^
-NoProfile ^
-ExecutionPolicy Bypass ^
-File "%PS1_FILE%"

set "EXITCODE=%ERRORLEVEL%"

echo.
echo ============================================================
echo.

if "%EXITCODE%"=="0" (
echo Sicherheitskonfiguration erfolgreich beendet.
) else (
echo ACHTUNG!
echo Die Konfiguration wurde mit Fehlercode %EXITCODE% beendet.
echo.
echo Bitte die angezeigte Fehlermeldung bzw. das Log pruefen.
)

echo.
pause

exit /b %EXITCODE%

Schritt 2: Das BSI-Hardening- & Firewall-Skript (FirewallSecurity.ps1)

Das Hauptskript führt die eigentliche Aushärtung des Systems durch. Es setzt die Windows-Firewall auf ein sicheres Default-Verhalten (Block Inbound, Allow Outbound), deaktiviert Telemetriedienste sowie die stöhrenden Killer-WLAN-Hintergrunddienste, schaltet unsichere Protokolle (LLMNR, NetBIOS, SMB1) ab und kapselt RDP- sowie WinRM-Zugriffe über explizite Blockregeln.

Alle Aktionen werden übersichtlich in einer Logdatei unter C:\ProgramData\FirewallSecurity\Logs\ protokolliert.

PowerShell
 
#requires -version 5.1

<#
============================================================
 WINDOWS FIREWALL SECURITY CENTER & BSI HARDENING
 Version 6.1

 Zielsystem:
   Windows 10 / 11 Home / Pro

 Sicherheitskonzept:
   - Windows Firewall AKTIV
   - Eingehend standardmäßig BLOCK
   - Ausgehend standardmäßig ALLOW
   - SMB bleibt unangetastet (SMB2/3 aktiv)
   - SMB1 wird deaktiviert / geprüft
   - RDP wird deaktiviert und explizit blockiert
   - WinRM wird deaktiviert und explizit blockiert
   - Remote Registry wird deaktiviert
   - LLMNR wird deaktiviert (BSI IT-Grundschutz)
   - NetBIOS over TCP/IP wird deaktiviert (BSI IT-Grundschutz)
   - Telemetrie-, iSCSI-, VR- & Killer-Dienste werden deaktiviert
============================================================
#>

$ErrorActionPreference = "Stop"

$ScriptVersion = "6.1"
$Failures = 0
$RestartNeeded = $false

$SecurityGroup = "SECURITY - Managed Firewall Rules"

# ============================================================
# LOGGING SYSTEM
# ============================================================

$LogDirectory = Join-Path $env:ProgramData "FirewallSecurity\Logs"
New-Item -Path $LogDirectory -ItemType Directory -Force | Out-Null

$TimeStamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
$LogFile = Join-Path $LogDirectory "FirewallSecurity_$TimeStamp.log"

function Write-Log {
    param(
        [string]$Message,
        [ValidateSet("INFO", "OK", "WARN", "ERROR")]
        [string]$Level = "INFO"
    )

    $Now = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $Line = "[$Now] [$Level] $Message"
    Add-Content -Path $LogFile -Value $Line -Encoding UTF8

    switch ($Level) {
        "INFO"  { Write-Host "[INFO] $Message" -ForegroundColor Cyan }
        "OK"    { Write-Host "[ OK ] $Message" -ForegroundColor Green }
        "WARN"  { Write-Host "[WARN] $Message" -ForegroundColor Yellow }
        "ERROR" { Write-Host "[ERR ] $Message" -ForegroundColor Red }
    }
}

# ============================================================
# HILFSFUNKTION FÜR DIENST-DEAKTIVIERUNG
# ============================================================

function Disable-SecurityService {
    param(
        [string]$ServiceName,
        [string]$DisplayNamePattern
    )

    try {
        $Service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
        if (-not $Service -and $DisplayNamePattern) {
            $Service = Get-Service -DisplayName $DisplayNamePattern -ErrorAction SilentlyContinue
        }

        if ($Service) {
            if ($Service.Status -eq "Running") {
                Stop-Service -Name $Service.Name -Force -ErrorAction SilentlyContinue
            }
            Set-Service -Name $Service.Name -StartupType Disabled -ErrorAction Stop
            Write-Log "Dienst '$($Service.DisplayName)' ($($Service.Name)) = Deaktiviert." "OK"
        } else {
            Write-Log "Dienst '$DisplayNamePattern' ($ServiceName) nicht vorhanden (übersprungen)." "INFO"
        }
    }
    catch {
        Write-Log "Dienst '$DisplayNamePattern' ($ServiceName) konnte nicht deaktiviert werden: $($_.Exception.Message)" "WARN"
    }
}

# ============================================================
# ADMINISTRATORPRÜFUNG
# ============================================================

$Identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$Principal = New-Object Security.Principal.WindowsPrincipal($Identity)
$IsAdmin = $Principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)

if (-not $IsAdmin) {
    Write-Host ""
    Write-Host "FEHLER: Dieses Skript muss als Administrator ausgeführt werden." -ForegroundColor Red
    Write-Host ""
    exit 10
}

# ============================================================
# HEADER
# ============================================================

Clear-Host
Write-Host "============================================================" -ForegroundColor DarkCyan
Write-Host "          WINDOWS FIREWALL & SECURITY CENTER" -ForegroundColor Cyan
Write-Host "============================================================" -ForegroundColor DarkCyan
Write-Host ""
Write-Host "Version:    $ScriptVersion"
Write-Host "Computer:   $env:COMPUTERNAME"
Write-Host "Benutzer:   $env:USERNAME"
Write-Host "PowerShell: $($PSVersionTable.PSVersion)"
Write-Host ""

Write-Log "Security Center gestartet."
Write-Log "Version $ScriptVersion"

# ============================================================
# WINDOWS VERSION
# ============================================================

try {
    $OS = Get-CimInstance Win32_OperatingSystem
    Write-Host "Betriebssystem: $($OS.Caption)"
    Write-Host "Build:          $($OS.BuildNumber)"
    Write-Host ""
    Write-Log "Betriebssystem: $($OS.Caption)"
    Write-Log "Build: $($OS.BuildNumber)"
}
catch {
    Write-Log "Windows-Version konnte nicht ermittelt werden." "WARN"
}

# ============================================================
# FIREWALL DIENST
# ============================================================

Write-Host ""
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " FIREWALL-DIENST" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"
Write-Host ""

try {
    $FirewallService = Get-Service -Name MpsSvc -ErrorAction Stop

    if ($FirewallService.Status -ne "Running") {
        Write-Log "Windows-Firewall-Dienst ist nicht aktiv." "WARN"
        try {
            Start-Service -Name MpsSvc -ErrorAction Stop
            Write-Log "Windows-Firewall-Dienst wurde gestartet." "OK"
        }
        catch {
            Write-Log "Windows-Firewall-Dienst konnte nicht gestartet werden." "ERROR"
            $Failures++
        }
    }
    else {
        Write-Log "Windows-Firewall-Dienst ist aktiv." "OK"
    }
}
catch {
    Write-Log "Windows-Firewall-Dienst konnte nicht geprüft werden." "ERROR"
    $Failures++
}

# ============================================================
# ALTE SECURITY-REGELN BEREINIGEN
# ============================================================

Write-Host ""
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " EIGENE SECURITY-REGELN BEREINIGEN" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"
Write-Host ""

try {
    $OldRules = Get-NetFirewallRule -Group $SecurityGroup -ErrorAction SilentlyContinue

    if ($OldRules) {
        $Count = @($OldRules).Count
        Remove-NetFirewallRule -Group $SecurityGroup -ErrorAction Stop
        Write-Log "$Count alte SECURITY-Regel(n) entfernt." "OK"
    }
    else {
        Write-Log "Keine alten SECURITY-Regeln vorhanden." "OK"
    }
}
catch {
    Write-Log "Eigene SECURITY-Regeln konnten nicht bereinigt werden." "ERROR"
    $Failures++
}

# ============================================================
# FIREWALL PROFILE
# ============================================================

Write-Host ""
Write-Host "============================================================" -ForegroundColor DarkCyan
Write-Host " FIREWALL-BASISKONFIGURATION" -ForegroundColor Cyan
Write-Host "============================================================"
Write-Host ""

try {
    Set-NetFirewallProfile `
        -Profile Domain,Private,Public `
        -Enabled True `
        -DefaultInboundAction Block `
        -DefaultOutboundAction Allow `
        -NotifyOnListen False `
        -AllowUnicastResponseToMulticast True `
        -LogBlocked True `
        -LogAllowed False `
        -LogMaxSizeKilobytes 32767 `
        -ErrorAction Stop

    Write-Log "Alle Firewallprofile aktiviert." "OK"
    Write-Log "Default Inbound = BLOCK." "OK"
    Write-Log "Default Outbound = ALLOW." "OK"
    Write-Log "Benutzerbenachrichtigungen bei Listen = AUS." "OK"
    Write-Log "Blockierte Verbindungen werden protokolliert." "OK"
}
catch {
    Write-Log "Firewall-Basiskonfiguration fehlgeschlagen: $($_.Exception.Message)" "ERROR"
    $Failures++
}

# ============================================================
# REMOTE DESKTOP (RDP)
# ============================================================

Write-Host ""
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " REMOTE DESKTOP / RDP" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"
Write-Host ""

try {
    New-NetFirewallRule `
        -DisplayName "SECURITY - BLOCK Remote Desktop TCP 3389" `
        -Description "Blockiert eingehende Microsoft Remote Desktop Verbindungen." `
        -Group $SecurityGroup `
        -Direction Inbound `
        -Action Block `
        -Protocol TCP `
        -LocalPort 3389 `
        -Profile Any `
        -Enabled True `
        -EdgeTraversalPolicy Block `
        -ErrorAction Stop | Out-Null

    Write-Log "Explizite RDP-Blockregel erstellt." "OK"
}
catch {
    Write-Log "RDP-Blockregel konnte nicht erstellt werden." "ERROR"
    $Failures++
}

try {
    $RdpRegistryPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server"
    Set-ItemProperty -Path $RdpRegistryPath -Name fDenyTSConnections -Type DWord -Value 1 -Force -ErrorAction Stop
    Write-Log "RDP Registry-Konfiguration = deaktiviert." "OK"
}
catch {
    Write-Log "RDP Registry-Konfiguration konnte nicht gesetzt werden." "ERROR"
    $Failures++
}

Disable-SecurityService -ServiceName "TermService" -DisplayNamePattern "Remotedesktoppostdienste"

# ============================================================
# WINRM & REMOTE REGISTRY
# ============================================================

Write-Host ""
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " WINRM & REMOTE REGISTRY" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"
Write-Host ""

try {
    New-NetFirewallRule `
        -DisplayName "SECURITY - BLOCK WinRM TCP 5985" `
        -Description "Blockiert eingehende WinRM HTTP Verbindungen." `
        -Group $SecurityGroup `
        -Direction Inbound `
        -Action Block `
        -Protocol TCP `
        -LocalPort 5985 `
        -Profile Any `
        -Enabled True `
        -EdgeTraversalPolicy Block `
        -ErrorAction Stop | Out-Null

    New-NetFirewallRule `
        -DisplayName "SECURITY - BLOCK WinRM TCP 5986" `
        -Description "Blockiert eingehende WinRM HTTPS Verbindungen." `
        -Group $SecurityGroup `
        -Direction Inbound `
        -Action Block `
        -Protocol TCP `
        -LocalPort 5986 `
        -Profile Any `
        -Enabled True `
        -EdgeTraversalPolicy Block `
        -ErrorAction Stop | Out-Null

    Write-Log "WinRM TCP 5985/5986 explizit blockiert." "OK"
}
catch {
    Write-Log "WinRM-Blockregeln konnten nicht erstellt werden." "ERROR"
    $Failures++
}

Disable-SecurityService -ServiceName "WinRM" -DisplayNamePattern "Windows-Remoteverwaltung*"
Disable-SecurityService -ServiceName "RemoteRegistry" -DisplayNamePattern "Remoteregistrierung"

# ============================================================
# TELEMETRIE & UNNÖTIGE DIENSTE DEAKTIVIEREN
# ============================================================

Write-Host ""
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " TELEMETRIE & UNNÖTIGE SYSTEMDIENSTE" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"
Write-Host ""

# Windows Systemdienste
Disable-SecurityService -ServiceName "DiagTrack" -DisplayNamePattern "Benutzererfahrungen und Telemetrie im verbundenen Modus"
Disable-SecurityService -ServiceName "RetailDemo" -DisplayNamePattern "Dienst für Einzelhandelsdemos"
Disable-SecurityService -ServiceName "MapsBroker" -DisplayNamePattern "Manager für heruntergeladene Karten"
Disable-SecurityService -ServiceName "MSiSCSI" -DisplayNamePattern "Microsoft iSCSI-Initiator-Dienst"
Disable-SecurityService -ServiceName "mixedrealityopenxr" -DisplayNamePattern "Windows Mixed Reality OpenXR Service"
Disable-SecurityService -ServiceName "wisvc" -DisplayNamePattern "Windows-Insider-Dienst"

# Killer Network Services
Disable-SecurityService -ServiceName "KAPSService" -DisplayNamePattern "Killer Analytics Service"
Disable-SecurityService -ServiceName "KDBMService" -DisplayNamePattern "Killer Dynamic Bandwidth Management"
Disable-SecurityService -ServiceName "KillerSmartAP" -DisplayNamePattern "Killer Smart AP Selection Service"
Disable-SecurityService -ServiceName "KDataHelper" -DisplayNamePattern "Killer Provider Data Helper Service"
Disable-SecurityService -ServiceName "KNetworkService" -DisplayNamePattern "Killer Network Service"

# ============================================================
# LLMNR DEAKTIVIEREN (BSI IT-GRUNDSCHUTZ)
# ============================================================

Write-Host ""
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " LLMNR DEAKTIVIEREN" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"
Write-Host ""

try {
    $DNSClientPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient"

    if (-not (Test-Path -Path $DNSClientPath)) {
        New-Item -Path $DNSClientPath -Force | Out-Null
    }

    Set-ItemProperty `
        -Path $DNSClientPath `
        -Name "EnableMulticast" `
        -Value 0 `
        -Type DWord `
        -Force `
        -ErrorAction Stop

    Write-Log "LLMNR erfolgreich über Registry deaktiviert." "OK"
}
catch {
    Write-Log "LLMNR konnte nicht deaktiviert werden: $($_.Exception.Message)" "ERROR"
    $Failures++
}

# ============================================================
# NETBIOS OVER TCP/IP DEAKTIVIEREN
# ============================================================

Write-Host ""
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " NETBIOS DEAKTIVIEREN" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"
Write-Host ""

try {
    $NetAdapterTcpip = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "IPEnabled = True"

    foreach ($Adapter in $NetAdapterTcpip) {
        $null = Invoke-CimMethod -InputObject $Adapter -MethodName SetTCPIPNetBIOS -Arguments @{TcpipNetbiosOptions = 2}
    }

    Write-Log "NetBIOS over TCP/IP auf allen aktiven Adaptern deaktiviert." "OK"
}
catch {
    Write-Log "NetBIOS konnte nicht deaktiviert werden: $($_.Exception.Message)" "ERROR"
    $Failures++
}

# ============================================================
# SMB PRÜFUNG / SMB1 DEAKTIVIEREN
# ============================================================

Write-Host ""
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " SMB / FRITZ!NAS" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"
Write-Host ""

try {
    $SMB1Feature = Get-WindowsOptionalFeature -Online -FeatureName SMB1Protocol -ErrorAction Stop
    Write-Log "SMB1 aktueller Status: $($SMB1Feature.State)"

    if ($SMB1Feature.State -eq "Enabled" -or $SMB1Feature.State -eq "Enable Pending") {
        Write-Log "SMB1 ist aktiviert und wird deaktiviert." "WARN"

        $DisableResult = Disable-WindowsOptionalFeature -Online -FeatureName SMB1Protocol -NoRestart -ErrorAction Stop

        if ($DisableResult.RestartNeeded) {
            $RestartNeeded = $true
            Write-Log "Windows benötigt einen Neustart für die SMB1-Deaktivierung." "WARN"
        }
    }

    $SMB1Verify = Get-WindowsOptionalFeature -Online -FeatureName SMB1Protocol -ErrorAction Stop

    if ($SMB1Verify.State -eq "Disabled" -or $SMB1Verify.State -eq "DisabledWithPayloadRemoved") {
        Write-Log "SMB1 = DEAKTIVIERT." "OK"
    }
    else {
        Write-Log "SMB1 konnte nicht vollständig deaktiviert werden. Status: $($SMB1Verify.State)" "ERROR"
        $Failures++
    }
}
catch {
    Write-Log "SMB1-Prüfung fehlgeschlagen: $($_.Exception.Message)" "ERROR"
    $Failures++
}

# ============================================================
# ABSCHLUSSPRÜFUNG
# ============================================================

Write-Host ""
Write-Host "============================================================" -ForegroundColor DarkCyan
Write-Host " ABSCHLUSSPRÜFUNG" -ForegroundColor Cyan
Write-Host "============================================================"
Write-Host ""

Write-Host "[1] Firewall-Profile"
try {
    $Profiles = Get-NetFirewallProfile
    foreach ($ProfileName in @("Domain", "Private", "Public")) {
        $Profile = $Profiles | Where-Object { $_.Name -eq $ProfileName }
        if (-not $Profile) {
            Write-Log "$ProfileName Profil nicht gefunden." "ERROR"
            $script:Failures++
            continue
        }
        if ($Profile.Enabled -eq $true) { Write-Log "$ProfileName Firewall = AKTIV" "OK" }
        else { Write-Log "$ProfileName Firewall = AUS" "ERROR"; $script:Failures++ }

        if ($Profile.DefaultInboundAction -eq "Block") { Write-Log "$ProfileName Inbound = BLOCK" "OK" }
        else { Write-Log "$ProfileName Inbound ist NICHT BLOCK." "ERROR"; $script:Failures++ }
    }
}
catch {
    Write-Log "Firewall-Profilprüfung fehlgeschlagen." "ERROR"
    $Failures++
}

Write-Host ""
Write-Host "[2] SECURITY-FIREWALLREGELN"

function Test-SecurityRule {
    param([string]$DisplayName, [string]$Direction, [string]$Action)
    try {
        $Rule = Get-NetFirewallRule -DisplayName $DisplayName -ErrorAction Stop
        if ($Rule.Enabled -eq "True" -and $Rule.Direction -eq $Direction -and $Rule.Action -eq $Action) {
            Write-Log "$DisplayName = OK" "OK"
        } else {
            Write-Log "$DisplayName = FALSCH KONFIGURIERT" "ERROR"
            $script:Failures++
        }
    }
    catch {
        Write-Log "$DisplayName = FEHLT" "ERROR"
        $script:Failures++
    }
}

Test-SecurityRule -DisplayName "SECURITY - BLOCK Remote Desktop TCP 3389" -Direction Inbound -Action Block
Test-SecurityRule -DisplayName "SECURITY - BLOCK WinRM TCP 5985" -Direction Inbound -Action Block
Test-SecurityRule -DisplayName "SECURITY - BLOCK WinRM TCP 5986" -Direction Inbound -Action Block

Write-Host ""
Write-Host "[3] RDP, LLMNR & NETBIOS STATUS"

try {
    $RdpState = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server" -Name fDenyTSConnections -ErrorAction Stop
    if ($RdpState -eq 1) { Write-Log "RDP = DEAKTIVIERT" "OK" }
    else { Write-Log "RDP = AKTIVIERT" "ERROR"; $Failures++ }
}
catch {
    Write-Log "RDP-Status konnte nicht geprüft werden." "ERROR"
    $Failures++
}

try {
    $LlmnrState = Get-ItemPropertyValue -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient" -Name EnableMulticast -ErrorAction Stop
    if ($LlmnrState -eq 0) { Write-Log "LLMNR = DEAKTIVIERT" "OK" }
    else { Write-Log "LLMNR = AKTIVIERT" "ERROR"; $Failures++ }
}
catch {
    Write-Log "LLMNR-Status konnte nicht geprüft werden." "ERROR"
    $Failures++
}

# ============================================================
# GESAMTERGEBNIS
# ============================================================

Write-Host ""
Write-Host "============================================================" -ForegroundColor DarkCyan
Write-Host "                     ERGEBNIS" -ForegroundColor Cyan
Write-Host "============================================================"
Write-Host ""
Write-Host "Firewall:                AKTIV"
Write-Host "Inbound Default:         BLOCK"
Write-Host "Outbound Default:        ALLOW"
Write-Host "SMB2/SMB3:               NICHT VERÄNDERT"
Write-Host "SMB1:                    DEAKTIVIERT"
Write-Host "Remote Desktop:          DEAKTIVIERT"
Write-Host "WinRM:                   DEAKTIVIERT"
Write-Host "Remote Registry:         DEAKTIVIERT"
Write-Host "LLMNR:                   DEAKTIVIERT"
Write-Host "NetBIOS:                 DEAKTIVIERT"
Write-Host "Telemetrie & Bloatware:  DEAKTIVIERT"
Write-Host ""

if ($Failures -eq 0) {
    Write-Host "============================================================" -ForegroundColor Green
    Write-Host "              KONFIGURATION ERFOLGREICH" -ForegroundColor Green
    Write-Host "============================================================" -ForegroundColor Green
    Write-Log "Alle kritischen Prüfungen erfolgreich." "OK"
}
else {
    Write-Host "============================================================" -ForegroundColor Red
    Write-Host "          KONFIGURATION MIT FEHLERN ($Failures)" -ForegroundColor Red
    Write-Host "============================================================" -ForegroundColor Red
    Write-Log "$Failures Fehler festgestellt." "ERROR"
}

if ($RestartNeeded) {
    Write-Host ""
    Write-Host "============================================================" -ForegroundColor Yellow
    Write-Host "             NEUSTART ERFORDERLICH" -ForegroundColor Yellow
    Write-Host "============================================================" -ForegroundColor Yellow
    Write-Host "SMB1 wurde deaktiviert, Windows verlangt einen Neustart."
    Write-Log "Neustart wegen SMB1-Deaktivierung erforderlich." "WARN"
}

Write-Host ""
Write-Host "Logdatei: $LogFile"
Write-Host ""
Write-Log "Security Center beendet."

if ($Failures -eq 0) { exit 0 } else { exit 50 }

Schritt 3: Nur Prüfen statt Verändern – Das Audit-Skript (Audit-SecurityStatus.ps1)

Wer vor dem Ausführen von Änderungen wissen möchte, wie es um die eigene Systemhärtung steht, kann ein Audit durchführen. Dieses Skript nimmt keinerlei Änderungen vor, sondern wertet lediglich alle relevanten BSI-Kriterien, Firewall-Profile und Dienste-Zustände aus.

PowerShell
 
#requires -version 5.1

<#
============================================================
 AUDIT SECURITY STATUS & BSI HARDENING CHECK
 Version: 1.2 (Extended Service Inspection)

 Zweck:
   Prüft den aktuellen Sicherheitsstatus aller Firewall-,
   BSI-Hardening- und Dienst-Vorgaben, OHNE Änderungen am
   System vorzunehmen.
============================================================
#>

$ErrorActionPreference = "Continue"

# ------------------------------------------------------------
# ADMINISTRATORPRÜFUNG
# ------------------------------------------------------------
$Identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$Principal = New-Object Security.Principal.WindowsPrincipal($Identity)
$IsAdmin = $Principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)

if (-not $IsAdmin) {
    Write-Host ""
    Write-Host "FEHLER: Für eine vollständige Systemprüfung wird Administratorrecht benötigt." -ForegroundColor Red
    Write-Host "Bitte starte die PowerShell erneut als Administrator." -ForegroundColor Yellow
    Write-Host ""
    exit 10
}

# ------------------------------------------------------------
# HEADER & HILFSFUNKTIONEN
# ------------------------------------------------------------
Clear-Host
Write-Host "============================================================" -ForegroundColor DarkCyan
Write-Host "      SYSTEM SECURITY AUDIT & BSI STATUS CHECK" -ForegroundColor Cyan
Write-Host "============================================================" -ForegroundColor DarkCyan
Write-Host ""
Write-Host "Computer:   $env:COMPUTERNAME"
Write-Host "Datum:      $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Host ""

$PassedChecks = 0
$FailedChecks = 0

function Report-Check {
    param(
        [string]$Component,
        [string]$Detail,
        [bool]$IsSecure
    )

    if ($IsSecure) {
        $script:PassedChecks++
        Write-Host " [ PASS ] " -ForegroundColor Green -NoNewline
        Write-Host "${Component}: " -ForegroundColor White -NoNewline
        Write-Host $Detail -ForegroundColor DarkGray
    } else {
        $script:FailedChecks++
        Write-Host " [ FAIL ] " -ForegroundColor Red -NoNewline
        Write-Host "${Component}: " -ForegroundColor White -NoNewline
        Write-Host $Detail -ForegroundColor Yellow
    }
}

function Test-SecurityService {
    param(
        [string]$ServiceName,
        [string]$DisplayName
    )

    try {
        $Svc = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
        if (-not $Svc) {
            Report-Check -Component "Dienst '${DisplayName}'" -Detail "Nicht vorhanden (Sicher)" -IsSecure $true
            return
        }

        $IsSecure = ($Svc.StartType -eq "Disabled") -and ($Svc.Status -ne "Running")
        $StatusText = "Starttyp: $($Svc.StartType) | Status: $($Svc.Status)"
        Report-Check -Component "Dienst '${DisplayName}'" -Detail $StatusText -IsSecure $IsSecure
    } catch {
        Report-Check -Component "Dienst '${DisplayName}'" -Detail "Status konnte nicht ermittelt werden." -IsSecure $false
    }
}

# ------------------------------------------------------------
# 1. FIREWALL DIENST
# ------------------------------------------------------------
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " 1. FIREWALL-DIENST" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"

try {
    $FwService = Get-Service -Name MpsSvc -ErrorAction Stop
    $IsRunning = $FwService.Status -eq "Running"
    Report-Check -Component "Firewall-Dienst (MpsSvc)" -Detail "Status: $($FwService.Status)" -IsSecure $IsRunning
} catch {
    Report-Check -Component "Firewall-Dienst (MpsSvc)" -Detail "Dienst konnte nicht gelesen werden." -IsSecure $false
}

# ------------------------------------------------------------
# 2. FIREWALL PROFILE
# ------------------------------------------------------------
Write-Host ""
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " 2. FIREWALL PROFILE (Domain, Private, Public)" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"

try {
    $Profiles = Get-NetFirewallProfile -ErrorAction Stop
    foreach ($PName in @("Domain", "Private", "Public")) {
        $P = $Profiles | Where-Object { $_.Name -eq $PName }
        $IsActive = ($P.Enabled -eq $true) -and ($P.DefaultInboundAction -eq "Block") -and ($P.DefaultOutboundAction -eq "Allow")
        $StatusText = "Aktiv: $($P.Enabled) | Inbound: $($P.DefaultInboundAction) | Outbound: $($P.DefaultOutboundAction)"
        Report-Check -Component "Profil '$PName'" -Detail $StatusText -IsSecure $IsActive
    }
} catch {
    Report-Check -Component "Firewall-Profile" -Detail "Profile konnten nicht ausgelesen werden." -IsSecure $false
}

# ------------------------------------------------------------
# 3. BENUTZERDEFINIERTE FIREWALL-BLOCKREGELN
# ------------------------------------------------------------
Write-Host ""
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " 3. SECURITY FIREWALL-REGELN" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"

$SecurityRules = @(
    "SECURITY - BLOCK Remote Desktop TCP 3389",
    "SECURITY - BLOCK WinRM TCP 5985",
    "SECURITY - BLOCK WinRM TCP 5986"
)

foreach ($RuleName in $SecurityRules) {
    try {
        $Rule = Get-NetFirewallRule -DisplayName $RuleName -ErrorAction Stop
        $RuleOk = ($Rule.Enabled -eq "True") -and ($Rule.Action -eq "Block")
        Report-Check -Component "Firewall-Regel" -Detail "'$RuleName' existiert und ist AKTIV" -IsSecure $RuleOk
    } catch {
        Report-Check -Component "Firewall-Regel" -Detail "'$RuleName' FEHLT oder ist inaktiv" -IsSecure $false
    }
}

# ------------------------------------------------------------
# 4. REMOTE DESKTOP (RDP) & REMOTE SERVICES
# ------------------------------------------------------------
Write-Host ""
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " 4. REMOTE SERVICES (RDP, WinRM, Remote Registry)" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"

try {
    $RdpReg = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server" -Name fDenyTSConnections -ErrorAction Stop
    $RdpDenyOk = ($RdpReg -eq 1)
    Report-Check -Component "RDP Registry" -Detail "fDenyTSConnections = $RdpReg (1 = Deaktiviert)" -IsSecure $RdpDenyOk
} catch {
    Report-Check -Component "RDP Registry" -Detail "Wert konnte nicht ausgelesen werden." -IsSecure $false
}

Test-SecurityService -ServiceName "TermService" -DisplayName "Remotedesktoppostdienste"
Test-SecurityService -ServiceName "WinRM" -DisplayName "Windows Remote Management"
Test-SecurityService -ServiceName "RemoteRegistry" -DisplayName "Remote Registry"

# ------------------------------------------------------------
# 5. TELEMETRIE & UNNÖTIGE WINDOWS-DIENSTE
# ------------------------------------------------------------
Write-Host ""
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " 5. TELEMETRIE & SYSTEMDIENSTE" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"

Test-SecurityService -ServiceName "DiagTrack" -DisplayName "Benutzererfahrungen und Telemetrie im verbundenen Modus"
Test-SecurityService -ServiceName "RetailDemo" -DisplayName "Dienst für Einzelhandelsdemos"
Test-SecurityService -ServiceName "MapsBroker" -DisplayName "Manager für heruntergeladene Karten"
Test-SecurityService -ServiceName "MSiSCSI" -DisplayName "Microsoft iSCSI-Initiator-Dienst"
Test-SecurityService -ServiceName "mixedrealityopenxr" -DisplayName "Windows Mixed Reality OpenXR Service"
Test-SecurityService -ServiceName "wisvc" -DisplayName "Windows-Insider-Dienst"

# ------------------------------------------------------------
# 6. KILLER NETWORK SERVICES
# ------------------------------------------------------------
Write-Host ""
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " 6. KILLER NETWORK SERVICES" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"

Test-SecurityService -ServiceName "KAPSService" -DisplayName "Killer Analytics Service"
Test-SecurityService -ServiceName "KDBMService" -DisplayName "Killer Dynamic Bandwidth Management"
Test-SecurityService -ServiceName "KillerSmartAP" -DisplayName "Killer Smart AP Selection Service"
Test-SecurityService -ServiceName "KDataHelper" -DisplayName "Killer Provider Data Helper Service"
Test-SecurityService -ServiceName "KNetworkService" -DisplayName "Killer Network Service"

# ------------------------------------------------------------
# 7. LLMNR STATUS (BSI HARDENING)
# ------------------------------------------------------------
Write-Host ""
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " 7. LLMNR NAMENSAUFLÖSUNG" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"

try {
    $LlmnrRegPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient"
    if (Test-Path $LlmnrRegPath) {
        $LlmnrVal = Get-ItemPropertyValue -Path $LlmnrRegPath -Name EnableMulticast -ErrorAction SilentlyContinue
        $LlmnrOk = ($LlmnrVal -eq 0)
        Report-Check -Component "LLMNR Multicast" -Detail "EnableMulticast = $LlmnrVal (0 = Deaktiviert)" -IsSecure $LlmnrOk
    } else {
        Report-Check -Component "LLMNR Multicast" -Detail "Registry-Policy Pfad existiert nicht (LLMNR noch Standard/Aktiv)" -IsSecure $false
    }
} catch {
    Report-Check -Component "LLMNR Multicast" -Detail "Status konnte nicht ermittelt werden." -IsSecure $false
}

# ------------------------------------------------------------
# 8. NETBIOS OVER TCP/IP
# ------------------------------------------------------------
Write-Host ""
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " 8. NETBIOS OVER TCP/IP" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"

try {
    $Adapters = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "IPEnabled = True" -ErrorAction Stop
    $NetBiosAllDisabled = $true
    $DetailsList = @()

    foreach ($Adapter in $Adapters) {
        if ($Adapter.TcpipNetbiosOptions -ne 2) {
            $NetBiosAllDisabled = $false
            $DetailsList += "$($Adapter.Description): Aktiv/Default ($($Adapter.TcpipNetbiosOptions))"
        }
    }

    if ($NetBiosAllDisabled) {
        Report-Check -Component "NetBIOS Status" -Detail "Auf allen aktiven Adaptern vollständig DEAKTIVIERT (Option 2)" -IsSecure $true
    } else {
        Report-Check -Component "NetBIOS Status" -Detail "Auf folgenden Adaptern noch AKTIV: $($DetailsList -join '; ')" -IsSecure $false
    }
} catch {
    Report-Check -Component "NetBIOS Status" -Detail "Adapter-Konfiguration konnte nicht ausgelesen werden." -IsSecure $false
}

# ------------------------------------------------------------
# 9. SMB PROTOKOLLE (SMB1 CHECK)
# ------------------------------------------------------------
Write-Host ""
Write-Host "------------------------------------------------------------" -ForegroundColor DarkCyan
Write-Host " 9. SMB PROTOKOLLE" -ForegroundColor Cyan
Write-Host "------------------------------------------------------------"

try {
    $Smb1 = Get-WindowsOptionalFeature -Online -FeatureName SMB1Protocol -ErrorAction Stop
    $Smb1Disabled = ($Smb1.State -eq "Disabled") -or ($Smb1.State -eq "DisabledWithPayloadRemoved")
    Report-Check -Component "SMB1 Feature Status" -Detail "Status: $($Smb1.State)" -IsSecure $Smb1Disabled
} catch {
    Report-Check -Component "SMB1 Feature Status" -Detail "SMB1 Status konnte nicht ermittelt werden." -IsSecure $false
}

# ------------------------------------------------------------
# GESAMTERGEBNIS & AUDIT SUMMARY
# ------------------------------------------------------------
Write-Host ""
Write-Host "============================================================" -ForegroundColor DarkCyan
Write-Host "                    AUDIT ERGEBNIS" -ForegroundColor Cyan
Write-Host "============================================================" -ForegroundColor DarkCyan
Write-Host ""

Write-Host "Erfolgreiche Prüfungen [PASS]: " -NoNewline
Write-Host "$PassedChecks" -ForegroundColor Green

Write-Host "Fehlgeschlagene/Risiko-Prüfungen [FAIL]: " -NoNewline
if ($FailedChecks -eq 0) {
    Write-Host "$FailedChecks" -ForegroundColor Green
} else {
    Write-Host "$FailedChecks" -ForegroundColor Red
}

Write-Host ""
if ($FailedChecks -eq 0) {
    Write-Host "============================================================" -ForegroundColor Green
    Write-Host " RESULTAT: Das System entspricht voll den BSI-Vorgaben!" -ForegroundColor Green
    Write-Host "============================================================" -ForegroundColor Green
} else {
    Write-Host "============================================================" -ForegroundColor Red
    Write-Host " RESULTAT: Handlungsbedarf! Es wurden Schwachstellen gefunden." -ForegroundColor Red
    Write-Host "============================================================" -ForegroundColor Red
}
Write-Host ""

Schritt 4: WLAN-Dienste prüfen & störende Beacons unterdrücken (Manual_Test_WLAN_Beacon_Diag.ps1)

Ein interessantes Detail am Rande: Damit das automatische Verbinden mit dem heimischen WLAN nach der Dienstbereinigung reibungslos funktioniert, muss der Dienst wlansvc (WLAN AutoConfig) aktiv bleiben.

Hingegen führt der Dienst wcncsvc (Windows Connect Now) oft dazu, dass fremde Geräte oder Beacons unaufgefordert im Datei-Explorer auftauchen. Daher lässt sich dieser gezielt deaktivieren.

WLAN-Diagnoseskript:

PowerShell
 
#requires -version 5.1

<#
============================================================
 WLAN SERVICES DIAGNOSTIC SCRIPT
 Version: 1.0

 Zweck:
   Überprüft den Status von 'wlansvc' (WLAN AutoConfig) 
   und 'wcncsvc' (Windows Connect Now), um die korrekte
   Funktion der automatischen WLAN-Verbindung zu bestätigen.
============================================================
#>

Clear-Host
Write-Host "============================================================" -ForegroundColor DarkCyan
Write-Host "         WLAN DIENSTE-STATUS DIAGNOSE" -ForegroundColor Cyan
Write-Host "============================================================" -ForegroundColor DarkCyan
Write-Host ""

# 1. Hauptdienst für automatische WLAN-Verbindungen prüfen
try {
    $WlanSvc = Get-Service -Name "wlansvc" -ErrorAction Stop
    Write-Host "[1] WLAN AutoConfig (wlansvc) - Hauptdienst:" -ForegroundColor White
    Write-Host "    Status:    $($WlanSvc.Status)" -ForegroundColor Green
    Write-Host "    Starttyp:  $($WlanSvc.StartType)" -ForegroundColor Green
    
    if ($WlanSvc.Status -eq "Running") {
        Write-Host "    -> ERFOLG: Automatische WLAN-Verbindungen funktionieren einwandfrei." -ForegroundColor Green
    } else {
        Write-Host "    -> WARNUNG: Der Hauptdienst läuft nicht!" -ForegroundColor Red
    }
} catch {
    Write-Host " [ FEHLER ] Dienst 'wlansvc' konnte nicht abgefragt werden." -ForegroundColor Red
}

Write-Host ""

# 2. Deaktivierten Connect Now Dienst prüfen
try {
    $WcnSvc = Get-Service -Name "wcncsvc" -ErrorAction Stop
    Write-Host "[2] Windows Connect Now (wcncsvc) - Beacon/WPS-Dienst:" -ForegroundColor White
    Write-Host "    Status:    $($WcnSvc.Status)" -ForegroundColor Yellow
    Write-Host "    Starttyp:  $($WcnSvc.StartType)" -ForegroundColor Yellow
    
    if ($WcnSvc.StartType -eq "Disabled") {
        Write-Host "    -> ERFOLG: Fremde WLAN-Beacons/Geräte werden im Explorer unterdrückt." -ForegroundColor Green
    }
} catch {
    Write-Host " [ FEHLER ] Dienst 'wcncsvc' konnte nicht abgefragt werden." -ForegroundColor Red
}

Write-Host ""
Write-Host "============================================================" -ForegroundColor DarkCyan

Einzeiler zur direkten Deaktivierung von Windows Connect Now:

PowerShell
 
Stop-Service -Name "wcncsvc" -Force
Set-Service -Name "wcncsvc" -StartupType Disabled

Fazit: Mindestmaß an Sicherheit ohne Daueraufwand

Nach einer Inplace-Reparatur ist das System zwar wieder frei von Softwarefehlern, aber eben auch ungeschützt bezüglich Telemetrie und überflüssiger Netzwerkdienste.

Mit dieser Skript-Sammlung lässt sich das Re-Härten nach BSI-Vorgaben innerhalb weniger Sekunden automatisieren. Auch Herstellersoftware wie die von Killer Network verliert ihren Schrecken, da der reine Treiber erhalten bleibt, während die leistungsmindernden Dienste dauerhaft deaktiviert werden.


Das Skript wurde mit Hilfe von Chat GPT und Gemini Geprüft. Beitragsbild ist mit Gemini Generiert.