Bei Projekt Neptun haben wir viele Supporgeräte, die wir bei Garantiefällen oder zur Überbrückung von Lieferzeiten an Kunden ausleihen. Wenn wir dieser zurückerhalten, müssen wir sie zurücksetzen. Die aktuelle Prozedur basiert auf Images, die mit Clonezilla/Parted Magic auf einen Server gespeichert bzw. gelesen werden.
Der Prozess war früher sinnvoll, hat aber mehrere Probleme. Das Image muss auf das Gerät aufgespielt werden, und nachdem Updates getätigt worden sind, wird das Gerät wiederum auf den Server geimaged. Das kann gerade bei älteren Geräten länger dauern. Fehlerquellen beinhalten die Qualität der Verbindung und die Image-Dateinamen, welche von Hand gesetzt werden. Schliesslich ist relativ viel Handarbeit notwendig. Der Prozess zeigte sich ausser Lage, den stetig wachsenden Berg an zurückzusetzenden Geräten mit der begrenzten Zeit der Supportmitarbeiter zu bewältigen.
Demgegenüber dauert ein Windows-Clean Install mit modernen Flash-Speichermedien weniger als 15 Minuten. Wird generell mit Clean Installs gearbeitet, entfällt auch das Imagen auf den Server, was Zeit spart, und die entsprechende Infrastruktur muss nicht mehr unterhalten werden. Mit Powershell und Windows Unattended Install-Konfigurationen kann ein guter Teil der manuellen Arbeit automatisiert werden.
Deshalb war es meine Aufgabe, eine neue Prozedur für das Zurück- und Aufsetzen unserer Supportgeräte zu entwerfen, die auf Powershell und dem Windows Unattended Install basiert. In einem zweiten Schritt habe ich sie implementiert und dokumentiert. Ausserdem sollte ich nach IPERKA vorgehen, um eine strukturierte Herangehensweise zu üben. Während des gesamten Projektes habe ich mit einem Spreadsheet gearbeitet, um die Schritte zu organisieren und zu visualisieren.
Planungsgrundlage waren die Schritte des bestehenden Prozesses. Als Werkzeuge bereits definiert waren der Windows Unattended Install und Powershell. Vorab abgeklärt mussten zwei Aspekte:
Da der Support-Chef abwesend war und ich in Gang kommen wollte, ging ich zu Beginn davon aus, dass wir die Schritte 1:1 in die neue Prozedur übernehmen, das Imagen ausgenommen. Zu Punkt 2 verfolgte ich den Grundsatz, dass so viel wie möglich im Unattended-Verfahren gelöst werden sollte. Was dann übrig bleibt, wird soweit wie möglich via Powershell bearbeitet. Nur, was nicht oder nur sehr aufwändig automatisiert werden kann, sollte dann von Hand besorgt werden müssen.
Auszug aus den ersten Recherchearbeiten
Die Ergebnisse der Recherche habe ich in einer Präsentation gesammelt und vorgetragen.
Bei der Planung traf ich auf Schwierigkeiten:
Die Planung vermengte sich also teilweise mit der Implementation, was wie gesagt teils notwendig, teils übereilt war.
Ich führte aus, mit welchen Werkzeugen die Schritte bewältigt werden können, und verlinkte auf die entsprechenden Stellen in der WSIM- bzw. in der Powershell-Dokumentation. So schuf ich eine Entscheidungsgrundlage beim Testen und genauerer Konsultuierung der Dokumentation, und ich würde mich in Zukunft vermehrt auf das Schreiben des Skripts konzentrieren können. Ausserdem konkretisierte ich die zukünftige Prozedur: Phase I mit Unattended Install, Phase II mit Powershell-Skript (das automatisch beim ersten Start ausgeführt wird), und Phase III mit Handarbeit - vorher war provisorisch ein Ablauf mit zwei Skriptphasen geplant.
Die Planugsmatrix zu Beginn des Arbeitsschritts...
...und gegen Ende des Schritts, mit nur mehr drei Phasen.
Auch beim Entscheiden stiess ich auf ähnliche Problematiken wie beim Planen: Gewisse Entscheidungen (z.B. ob ein Schritt mit zumutbarem Aufwand in Powershell lösbar ist; oder ob ein gefundener Lösungsansatz noch aktuell ist) konnten erst getroffen werden, nachdem ihre Umsetzung zumindest im Ansatz erfolgt war. Auch hier vermengten sich also Entscheidungen und Realisierung.
Es wurden einige Schritte entweder von Phase I nach Phase II oder umgekehrt verschoben, sie wurden in die Phase III verschoben, oder aber sie mussten ganz aus der Prozedur fallen, weil sie mittlerweile ohnehin schon Standard waren oder unter Windows 11 nicht mehr zutrafen.
Ein wichtiges Beispiel für eine Entscheidung, die später wieder revidiert wurde, waren die Firmware- und Treiberupdates für HP-Geräte. Zu diesem Zeitpunkt hatte ich mich auf die Lösung festgelegt, auf automatischem Wege den HP Support Assistant zu installieren und die Updates später in Handarbeit durchzuführen, da die Client Management Script Library von HP nicht richtig zu funktonieren schien. Durch einen Tip des Supportchefs gelang es mir aber später (schon bei Schritt RK), einen grossen Teil dieser Updates dennoch in Phase II mit einem anderen HP-Tool durchzuführen und die Handarbeitsphase somit zu verkürzen.
Ich habe hier die Schritte «Realisieren» und «Kontrollieren» zusammengenommen, da ich mich hier (wie bei Entwicklungsarbeiten wohl üblich) in einem konstanten Kreislauf befand: Implementationen mussten laufend getestet, dann angepasst und/oder gefixt werden. Dies geschah teilweise in PowerShell ISE, teilweise musste der gesamte Installationsprozess mit einem Testgerät durchlaufen werden.
Den Fortschritt hielt ich laufend in einer neuen Tabelle fest, an der ich kontrollieren und nachführen konnte, was schon implementiert wurde:
Stand der Tabelle nach der Ausführung
Bei den Testläufen traten zahlreiche Fehler auf und es dauerte eine ganze Weile, bis das Script in einem ersten brauchbaren Zustand war. Dies war sicher meiner mangelnden Erfahrung mit Powershell geschuldet, zudem begann ich erst nach einer ganzen Weile, überhaupt einen Linter zu verwenden. Umso grösser war dann das Erfolgserlebnis, nachdem der Prozess erfolgreich abschloss.
Einerseits konnte mich die IPERKA-Methode, bzw. das Planen überhaupt, sehr überzeugen: Ich konnte mich konzentriert und zielgerichtet an die Arbeit machen und eine Pendenz nach der anderen abhaken, was sehr befriedigend war. Anderserseits zeigte sich wieder einmal, dass ich mehr vorausdenken und mir den späteren Rewrite hätte ersparen können - wobei man hier einräumen muss, dass die erste Implementation trotzdem sehr nützlich war, um erste Kenntnisse mit Powershell zu sammeln; ich war da immerhin Laie.
In der ersten Version der Implementierung basierte die ganze Phase II auf einem einzelnen Powershell-Skript, welches alles aufs Mal erledigte. Es verfügte über keine Funktionsdefinitionen und war dadurch unübersichtlich. Modifikationen waren relativ aufwendig vorzunehmen und konnten somit auch Fehler mit sich ziehen. Auch die Dokumentation führte ich nur mit einiger Verspätung.
# Disable progressbar because it obscures terminal output
$ProgressPreference = "SilentlyContinue"
# Read key from UEFI and activate Windows
Write-Output "Activating Windows..."
$service = get-wmiObject -query 'select * from SoftwareLicensingService'
$key = $service.OA3xOriginalProductKey
$service.InstallProductKey($key) >> "C:\Users\Neptun\Documents\unattend.log"
# Install winget (should already be installed according to MS, but isn't >:()
Write-Output "Installing winget package manager..."
Add-AppxPackage "D:\NepResources\winget.msixbundle" 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
# Install NuGet - required for installing PS modules
Write-Output "Installing NuGet PowerShell module manager..."
Install-PackageProvider -Name NuGet -Force 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
# "mount" HKEY_USERS as a PSDrive so we can work with it
# then add reg key for disabling sharing of updates over network
# will oftentimes fail as set by default
Write-Output "Changing registry setting for network-shared updates..."
New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
New-ItemProperty -Path "HKU:\S-1-5-20\Software\Microsoft\Windows\CurrentVersion\DeliveryOptimization\Settings\" -Name "DownloadMode" -PropertyType DWord -Value 0 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
# copy wallpaper to documents and set wallpaper
Write-Output "Copying and changing wallpaper..."
Copy-Item D:\NepResources\wallpaper.png C:\Users\Neptun\Documents\ 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
Set-ItemProperty -Path "HKCU:\Control Panel\Desktop\" -Name WallPaper -Value "C:\Users\Neptun\Documents\wallpaper.png" 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
# Install auxilliary software
Write-Output "Installing Foxit Reader..."
winget install Foxit.FoxitReader -h --accept-package-agreements --accept-source-agreements 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
Write-Output "Installing Thunderbird..."
winget install Mozilla.Thunderbird --accept-package-agreements --accept-source-agreements 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
Write-Output "Installing Firefox..."
winget install Mozilla.Firefox -h --accept-package-agreements --accept-source-agreements 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
Write-Output "Installing LibreOffice..."
winget install TheDocumentFoundation.LibreOffice -h --accept-package-agreements --accept-source-agreements 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
Write-Output "Installing 7-Zip..."
winget install 7zip.7zip -h --accept-package-agreements --accept-source-agreements 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
# Check if touch device, if yes, install Drawboard PDF
# NOTE: Depends on locale!
$sysinfo = Get-PnpDevice
if($sysinfo.FriendlyName.Contains("HID-konformer Touchscreen" -or "HID-conforming touchscreen" -or "Écran tactile compatible HID")) {
Write-Output "Touchscreen detected - installing Drawboard PDF..."
winget install "Drawboard PDF" -h --accept-package-agreements --accept-source-agreements 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
} else {
Write-Output "No touchscreen detected - skipping Drawboard PDF..."
}
# Execute MS Store updates
Write-Output "Updating MS Store applications..."
winget upgrade -h --all 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
# find out if device is LENOVO or HP and install appropriate software
# NOTE: LCVa uses winget, HPSA reliant on .exe on install drive
Write-Output "Checking for manufacturer and installing firmware/driver update tools..."
$manufacturer = Get-ComputerInfo -Property "CsManufacturer"
switch($manufacturer) {
"LENOVO" {
Write-Output "Lenovo system detected."
Write-Output "Installing Lenovo Commercial Vantage..."
winget install --accept-source-agreements --accept-package-agreements "Commercial Vantage" 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
}
"HP" {
Write-Output "HP system detected."
Write-Output "Installing HP Support Assistant..."
Invoke-Expression -Command "D:\NepResources\HPSA.exe /s"
}
"DELL" {
Write-Output "Dell system detected."
Write-Output "Installing Dell Command | Update..."
winget install --accept-source-agreements --accept-package-agreements Dell.CommandUpdate.Universal 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
}
"Microsoft Corporation" {
Write-Output "Microsoft system detected. Will update via MS Store and Windows updates."
}
Default {
Write-Output "Manufacturer identification failed. No action taken."
}
}
# Install manufacturer updates
# NOTE: Only Lenovo automated.
# NOTE: Only Lenovo updates with unattended installation are installed
switch($manufacturer) {
"LENOVO" {
Write-Output "Installing LSUClient and getting Lenovo updates..."
Install-Module -Name "LSUClient" -Force 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
Import-Module LSUClient
$updates = Get-LSUpdate | Where-Object { $_.Installer.Unattended }
Write-Output "Downloading Lenovo updates..."
$updates | Save-LSUpdate 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
Write-Output "Installing Lenovo updates..."
$updates | Install-LSUpdate
}
"HP" {
Write-Output "Skipping HP updates - remember to check manually!"
}
"DELL" {
Write-Output "Skipping Dell updates - remember to check manually!"
}
"Microsoft Corporation" {
Write-Output "Microsoft system detected. Will update via MS Store and Windows updates."
}
Default {
Write-Output "Identification failed. No driver/firmware updates applied automatically."
}
}
# First we re-enable progress bar, as it comforts us
# Add service for optional updates
# Then install PSWindowsUpdate, import module and execute Windows updates
# Then reset execution policy and reboot
$ProgressPreference = "Continue"
Write-Output "Installing and importing PSWindowsUpdate..."
Install-Module -Name PSWindowsUpdate -Force 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
Import-Module PSWindowsUpdate
Add-WUServiceManager -ServiceID "7971f918-a847-4430-9279-4a52d1efe18d" -confirm:$false 1>>"C:\Users\Neptun\Documents\unattend.log"
Write-Output "Querying Windows updates..."
Get-WindowsUpdate 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
Write-Output "Downloading and installing Windows updates, this will take a while. System will autoreboot!"
Install-WindowsUpdate -AcceptAll -AutoReboot 1>>"C:\Users\Neptun\Documents\unattend.log" 2>>"C:\Users\Neptun\Documents\unattenderror.log"
Write-Output "Resetting Execution Policy..."
Set-ExecutionPolicy Default
Der Supportchef und mein Ausbildner waren noch immer in den Ferien oder krank, weshalb die Aufgabe grossteils mir allein zufiel. Ich stellte mehrere Problematiken mit meinem Script fest:
Durch die Entwicklung dieser ersten Version hatte ich Einblicke und Erfahrungen gewonnen, es war aber Zeit für einen grundlegenden Rewrite, um die oben genannten Probleme anzugehen. Für die nächte Revision sollten folgende Grundsätze gelten:
Auf diese Prinzipien gestützt startete ich in die zweite Projektphase. Ihre Entwicklung wird im nächsten Eintrag besprochen.