Lüfter dreht auf? CPU-Fresser unter Windows mit PowerShell finden

Der CPU-Fresser ist der Prozess, der gerade die meiste Rechenzeit verbraucht — nicht der, der seit dem Start die meiste verbraucht hat. Wenn der Lüfter plötzlich aufdreht, belegen meist ein oder mehrere Prozesse dauerhaft Kerne: vergessene Skripte, hängende Hintergrunddienste oder eingefrorene Renderer. Mit drei PowerShell-Schritten findest du heraus, welcher Prozess es ist, wie lange er läuft und wer ihn gestartet hat.

Stand: 16. Oktober 2026. Getestet mit Windows PowerShell 5.1 und PowerShell 7.6 unter Windows 11.

Diagnose-Ablauf in drei Schritten: Last messen, Herkunft klären, Prozess beenden Vier Kästen von links nach rechts: Lüfter dreht auf (CPU-Last vermutet), Schritt 1 Last messen (Prozent und Laufzeit), Schritt 2 Herkunft klären (Startbefehl und Elternprozess), Schritt 3 Prozess beenden (nur wenn er hängt). Lüfter dreht auf CPU-Last vermutet 1 Last messen Prozent und Laufzeit 2 Herkunft klären Startbefehl, Eltern 3 Prozess beenden nur wenn er hängt
Abbildung 1: Der Ablauf im Überblick. Wird der Prozess regulär gebraucht, endet die Diagnose nach Schritt 2.

Warum zeigt Get-Process den falschen Prozess?

Weil die Spalte CPU von Get-Process die aufsummierte Rechenzeit seit dem Start des Prozesses in Sekunden enthält, nicht die aktuelle Last. Ein Browser, der seit Tagen läuft, steht deshalb oben, obwohl er gerade nichts tut. Die aktuelle Auslastung in Prozent liefert die WMI-Klasse Win32_PerfFormattedData_PerfProc_Process.

Get-Process im Vergleich zur CIM-Abfrage der Performance-Daten Get-Process zeigt die Summe der Rechenzeit seit dem Start und sortiert deshalb Dauerläufer nach oben. Die CIM-Abfrage der Performance-Daten zeigt die Auslastung in Prozent zum Messzeitpunkt, liefert die Laufzeit gleich mit und nennt so den aktuellen Verursacher. Get-Process CPU = Sekunden seit Start Sortierung nach Gesamtzeit Dauerläufer steht oben CIM-Abfrage (PerfProc) Auslastung jetzt in Prozent Laufzeit gleich mit dabei zeigt den aktuellen Verursacher
Abbildung 2: Gesamte Rechenzeit seit dem Start (links) und Last zum Messzeitpunkt (rechts) beantworten verschiedene Fragen.

Schritt 1: Wie listest du die CPU-Fresser mit Laufzeit auf?

Mit einer einzigen Abfrage auf Win32_PerfFormattedData_PerfProc_Process: Sie liefert je Prozess die aktuelle Auslastung in Prozent, den privaten Arbeitsspeicher und die Laufzeit in Sekunden. Der Befehl filtert Gesamtsumme und Leerlauf heraus, sortiert absteigend nach Last und zeigt die ersten 15 Prozesse mit der Laufzeit als Tage.Stunden:Minuten:Sekunden.

Get-CimInstance Win32_PerfFormattedData_PerfProc_Process |
  Where-Object { $_.Name -notmatch '^(_Total|Idle)$' -and $_.PercentProcessorTime -gt 0 } |
  Sort-Object PercentProcessorTime -Descending |
  Select-Object -First 15 `
    Name,
    IDProcess,
    @{N="CPU_%";    E={$_.PercentProcessorTime}},
    @{N="RAM_MB";   E={[math]::Round($_.WorkingSetPrivate / 1MB, 1)}},
    @{N="Laufzeit"; E={[TimeSpan]::FromSeconds($_.ElapsedTime).ToString("dd\.hh\:mm\:ss")}} |
  Format-Table -AutoSize

Die Beispielausgabe stammt von einem Entwicklungsrechner (Oktober 2026), gekürzt auf fünf Zeilen:

Name                          IDProcess CPU_% RAM_MB Laufzeit
----                          --------- ----- ------ --------
python#1                          46856   100   3,10 00.16:21:03
python#2                          24388    97   3,20 00.13:30:18
Code#27                           16148    97 410,90 00.15:13:34
IntelGraphicsSoftware.Service      7040    97  41,30 02.22:14:10
svchost#72                        11156    72  15,00 02.22:15:09

Beide python-Prozesse laufen hier seit mehr als 13 Stunden und belegen aktuell jeweils einen vollen Kern, bei nur gut 3 MB privatem Speicher.

Spalte Bedeutung Worauf achten?
Name Prozessname; #1, #2 trennen mehrere Instanzen Hinter mehreren gleichen Namen stecken oft Unterprozesse.
IDProcess Prozess-ID (PID) Brauchst du für Schritt 2 und Schritt 3.
CPU_% Auslastung bezogen auf einen Kern 100 entspricht einem vollen Kern; mehr als 100 heißt, dass der Prozess mehrere Kerne nutzt.
RAM_MB privater Arbeitsspeicher Sehr wenig Speicher bei voller Last kann auf eine Schleife hindeuten, beweist sie aber nicht.
Laufzeit Tage.Stunden:Minuten:Sekunden seit dem Start Ein Skript, das seit Stunden einen Kern voll belegt, ist verdächtig — außer es soll genau das tun, etwa ein Build, ein Rendering oder ein Backup.

Taucht MsMpEng (die Engine von Microsoft Defender) auf einem Datenbankserver dauerhaft ganz oben auf, helfen angepasste Virenschutz-Ausschlüsse (wäge die Sicherheitsfolgen vorher ab) und ein passender Energieplan; beides steht in Windows unter dem Datenbankserver.

Schritt 2: Wie findest du heraus, wer den Prozess gestartet hat?

Über die Klasse Win32_Process: Sie liefert zu jeder Prozess-ID den Startbefehl (CommandLine), den Startzeitpunkt (CreationDate) und die ID des Elternprozesses (ParentProcessId). Damit siehst du, welches Skript läuft und welches Programm es gestartet hat. Die Abfrage funktioniert in Windows PowerShell 5.1 und in PowerShell 7.

# Die PIDs aus Schritt 1 einsetzen
Get-CimInstance Win32_Process -Filter "ProcessId = 46856 OR ProcessId = 24388" |
  Select-Object ProcessId, Name, ParentProcessId, CreationDate, CommandLine |
  Format-List

Den Elternprozess und dessen Eltern verfolgt diese kleine Funktion bis zur Wurzel (höchstens zehn Ebenen):

function Get-ProcessChain {
    param([Parameter(Mandatory)][int]$ProcessId)
    for ($i = 0; $i -lt 10 -and $ProcessId -gt 0; $i++) {
        $p = Get-CimInstance Win32_Process -Filter "ProcessId = $ProcessId"
        if (-not $p) { break }
        $p | Select-Object ProcessId, Name, CommandLine
        $ProcessId = $p.ParentProcessId
    }
}
Get-ProcessChain 46856 | Format-List
Beispiel einer Prozesskette: bash.exe startet das Python-Startprogramm, dieses startet python.exe mit 100 Prozent CPU, das seit 16 Stunden läuft Drei Prozesse, jeweils vom linken gestartet: bash.exe mit PID 38204, das Startprogramm WindowsApps\python.exe mit PID 52244 und python.exe mit PID 46856, das 100 Prozent CPU belegt und seit 16 Stunden läuft. bash.exe PID 38204 WindowsApps\python.exe PID 52244 python.exe, PID 46856 100 % CPU, läuft 16 Std. startet startet
Abbildung 3: Beispiel einer Prozesskette. Beendet wird der hängende Prozess ganz rechts; das Startprogramm in der Mitte läuft sonst weiter.

Bei einem svchost.exe-Prozess zeigt die Dienstliste, was darin läuft:

Get-CimInstance Win32_Service -Filter "ProcessId = 11156" | Select-Object Name, DisplayName

In PowerShell 7 gibt es eine Kurzform: Get-Process -Id 46856 | Select-Object Id, ProcessName, Parent, CommandLine. Sie liefert in Windows PowerShell 5.1 nur leere Spalten, deshalb steht oben die CIM-Variante.

Schritt 3: Wie beendest du einen hängenden Prozess?

Mit Stop-Process -Id <PID>: Das beendet einen Prozess sofort, ungespeicherte Daten gehen verloren. Beende nur Prozesse, deren Startbefehl du verstanden hast. Probiere den Befehl zuerst mit -WhatIf, er zeigt dann nur das Ziel an. Kindprozesse beendet Windows in der Regel nicht automatisch mit ihrem Elternprozess, sie müssen einzeln oder per Prozessbaum beendet werden.

# Die PID aus Schritt 1 und 2 einsetzen, keine Beispielwerte übernehmen
Stop-Process -Id <PID> -WhatIf   # nur anzeigen, was passieren würde
Stop-Process -Id <PID>           # beenden

# Hängt der Prozess und reagiert nicht: -Force erzwingt das Beenden
Stop-Process -Id <PID> -Force

# Prozess samt Kindprozessen beenden
taskkill /PID <PID> /T /F

Wie hängende Läufe bei Prozessen aussehen, die wochenlang durchlaufen, zeigt Ollama im Dauerbetrieb: sieben Fehler, die wie Modellfehler aussehen. Auf Datenbankservern ist „welcher Prozess verbraucht die Ressourcen?“ der erste Schritt jeder Performance-Analyse, bevor es um Indexstrategien und Abfragen geht, wie sie das Seminar Datenbank-Performance-Tuning behandelt.

Wie rufst du die Abfrage mit einem Kurzbefehl auf?

Du legst die Abfrage aus Schritt 1 als Funktion in dein PowerShell-Profil und gibst ihr einen Alias, etwa ps-top. Danach genügt der Befehl ps-top in jeder neuen Konsole derselben PowerShell-Version. Windows PowerShell 5.1 und PowerShell 7 haben getrennte Profildateien, du musst die Funktion also je Version eintragen; $PROFILE zeigt jeweils auf die Datei des Hosts, in dem du den Befehl eingibst.

Zuerst legst du die Profildatei an, falls sie fehlt, und öffnest sie:

if (-not (Test-Path $PROFILE)) { New-Item -ItemType File -Path $PROFILE -Force | Out-Null }
notepad $PROFILE

Dann fügst du diese Funktion ein und speicherst die Datei:

function Get-TopProcesses {
    param([int]$Top = 15)
    Get-CimInstance Win32_PerfFormattedData_PerfProc_Process |
      Where-Object { $_.Name -notmatch '^(_Total|Idle)$' -and $_.PercentProcessorTime -gt 0 } |
      Sort-Object PercentProcessorTime -Descending |
      Select-Object -First $Top `
        Name,
        IDProcess,
        @{N="CPU_%";    E={$_.PercentProcessorTime}},
        @{N="RAM_MB";   E={[math]::Round($_.WorkingSetPrivate / 1MB, 1)}},
        @{N="Laufzeit"; E={[TimeSpan]::FromSeconds($_.ElapsedTime).ToString("dd\.hh\:mm\:ss")}} |
      Format-Table -AutoSize
}
Set-Alias -Name ps-top -Value Get-TopProcesses

Ab dem nächsten Terminal-Start zeigt ps-top die Top 15 und ps-top 5 die Top 5.

Häufige Fragen

Was bedeutet ein CPU-Wert über 100 Prozent?

Der Wert bezieht sich auf einen Kern: 100 entspricht einem voll ausgelasteten Kern. Nutzt ein Prozess mehrere Threads parallel, kann er bis zur Kernzahl mal 100 erreichen. In einer Messung am 16. Oktober 2026 zeigte ein mehrthreadiger Prozess 285 Prozent.

Warum steht System oder svchost ganz oben?

System (PID 4) ist der Windows-Kernel, svchost.exe hostet Dienste. Beides sind Teile von Windows und keine Kandidaten zum Beenden. Mit Get-CimInstance Win32_Service -Filter "ProcessId = <PID>" siehst du, welcher Dienst in einem svchost-Prozess läuft, und kannst dort die Ursache suchen.

Brauche ich Administratorrechte?

Für Auflistung und Beenden eigener Prozesse nicht. Für Systemdienste und Prozesse anderer Benutzer bleibt der Startbefehl ohne Administratorrechte leer, und Beenden schlägt dort ohne erhöhte Rechte fehl. Starte PowerShell in diesem Fall als Administrator.

Läuft das in Windows PowerShell 5.1 und in PowerShell 7?

Ja, die Schritte 1 und 2 laufen in beiden unverändert, weil sie nur CIM-Abfragen nutzen. Die Eigenschaften Parent und CommandLine von Get-Process gibt es nur in PowerShell 7; in 5.1 sind sie leer.

Ab wann ist ein Prozess mit voller Auslastung verdächtig?

Eine feste Grenze gibt es nicht. Build, Rendering und Backup dürfen stundenlang einen Kern belegen. Verdächtig ist ein Prozess, der lange einen Kern auslastet, ohne Ausgabe oder Fortschritt zu zeigen, und dessen Startbefehl du nicht zuordnen kannst. Prüfe vor dem Beenden immer CommandLine und den Elternprozess.

Verwandte Seminare und Artikel

Im Seminar vertiefen

Wer die Last nicht nur finden, sondern auf Datenbankservern dauerhaft senken will, findet das passende Seminar zur Performance-Analyse; dazu gibt es auch Beratung und Coaching. Das Angebot richtet sich an Unternehmen, Behörden und Selbstständige. Die Anfrage ist unverbindlich und kostenlos; Umfang und Konditionen klären wir danach individuell.

Inhouse-Seminar: Datenbank-Performance-Tuning

Du arbeitest an Indexstrategien, Query-Optimierung und Ausführungsplänen, herstellerübergreifend für PostgreSQL, MySQL und Oracle. Der Schritt davor ist der aus diesem Artikel: erst klären, welcher Prozess die Last verursacht.

Zum Seminar Datenbank-Performance-Tuning

Coaching am Arbeitsplatz

Dauerlast, hängende Prozesse oder ein langsamer Datenbankserver: Wir analysieren das gemeinsam an deinen eigenen Systemen, vor Ort in Köln und Leverkusen sowie bundesweit inhouse oder remote.

Beratung oder Coaching anfragen