Tags: Hyper-V, PowerShell
Neue virtuelle Maschinen lassen sich mit geringem Aufwand einrichten, so dass man sie oft nur für den kurzfristigen Gebrauch erstellt. Anschließend geraten solche VMs leicht in Vergessenheit. Mit PowerShell kann man anzeigen, wann eine VM das letzte Mal ein- oder ausgeschaltet wurde.
Das Problem mit Zombie-VMs besteht nicht nur darin, dass sie weiterhin Ressourcen der virtuellen Infrastruktur blockieren. Nicht minder bedeutsam unter Kostengesichtspunkten sind die Software-Lizenzen, die an solche aufgelassenen virtuellen Maschinen gebunden sind und die für andere Zwecke freigegben werden könnten. Und schließlich können daraus auch Sicherheitsrisiken erwachsen, wenn eine VM nach langer Zeit wieder online geht und wichtige Patches nicht eingespielt wurden.
Zeitangaben in der Konfigurationsdatei
Während der Hyper-V Manager beispielsweise für jede aktive VM anzeigt, wie lange sie schon online ist, gibt das Tool keine Auskunft über den Zeitpunkt, zu dem eine inaktive virtuelle Maschine das letzte Mal gestartet oder heruntergefahren wurde.
Ähnlich ist die Lage bei PowerShell, wo man mit Hilfe von
Get-VM | select Name, Uptime
recht einfach die Uptime aller VMs auf einem Host auslesen kann. Schwieriger kommt man an die Informationen über Statusänderungen wie das Hoch- oder Herunterfahren. Theoretisch könnte man bei ausgeschalteten VMs das Änderungsdatum der Konfigurationsdatei nehmen, weil dieses im laufenden Betrieb ständig aktualisiert wird und so auf das letzte Herunterfahren schließen lässt.
Verlässlicher sind dagegen entsprechende Einträge in der Konfigurationsdatei einer virtuellen Maschine. Diese liegt in den bisherigen Versionen des Microsoft-Hypervisors im XML-Format vor und enthält Elemente mit dem Namen last_powered_on_time und last_powered_off_time.
Informationsbeschaffung mit Hindernissen
Auf den ersten Blick erscheint es trivial, diese Daten auszulesen, ein regulärer Ausdruck sollte dafür reichen. In der Praxis stehen dieser Aufgabe einige Hindernisse im Weg. Zum einen möchte man nicht einzelne Dateinamen eingeben, die aus der recht langen ID der VM bestehen, sondern im Idealfall alle Konfigurationen an allen Speicherorten automatisch finden.
Zum anderen enthält die XML-Datei nicht einfach die lesbaren Datumsangaben für das letzte Ein- und Ausschalten, sondern nur die Zahl der Ticks, die seit dem 1. Januar 1601 vergangen sind. Diesen numerischen Wert gilt es in ein vernünftiges Format zu bringen.
Konfigurationsdateien lokalisieren
Bei der Ortung der VM-Konfigurationen hilft das Cmdlet Get-VM, das Auskunft über die ID und das Verzeichnis gibt, in der die XML-Datei einer VM zu finden ist. Allerdings liegt diese normalweise nicht direkt in diesem Ordner, sondern in einem Verzeichnis unterhalb namens Virtual Machines.
Das folgende Skript liest anschließend alle XML-Konfigurationen in die Variable $XMLConfig ein und extrahiert daraus die Textknoten der Elemente name, last_powered_on_time und last_powered_off_time. Sie werden in einer Hash-Tabelle gespeichert, von wo anschließend eine for-Schleife die Werte entnimmt und die Zeitangaben in ein Datum umrechnet. Zu diesem addiert man eine Stunde hinzu, um die mitteleuropäische Zeit zu erhalten.
function VMLastPowerOn{
$XMLfiles = Get-VM | foreach{$_.ConfigurationLocation + "\Virtual Machines\" + $_.VMID + ".xml"}
$VMConfig = $XMLfiles| foreach{([XML](Get-Content $_))}
[datetime]$d = "01/01/1601 00:00:00"
$VMinfo = @{Name = $VMConfig.configuration.properties.name.'#text'
Ein = $VMConfig.configuration.properties.last_powered_on_time.'#text'
Aus = $VMConfig.configuration.properties.last_powered_off_time.'#text'
}
for ($i=0; $i -lt $XMLfiles.Count ; $i++){
"`n" + $VMinfo.Name[$i]
$d.AddTicks($VMinfo.Ein[$i]).AddHours(1)
$d.AddTicks($VMinfo.Aus[$i]).AddHours(1)
}
}
Die beschriebenen Anweisungen kann man wie hier gezeigt in eine Funktion packen und diese bei Bedarf in das PowerShell-Profil aufnehmen, so dass sie immer zur Verfügung steht.
Varianten des Skripts
Dieses relativ einfache Skript lässt sich natürlich auch erweitern oder variieren. Wenn man beispielsweise aus naheliegenden Gründen nur an VMs interessiert ist, die nicht eingeschaltet sind, dann kann man in der ersten Zeile der Funktion den Aufruf von Get-VM durch eine Statusabfrage ergänzen:
Get-VM | Where state -ne "Running" | foreach …
Möchte man nicht das Datum des letzten Hoch- oder Herunterfahrens angezeigt bekommen, sondern einfach nur die Zahl der Tage, die seitdem vergangen sind, dann ließe sich das so bewerkstelligen:
"Zuletzt eingeschaltet vor: " + (New-TimeSpan -start $d.AddTicks($VMinfo.Ein[$i]) -End (Get-Date)).days + " Tagen"
Diesen Befehl platziert man in den Körper der for-Schleife, wo sie die einfache Datumsumrechnung durch AddTicks ersetzt. Eine entsprechende Variante für das letzte Herunterfahren funktioniert natürlich nach dem gleichen Muster.
Täglich Know-how für IT-Pros mit unserem Newsletter
Verwandte Beiträge
- Virtuelle Maschine vollständig mit PowerShell erstellen (am Beispiel von Azure Stack HCI)
- PowerShell-Remoting, Hyper-V Manager: Fehler wegen Netzwerkverbindungstyp "Öffentlich"
- Hyper-V-Host mit PowerShell (remote) konfigurieren, vSwitch hinzufügen
- Module für Active Directory, Hyper-V, WMI laden in PowerShell Core 6
- DVD-Laufwerke von VMs anzeigen und entfernen, Medien auswerfen
Weitere Links