PowerShell-Scripte für die schnelle Bereitstellung von aktuell gepatchten Installationsmedien von Window 10 Build 1909. Die Formate .WIM und .ISO sind teils Microsoft- und teils allgemeinspezifisch.
Ziel #1 - Erstellen einer aktuell gepatchten Windows 10-Ausgabe
Ausgangslage: IT-Profressionals stehen möglicherweise vor der Aufgabe, das Client-Betriebssystem Windows 10 laufend auf einem aktuell gepatchten Level zu bringen oder zumindest ein sogenanntes "Referenz-Image" zyklisch auf die Endgeräte "auszurollen". Monatlich erscheinen für Windows 10 Sicherheitsverbesserungen und Stabilitätsupdates (siehe Update-Verlauf). Diese müssen aufgrund von Compliance-Richtlinien (ISO 27001, NIST, STIG, BSI) sowie aus regulatorischen Gründen (DS-GVO, UGB etc.) in Organisationen, Behörden, Konzernen, Vereinen etc. angewendet werden. Das Update-Prozedere kontinuierlich (PDCA) zu servicieren, fällt aufgrund der Komplexität vielen Akteuren nicht leicht - angesichts der täglichen vielen Routinen und Projekt-Paketen von IT-Verantwortlichen. Ansätze zur Semi- oder Vollautomatisierung sind gefragt. Eine Semi-Automatisierung, wie die folgenden PowerShell-Scripte, unterstützt bei der Reduzierung der Komplexität, damit ein kontinuierlichen Patch-Management von Microsoft Windows-10-Betriebssystemen gewährleistet werden kann.
Vorteile der scriptbasierten Variante
Transparenz, keine Kosten: Quelloffen, frei verfügbar und skalierbar für Endanwender.
Standard: Abbilder werden zu 100-Prozent-Hersteller-Empfehlung und der Erfahrung der Authoren wie Johan Arwidmark und Alexander Scharmer "lege artis" erzeugt.
Aktualität: Die aktuellsten SSU- und LCU-Updates werden automatisch - mit Unterstützung des PowerShell-Moduls OSDSUS/OSDUpdate von David Segura - direkt Online von der Microsoft Update-Cataloge-Site bezogen und integriert.
Optimiert "Small Footprint": Die Abbilder sind nach den Richtlinien des Herstellers und der WIM-Technologie auf geringen "Overhead" und kleinen Dateigrößen optimiert.
Simplifiziert: Das PowerShell-Script Create-W10RefImagev1909.ps1 ist nur auf das notwendigste reduziert, um ein natürliches und aktuelles Windows 10 Image zu erzeugen. Es verändert keine kritischen Komponenten oder ersetzt diese. Es werden auch keine unnötigen Dienste oder Services aktiviert oder deaktiviert.
Voraussetzungen
Es wird eine Verbindung zum Internet benötigt. Das Herunterladen der PowerShell-Module sowie der Software-Patches erfolgt auf Ressourcen in der Cloud. Stellen Sie deshalb eine Internet-Konnektivität sicher.
Der PowerShell-Oneliner meldet die erfolgreiche Internet-Konnektivität zurück:
if (Test-Connection -Count 1 -Quiet 1.1.1.1) {Write-Output "Internet-Konnektivität erfolgreich hergestellt."}
Benutzen Sie eine Privileged Access Workstations (PAWs), wo Sie administrative Rechte besitzen um Programm-Installationen vornehmen zu können. Dies kann ein Notebook, ein Desktop-PC oder sonstiges Endgerät mit Windows 10 Home, Pro, Education, Enterprise (in deutscher Sprachvariante) sein.
Bereitstellungsumgebung für Offline-Patchen einrichten
Benutzen Sie nachfolgendes PowerShell-Script mit der Bezeichnung Install-SetupDeploymentv1909.ps1für die initiale Bereitstellung für das Offline-Patchen von Windows 10. Die Erstkonfiguration erstellt neben der Ordnerstruktur C:\SetupDeployment ebenfalls die Installation der Microsoft Windows ADK-Tools in der Version 1903.
Folgende Komponenten umfasst die Script-Installation auf dem PAW-Endgerät
Windows Assessment Toolkit and the Windows Performance Toolkit to assess the quality and performance of systems or components.
Deployment tools such as WinPE, Sysprep, and other tools that you can use to customize and deploy Windows 10 images.
Windows Preinstallation Environment (PE).
Download the Windows System Image Manager (WSIM) 1903 update(fix).
Empfehlung für den korrekten Aufruf des PS Install-SetupDeploymentv1909.ps1 ist:
powershell -ex bypass -co <pfad zum PS Script Install-SetupDeploymentv1909.ps1>
Die obige Befehlszeile in einer privilegierten Kommandozeile (CMD) unter Windows 10 aufrufen (z. B. als Administrator).
Nach dem Aufruf mit privilegierten Berechtigungen wird die Installation aller Komponenten automatisch durchgeführt. Dies kann je nach Ressourcen bzw. Leistung des Endgerätes zwischen 15 und 45 Minuten dauern - bitte haben Sie hier etwas Geduld.
Source-Code des Scripts Install-SetupDeploymentv1909.ps1
Install-SetupDeploymentv1909.ps1
# Check for elevationIf (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(` [Security.Principal.WindowsBuiltInRole] "Administrator")){ Write-Warning "Oupps, you need to run this script from an elevated PowerShell prompt!`nPlease start the PowerShell prompt as an Administrator and re-run the script."
Write-Warning "Aborting script..."Break}# Our Deployment Folder Structure $deploy_dir = "$env:HOMEDRIVE\SetupDeployment" $deploy_DismPath = "$env:HOMEDRIVE\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\DISM"
$deploy_OscdImgPath = "$env:HOMEDRIVE\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg"
$deploy_src = "$deploy_dir\src" $deploy_drivers = "$deploy_dir\src\drivers" $deploy_ADKOffline = "$deploy_dir\src\ADKOffline" $deploy_ADKWinPeOffline = "$deploy_dir\src\ADKWinPeOffline"# $deploy_UpdatesDir = "$deploy_dir\src\Updates" $deploy_logs = "$deploy_dir\logs" $deploy_build = "$deploy_dir\build" $deploy_mount = "$deploy_dir\build\mount" $deploy_iso = "$deploy_dir\ISO" $deploy_tmp = "$deploy_dir\tmp" $deploy_WSIMUpdate = "$deploy_dir\src\WSIM1903Update"if (!(Test-Path-path $deploy_dir)) {New-Item $deploy_dir -TypeDirectory}if (!(Test-Path-path $deploy_src)) {New-Item $deploy_src -TypeDirectory}if (!(Test-Path-path $deploy_drivers)) {New-Item $deploy_drivers -TypeDirectory}if (!(Test-Path-path $deploy_ADKOffline)) {New-Item $deploy_ADKOffline -TypeDirectory}if (!(Test-Path-path $deploy_ADKWinPeOffline)) {New-Item $deploy_ADKWinPeOffline -TypeDirectory}# if (!(Test-Path -path $deploy_UpdatesDir)) {New-Item $deploy_UpdatesDir -Type Directory}# if (!(Test-Path -path $deploy_UpdatesDirLCU)) {New-Item $deploy_UpdatesDirLCU -Type Directory}# if (!(Test-Path -path $deploy_UpdatesDirSSU)) {New-Item $deploy_UpdatesDirSSU -Type Directory}if (!(Test-Path-path $deploy_WSIMUpdate)) {New-Item $deploy_WSIMUpdate -TypeDirectory}if (!(Test-Path-path $deploy_logs)) {New-Item $deploy_logs -TypeDirectory}if (!(Test-Path-path $deploy_build)) {New-Item $deploy_build -TypeDirectory}if (!(Test-Path-path $deploy_mount)) {New-Item $deploy_mount -TypeDirectory}if (!(Test-Path-path $deploy_tmp)) {New-Item $deploy_tmp -TypeDirectory}if (!(Test-Path-path $deploy_iso)) {New-Item $deploy_iso -TypeDirectory}# A Windows ADK for Windows 10, version 1909 will not be released. You can use the Windows ADK for Windows 10, version 1903 to deploy Windows 10, version 1909.
# https://docs.microsoft.com/en-us/windows-hardware/get-started/adk-install# ADK Version 1903 Url and Install Options# https://docs.microsoft.com/en-us/windows-hardware/get-started/adk-install $adk_url = 'https://download.microsoft.com/download/B/E/6/BE63E3A5-5D1C-43E7-9875-DFA2B301EC70/adk/adksetup.exe'
$adk_file = 'adksetup.exe' $adk_features = '*' # https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-8.1-and-8/dn621910(v=win.10)
$adk_install_log = "$deploy_logs\adksetup.log" $adk_reg_key = "HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{fb450356-9879-4b2e-8dc9-282709286661}"
$adk_winPeUrl = "https://download.microsoft.com/download/E/F/A/EFA17CF0-7140-4E92-AC0A-D89366EBD79E/adkwinpeaddons/adkwinpesetup.exe"
$adk_winPeFile = "adkwinpesetup.exe" $mdt_reg_key = "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\{2E6CD7B9-9D00-4B04-882F-E6971BC9A763}"
$mdt_fileURL = "https://download.microsoft.com/download/3/3/9/339BE62D-B4B8-4956-B58D-73C4685FC492/MicrosoftDeploymentToolkit_x64.msi"
$mdt_fileName = "MicrosoftDeploymentToolkit_x64.msi" $adk_WinPeInstall_log= "C:\SetupDeployment\logs\ADKWinPEInstallation.log"Add-Type-AssemblyName "system.io.compression.filesystem"Start-Sleep-Seconds2if(-not (Test-Path -Path $adk_reg_key)){# Offline Download ADK# $downADK = (New-Object System.Net.WebClient).DownloadFile($adk_url,"$deploy_src\$adk_file")# Invoke-WebRequest -uri $adk_url -OutFile $deploy_src\$adk_file -PassThru -VerboseWrite-Host "`nDownloadvon $adk_url erfolgt..." -ForeGroundColor Green Start-BitsTransfer -Source $adk_url -Destination "$deploy_src\$adk_file" Write-Host "`nInstallation von $deploy_src\$adk_file erfolgt ..." -ForeGroundColorGreen Start-Process -FilePath "$deploy_src\$adk_file" -ArgumentList "/quiet /layout $deploy_ADKOffline /log `"$adk_install_log`"" -wait -Verbose
[System.GC]::Collect()# Offline Download WinPE-ADK# $downADKPE = (New-Object System.Net.WebClient).DownloadFile($adk_winPeUrl,"$deploy_src\$adk_winPeFile")# Invoke-WebRequest -UseBasicParsing -uri $adk_winPeUrl -OutFile $deploy_src\$adk_winPeFile -PassThru -VerboseWrite-Host "`nDownloadvon $adk_winPeUrl erfolgt..." -ForeGroundColor Green Start-BitsTransfer -Source $adk_winPeUrl -Destination "$deploy_src\$adk_winPeFile" Write-Host "`nInstallation von $deploy_src\$adk_winPeFile erfolgt ..." -ForeGroundColorGreen Start-Process -FilePath "$deploy_src\$adk_winPeFile" -ArgumentList "/quiet /layout $deploy_ADKWinPeOffline /log `"$adk_WinPeInstall_log`"" -wait -Verbose
[System.GC]::Collect()# Install ADK Offline-RepositoryWrite-Host "`nInstallationvonWindowsADKerfolgt..." -ForeGroundColor Green Start-Process -FilePath "$deploy_ADKOffline\$adk_file" -ArgumentList "/quiet /norestart /log `"$adk_install_log`"" -wait -PassThru -Verbose
# Install WinPE Offline-Repository Write-Host "`nInstallation von Windows PE erfolgt ..." -ForeGroundColorGreen Start-Process -FilePath "$deploy_ADKWinPeOffline\$adk_winPeFile" -ArgumentList "/quiet /norestart /log `"$adk_WinPeInstall_log`"" -wait -PassThru -Verbose
# Download and Install the Windows System Image Manager (WSIM) 1903 update $WSIMUpdateURL = "https://download.microsoft.com/download/4/0/F/40FD29FC-0E6D-46D0-8F7E-B033110D07D5/WSIM1903.zip"Write-Host "`nDownloadvonWindowsSystemImageManager (WSIM) 1903 update erfolgt ..." -ForeGroundColor Green Start-BitsTransfer -Source $WSIMUpdateURL -Destination "$deploy_src\WSIM1903Update\WSIM1903.zip" [io.compression.zipfile]::ExtractToDirectory("$deploy_src\WSIM1903Update\WSIM1903.zip", "$deploy_src/WSIM1903Update/") | Out-Null
Write-Host "`nInstallation von Windows System Image Manager (WSIM) 1903 update erfolgt ..." -ForeGroundColorGreen Start-Process -FilePath "cmd.exe" -ArgumentList "/c $deploy_src\WSIM1903Update\UpdateWSIM.bat" -WindowStyle Hidden -WorkingDirectory "$deploy_src/WSIM1903Update/" -PassThru -Wait
}# Install MDT 8456if(-not (Test-Path -Path $mdt_reg_key)) {Write-Host "`nDownloadvon $mdt_fileName erfolgt..." -ForeGroundColor Green Start-BitsTransfer -Source $mdt_fileURL -Destination "$deploy_src\$mdt_fileName" # Invoke-WebRequest -UseBasicParsing -uri $mdt_fileURL -OutFile $deploy_src\$mdt_fileName -PassThru -Verbose Write-Host "`nInstallation von $deploy_src\$mdt_fileName erfolgt ..." -ForeGroundColorGreen Start-Process -FilePath "$deploy_src\$mdt_fileName" -ArgumentList "/passive /norestart /L*V `"$deploy_logs\mdt_install.log`"" -wait -PassThru -Verbose
# Download and extract Sysinternals $SysinternalsURL = "https://download.sysinternals.com/files/SysinternalsSuite.zip"Write-Host "`nDownloadvon $SysinternalsURL erfolgt..." -ForeGroundColor Green Start-BitsTransfer -Source $SysinternalsURL -Destination "$deploy_src\Sysinternals.zip" Write-Host "`nEntpacken von $deploy_src\Sysinternals.zip erfolgt ..." -ForeGroundColorGreen [io.compression.zipfile]::ExtractToDirectory("$deploy_src\Sysinternals.zip", "$deploy_src/Sysinternals")}# Check if SSU OR LCU exists else get it# if ((Get-ChildItem $deploy_UpdatesDirSSU -Filter *.msu | measure).Count -eq 0 `# -OR (Get-ChildItem $deploy_UpdatesDirLCU -Filter *.msu | measure).Count -eq 0) {# Import DISM modules from Windows 10 ADKImport-Module $deploy_DismPath -Force# Global Variables&setx/M "PATH" "$ENV:PATH;$deploy_DismPath"# Get Latest Updates Windows 10 Version 1903# https://docs.stealthpuppy.com/docs/latestupdate/usage/get-stack# Install-PackageProvider -Name NuGet -Force -Confirm:$false# Install-Module -Name LatestUpdate -Force -Confirm:$false -AllowClobber# Import-Module -Name LatestUpdate -Force -PassThru# SSU# Get-LatestServicingStackUpdate -OperatingSystem Windows10 -Version 1903 | `# Where-Object { $_.Architecture -eq "x64" -and $_.Note -notmatch "Server"} | `# Save-LatestUpdate -Path $deploy_UpdatesDirSSU# LCU# Get-LatestCumulativeUpdate -OperatingSystem Windows10 -Version 1903 | `# Where-Object { $_.Architecture -eq "x64" -and $_.Note -notmatch "Server"} | `# Save-LatestUpdate -Path $deploy_UpdatesDirLCU# Unblock Files# Get-ChildItem -Path $deploy_UpdatesDir -Filter *.msu -Recurse -Force | Unblock-File# }# Fix NTFS-permission&icacls $deploy_dir /c/t/q/reset|Out-Null# Fix MDT DeploymentShare permissions# https://deploymentresearch.com/fixing-mdt-2013-update-1-deployment-share-permissions-using-powershell/# ------------------------------------------------------------------------------------------
Video-Sequenz zum Ablauf des ersten Scripts.
Windows-Medien mit aktuellen SSU und LCU erstellen
Das PowerShell-Script Create-W10RefImagev1909.ps1 erstellt nach Durchlauf die aktuell gepatchte Windows-10-Version 1909 inklusive dem Feature .NET-Framework 2.0-3.5. Die Besonderheit ist die Reihenfolge in dem das Referenz-Image erstellt wird. Dies ist ein Abbild einer etablierten Herstellung eines sogenannten "Referenz"-Image wie es von Microsoft empfohlen wird.
1) Kopieren Sie das Script Create-W10RefImagev1909.ps1 innherhalb des Ordners C:\SetupDeployment\
Folgende Änderungen sollten Sie vor dem ersten Aufruf ggf. vornehmen:
$ISO = [System.IO.Path]::Combine("$RootDir\ISO","<Name der ISO-Datei.iso>")
Kopieren Sie also vor dem Aufrufen des PowerShell-Scripts ihre gewünschte ISO-Datei in den Ordner C:\SetupDeployment\ISO und halten Sie den Namen durch die Änderung der Variable $ISO im Script fest. Ansonsten erscheint das folgende Dialogfenster und bittet Sie um Angabe eines ISO-Abbildes um erfolgreich fortzusetzen zu können.
Ausführen des Scripts unter privilegierten Benutzerrechten:
2) powershell -ex bypass -co <pfad zum Script Create-W10RefImagev1909.ps1>
SSU = Servicing Stack-updates/Wartungsstapel: SSUs verbessern die Zuverlässigkeit des Updatevorgangs. Dadurch wird das Risiko potenzieller Probleme beim Installieren des LCU und beim Anwenden von Microsoft-Sicherheitsfixes reduziert. Beim Warten auf Stack-Updates werden Korrekturen für den Wartungsstapel, die Komponente, die Windows-Updates installiert, bereitgestellt. Darüber hinaus enthält Sie den "komponentenbasierten Servicing Stack" (CBS), der eine wichtige zugrunde liegende Komponente für verschiedene Elemente der Windows-Bereitstellung ist, wie DISM, SFC, Ändern von Windows-Features oder-Rollen sowie Reparieren von Komponenten. Das CBS ist eine kleine Komponente, in der in der Regel keine Updates monatlich veröffentlicht werden.
LCU = Latest Cumulative Update: A tested, cumulative set of updates. They include both security and reliability updates that are packaged together and distributed over Windows Update, WSUS, System Center Configuration Manager and Microsoft Update Catalog for easy deployment. The Monthly Rollup is product specific, addresses both new security issues and nonsecurity issues in a single update and will proactively include updates that were released in the past. Security vulnerabilities are rated by their severity. The severity rating is indicated in the Microsoft security bulletin as critical, important, moderate, or low. This Monthly Rollup would be displayed under the title Security Monthly Quality Rollup when you download or install. This Monthly Rollup will be classified as an "Important" update on Windows Update and will automatically download and install if your Windows Update settings are configured to automatically download and install Important updates.
Why does a Windows 10 Cumulative Update Install Twice?
Wenn ein kumulatives Update (LCU) zweimal installiert wird, können Sie die Hintergründe hier in diesem Artikel recherchieren.
Empfohlene Reihenfolge beim Offline-Service-Management
Das Script unterstützt die folgende Hersteller-Empfehlung in den folgenden Punkten:
Source Code Create-W10RefImagev1909.ps1
Create-W10RefImagev1909.ps1
<#.SYNOPSISDiesesScripterstellteineaktuellgepatchteISO-Installations-undWIM-DateivonWindows101909.FühredasScriptunterprivilegiertenBenutzerrechten (Administrator) aus um einen einwandfreienBetriebderFunktionenzugewährleisten!.DESCRIPTIONFürdieschnelleBereitstellungvonWindowsinCampus-UmgebungensindaktuellgepatchteISO-undWIM-DateieneinewesentlicheUnterstützung.DieWeiterverarbeitungvonWIM-Dateiensind in MDT oder SCM-Tools von Microsoft direkt zu importieren. DieISO-DateikannmitToolswieRufus (https://rufus.ie/) auf einen USB-Stick übertragen werden..PARAMETER<Parameter_Name>Noparameterinputrequired..INPUTSNone.OUTPUTSWIM-filestoredinC:\SetupDeployment\build\REFW10-001.wimISO-filestoredinC:\SetupDeployment\build\<W10_<DATE>.ISO.NOTESVersion:2.0Author:AlexanderScharmerCreationDate:29.12.2019Purpose/Change: Note #1 : To service a newer version of WinPE than the OS you are servicing from, for example service Windows 10 v1709
fromaWindowsServer2019server,youneedanewerDISMversion.Solution,simplyinstallthelatestWindowsADK10,anduseDISMfromthatversion Note #2 : If your Windows OS already have a newer version of dism, uncomment the below line, and comment out line 11 and 12
$DISMFile ='dism.exe'.EXAMPLEPS> . \Create-W10RefImagev1909.ps1#>Clear-HostSet-ExecutionPolicyBypass-ScopeProcess-Force## Release handles on Registry Hive and free up memory[System.GC]::Collect()# Check for elevationIf (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(` [Security.Principal.WindowsBuiltInRole] "Administrator")){ Write-Warning "Oupps, you need to run this script from an elevated PowerShell prompt!`nPlease start the PowerShell prompt as an Administrator and re-run the script."
Write-Warning "Aborting script..."BreakPause}write-host "`nOffline-Patching Window 10 Image v2.0 - by Alexander Scharmer.`n" -ForegroundColor Yellow -BackgroundColor Black
$DISMFile = 'C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\DISM\dism.exe'If (!(Test-Path $DISMFile)) { $scriptName = $MyInvocation.MyCommand.NameWrite-Warning "DISM.exe bzw. Windows ADK nicht gefunden! Abbruch des Scripts $scriptName erfolgt!" [console]::beep(1000,500) Write-Host "`nINFO: Führen Sie das Script 'Install-SetupDeployment.ps1' vorher aus um alle Tools zu installieren und um die notwendige Ordnerstruktur zu erstellen." -ForegroundColor White -BackgroundColor Black
Break }else { Write-Host "`nDISM.exeinWindowsADKgefunden!DasScriptwirdfortgesetzt..." -ForegroundColor Green }$RootDir = [System.IO.Path]::GetDirectoryName($MyInvocation.MyCommand.Path)$ParentDir = [System.IO.Path]::GetDirectoryName($RootDir)Set-StrictMode -Version Latestfunction fGetUpdates { [CmdletBinding()] Param( [parameter(Position=0,Mandatory=$true)] [String]$arch = "x64", [parameter(Position=1,Mandatory=$true)] [ValidateSet("SSU","LCU")] [String]$SLCU, [parameter(Position=2,Mandatory=$true)] [ValidateSet("1909","1903","1809","1803")] [String]$BuildNummer ) $ErrorActionPreference = "Stop" try{ <# In diesem Block der Code, der eine Exception auslösen könnte #> if (!(Get-Module "OSDSUS")) { write-host "ModulOSDSUSnichtgeladen...versucheesnachzuladen..." -ForegroundColor DarkGreen Import-Module OSDSUS -Force } if (!(Get-Module "OSDUpdate")) { write-host "ModulOSDUpdatenichtgeladen...versucheesnachzuladen..." -ForegroundColor DarkGreen Import-Module OSDUpdate -Force } # $error[0].Exception.GetType().FullName } catch [System.IO.FileNotFoundException] { <# Modul OSDSUS oder OSDUpdate wurde nicht gefunden weil nicht installiert #> write-host "Modul OSDSUS bzw. OSDUpdate nicht installiert ... versuche es aus dem Internet zu laden und zu installieren ..." -ForegroundColor DarkGreen
Install-PackageProvider -Name NuGet -Force -Scope AllUsers -ForceBootstrap Install-Module OSDSUS -Scope AllUsers -Force -AllowClobber -SkipPublisherCheck -Confirm:$false Update-OSDSUS Import-Module OSDSUS -Force Install-Module OSDUpdate -Scope AllUsers -Force -AllowClobber -SkipPublisherCheck -Confirm:$false Import-Module OSDUpdate -Force } catch { <# Hier findet die Fehlerbehandlung statt, z.B. das Schreiben eines Logs Der letzte aufgezeichnete Fehler ist hier über die Variable $_ abrufbar, einzelne Eigenschaften daher nach diesem Muster: $_.Exception.Message #> "`n==> Exception Handling durch nicht-terminierenden Fehler" }finally{<# Jede Anweisung in diesem Block wird immer ausgeführt, egal ob ein Fehler aufgetreten ist oder nicht. Dieser Block ist optional. #> write-host "`n`nFinally-Block-OSD-Module:ErfolgreichVerarbeitung." -ForegroundColor Green if (Get-Module "OSDSUS") { Write-Host "ModulOSDSUSerfolgreichgeladen." -ForegroundColor Yellow} if (Get-Module "OSDUpdate") { Write-Host "ModulOSDUpdateerfolgreichgeladen." -ForegroundColor Yellow} # $error[0].Exception.GetType().FullName $error.Clear() } # Get Update-Information $updateInfo = Get-OSDUpdate | ? {$_.UpdateOS -eq 'Windows 10' -and $_.UpdateBuild -eq $BuildNummer -and $_.UpdateGroup -eq $SLCU -and $_.UpdateArch -eq $arch -and $_.IsLatestRevision -eq 'True'}
# Combine Path-Structure $path = [IO.Path]::Combine("$env:SystemDrive\SetupDeployment\Updates", $updateInfo."UpdateOS", $updateInfo."UpdateBuild", $updateInfo."Updategroup")
# Create Folder-Structure for Updates New-Item $path -ItemType Directory -Force | Out-Null # Download or match Updates $updateInfo | Get-DownOSDUpdate -DownloadPath $path sl $path | Out-Null set-content -path .\LatestFile.txt -value ([IO.Path]::Combine($path, $updateInfo."Title", $updateInfo."FileName")) -Force
}fGetUpdates -arch x64 -SLCU SSU -BuildNummer 1909fGetUpdates -arch x64 -SLCU LCU -BuildNummer 1909#Auxiliary$ISO = [System.IO.Path]::Combine("$RootDir\ISO","SW_DVD9_Win_Pro_10_1909_64BIT_German_Pro_Ent_EDU_N_MLF_X22-17400.ISO")
$SSU = Get-Content -Path ([System.IO.Path]::Combine("$env:SystemDrive\SetupDeployment\Updates","Windows 10","1909","SSU","LatestFile.txt"))
$LCU = Get-Content -Path ([System.IO.Path]::Combine("$env:SystemDrive\SetupDeployment\Updates","Windows 10","1909","LCU","LatestFile.txt"))
$MountFolder = [System.IO.Path]::Combine($RootDir,'build\Mount')$RefImageFolder = [System.IO.Path]::Combine($RootDir,'build')$TmpImage = [System.IO.Path]::Combine("$RootDir\tmp",'tmp_install.wim')$RefImage = [System.IO.Path]::Combine($RefImageFolder,'REFW10-001.wim')# Verify that the ISO and CU files existnoteif (!(Test-Path -path $ISO)) { Write-Warning "`nINFO:CouldnotfindWindows10ISO $ISO.WähleeinegültigeISO-DateiimDialogfeldaus..." Write-Host "INFO:ImRegelfallsuchtdasScripteineWindows-10-ISO-DateiimPfad $ISO" -ForegroundColor Green Add-Type -AssemblyName System.Windows.Forms # https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.openfiledialog?redirectedfrom=MSDN&view=netframework-4.8
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{ Title = "WähleeinegültigeWindows-10-ISO-Dateiaus..." InitialDirectory = [System.IO.Directory]::GetCurrentDirectory(); Multiselect = $false Filter = "Image-Dateien (*.iso)|*.iso"; CheckPathExists = 'True'; } [void]$FileBrowser.ShowDialog() $ISO = $FileBrowser.FileName }if (!(Test-Path -path $SSU)) { Write-Warning "Could not find servicing stack Update for Windows 10. Try to download ..." fGetUpdates -arch x64 -SLCU SSU -BuildNummer 1909 }if (!(Test-Path -path $LCU)) { Write-Warning "Could not find Cumulative Update for Windows 10. Try to download ..." fGetUpdates -arch x64 -SLCU LCU -BuildNummer 1909 }# Mount the Windows 10 ISOWrite-Host "`nTryMountingISO $ISO ..." -ForegroundColor GreenMount-DiskImage -ImagePath $ISO | Out-Null$ISOImage = Get-DiskImage -ImagePath $ISO | Get-Volume$ISODrive = [string]$ISOImage.DriveLetter+":"$ImageName = (Get-WindowsImage -ImagePath "$ISODrive\Sources\install.wim" | ? { $_.imageindex -eq '1' }).ImageName.toString()
# Export the Windows 10 Standard index 1 to a new WIMWrite-Host "`nExportingimage $ImageName from $ISODrive\Sources\install.wim..." -ForegroundColor GreenExport-WindowsImage -SourceImagePath "$ISODrive\Sources\install.wim" -SourceIndex 1 -DestinationImagePath $TmpImage# Mount the imageWrite-Host "`nMountingWIM-File $TmpImage ..." -ForegroundColor GreenMount-WindowsImage -ImagePath $TmpImage -Index 1 -Path $MountFolder# Add the latest SSU to the Windows 10 Standard imageWrite-Host "`nInstallingSSU $SSU ..." -ForegroundColor GreenAdd-WindowsPackage -PackagePath $SSU -Path $MountFolder# Add the latest CU (LCU) to the Windows 10 Standard imageWrite-Host "InstallingLCU (bitte umGeduld,dauertetwas) $LCU ..." -ForegroundColor GreenAdd-WindowsPackage -PackagePath $LCU -Path $MountFolder# Cleanup the image BEFORE installing .NET to prevent errors# Using the /ResetBase switch with the /StartComponentCleanup parameter of DISM.exe on a running version of Windows removes all superseded versions of every component in the component store.
# https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/clean-up-the-winsxs-folder#span-iddismexespanspan-iddismexespandismexe
Write-Host "`nCleaningupImage $MountFolder BEFOREinstalling.NETtopreventerrors..." -ForegroundColor Green& $DISMFile /Image:$MountFolder /Cleanup-Image /StartComponentCleanup /ResetBase# Add .NET Framework 3.5.1 to the Windows 10 Standard imageWrite-Host "`nInstalling.NetFramework3.5.toOffline-Image $MountFolder ..." -ForegroundColor GreenAdd-WindowsCapability -Name NetFx3~~~~ –Source $ISODrive\sources\sxs\ -Path $MountFolder | Out-Null# Re-apply latest CU (LCU) because of .NET changesWrite-Host "`nErneutes Applizieren von LCU - aufgrund von .NET 2.0-3.5-Package-Installation - erforderlich ..." -ForegroundColor Green
Add-WindowsPackage -PackagePath $LCU -Path $MountFolder# Dismount the Windows 10 Standard imageWrite-Host "`nDismountingWIM $MountFolder ..." -ForegroundColor GreenDisMount-WindowsImage -Path $MountFolder -Save# Export the Windows 10 index to a new WIM (the export operation reduces the WIM size with about 100 MB or so)# Optimize final image - https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/oem-deployment-of-windows-10-for-desktop-editions
# Remove unused packages from your image, by exporting a copy of it.Write-Host "`nExportingtheWIM-File $TmpImage to $RefImage ..." -ForegroundColor GreenExport-WindowsImage -SourceImagePath $TmpImage -SourceIndex "1" -DestinationImagePath $RefImage# Remove the uneeded temporary WIM-File.Write-Host "`nDeletetemporaryWIM $TmpImage ..." -ForegroundColor Greenif (Test-Path -path $TmpImage) {Remove-Item -Path $TmpImage -Force}# Copy REF-IMG to Media for ISO-BuildWrite-Host "`nCopyREF-IMGtoMediaforISO-Build..." -ForegroundColor Greenif (!(Test-Path -path "$RefImageFolder\media")) {New-Item -path "$RefImageFolder\media" -ItemType Directory}Copy-Item -Path "$ISODrive\*" -Destination "$RefImageFolder\media" -Force -RecurseCopy-Item -Path $RefImage -Destination "$RefImageFolder\Media\sources\install.wim" -Force -Filter "*.wim" -Confirm:$false
# Create Windows ISO$ISOFile = "$RefImageFolder" + "\" + ([string]"W10_$(get-date-Formatd)").Replace(".","_") + ".ISO"write-Host"`nKonstruiereDateinamefürISO-Datei $ISOFile" -ForegroundColor Green$ToolsPath = "C:\ProgramFiles (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg"$BootData='2#p0,e,b"{0}"#pEF,e,b"{1}"' -f "$ToolsPath\etfsboot.com","$ToolsPath\efisys_noprompt.bin"$Proc = Start-Process -FilePath "$ToolsPath\oscdimg.exe" -ArgumentList @("-bootdata:$BootData",'-u2','-udfver102',"$RefImageFolder\media","$ISOFile") -PassThru -Wait
if($Proc.ExitCode -ne 0){ Throw "FailedtogenerateISOwithexitcode $($Proc.ExitCode)"}else { Write-Host "`nMedia $ISOFile creation has been successfully done!"-ForegroundColorYellow-BackgroundColorBlack}# Dismount the Windows 10 ISOWrite-Host"Dismounting ISO $ISO und finalisiere Script ..."-ForegroundColorGreenDismount-DiskImage-ImagePath $ISO |Out-NullWrite-Host"Ende. Have a nice Day!"# END OF SCRIPT
Video-Sequenz zum Ablauf des ersten Scripts.
Ausgabe der Medienformate .ISO und .WIM
Als Ergebnis werden die aktuell gepatchten Windows-10-1909-Builds als Abbilder in den Formaten .WIM und .ISO im Ordner C:\SetupDeployment\build ausgegeben.
Manuelles Erstellen eines startfähigen ISO-Abbildes von einem Ordner
Im Zusammenhang von Windows-Deployments werden auch Anforderungen gestellt, wo ein ISO-Abbild in einen Ordner kopiert wird, der Inhalt des Ordners aktualisiert wird (z. B. die Datei install.wim, oder das Einfügen einer Autounattend.xml-Datei oder auch Apps etc.) und anschließend wieder in das ISO-Format zurückgebracht werden soll. Microsoft liefert mit dem Windows ADK ein Kommandozeilen-basiertes Tool namens oscdimg.exe aus. Die 64-Bit-Variante von des Tools wird im Regelfall in den Standardordner C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg\oscdimg.exe abgelegt. Dies kann unter Angabe verschiedener Parameter erneut ein ISO-Abbild generieren. Folgendes Beispiel soll dies skizzieren:
Im Code-Block oben wird der Ordner D:\ISO_Files als bootfähiges (mithilfe der Dateien etfsboot.com und efisys.bin die in Windows ADK enthalten sind) Abbild im ISO-Format im Pfad D:\W10-1903FAT.iso erzeugt.
Einen startfähigen USB-Stick mit dem W10-ISO-Abbild erstellen
Das ISO-Abbild W10_<Erstell-Datum>.ISO kann mit einer vielzahl an Software-Tools auf einen USB-Stick übertragen werden. Damit kann ein Endgerät mithilfe des USB-Sticks gestartet (bootfähig) und Windows 10 mit aktuellen Patch-Level installiert werden. Der Author verwendet hier das Tool Rufus von Pete Batard.
.WIM-Abbild in Microsoft-Deployment-Toolkit (MDT) weiterverarbeiten
Abbilder im .WIM-Format können in MDT hervorragend dazu verwendet werden, um laufend aktualisierte Betriebssystem-Abbilder am Campus bereitzustellen. Hierbei können sowohl Microsoft Client- sowie Server-Betriebssysteme bereitgestellt werden.
Alternative Tools zur scriptbasierten Variante
NTLite ist ein Computerprogramm, mit dessen Hilfe alternative Installationsmedien von Windows 7, 8, 8.1 und 10 erstellt werden können. Mit NTLite können Addons, Treiber, Sprachpakete, Silent Installer und Updates in ein Installationsmedium integriert werden.
Integrate localization packs, drivers, feature packs, add-on packs and updates.
Remove Windows components, simplify installation and free up drive space.
You can set the look and feel of Windows OS as you like with cursors, fonts, themes and skins.
Automate Windows setup tasks, save and deploy the Windows installation image.
OSDBuilder is a PowerShell module to help you perform Offline Servicing to a Windows Operating System Image. By using an Offline method of configuring an Operating System, it can then be imported in MDT or SCCM and used like any other OS Deployment. This includes being able to use in an Upgrade Task Sequence, which you cannot do with a Captured Image.
The main difference between OSDBuilder and other scripted methods for Servicing a Windows Image Offline is that OSDBuilder creates an answer file called a Task (think Task Sequence). Since the Task has all the information it needs to update the Windows Image, there is no interaction necessary, and as long as the content (updates) are updated regularly, the Task can be repeated as needed.