mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-14 02:09:35 -06:00
Merge remote-tracking branch 'origin/2410.1' into pr/JonasKloseBW/91
This commit is contained in:
+247
-87
@@ -172,6 +172,9 @@ Model of the device to download drivers. This is required if Make is set.
|
|||||||
.PARAMETER AppsScriptVariables
|
.PARAMETER AppsScriptVariables
|
||||||
When passed a hashtable, the script will alter the $FFUDevelopmentPath\Apps\InstallAppsandSysprep.cmd file to set variables with the hashtable keys as variable names and the hashtable values their content.
|
When passed a hashtable, the script will alter the $FFUDevelopmentPath\Apps\InstallAppsandSysprep.cmd file to set variables with the hashtable keys as variable names and the hashtable values their content.
|
||||||
|
|
||||||
|
.PARAMETER CustomFFUNameTemplate
|
||||||
|
Sets a custom FFU output name with placeholders. Allowed placeholders are: {Name}, {DisplayVersion}, {SKU}, {BuildDate}, {yyyy}, {MM}, {dd}, {H}, {hh}, {mm}, {tt}
|
||||||
|
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
Command line for most people who want to download the latest Windows 11 Pro x64 media in English (US) with the latest Windows Cumulative Update, .NET Framework, Defender platform and definition updates, Edge, OneDrive, and Office/M365 Apps. It will also copy drivers to the FFU. This can take about 40 minutes to create the FFU due to the time it takes to download and install the updates.
|
Command line for most people who want to download the latest Windows 11 Pro x64 media in English (US) with the latest Windows Cumulative Update, .NET Framework, Defender platform and definition updates, Edge, OneDrive, and Office/M365 Apps. It will also copy drivers to the FFU. This can take about 40 minutes to create the FFU due to the time it takes to download and install the updates.
|
||||||
.\BuildFFUVM.ps1 -WindowsSKU 'Pro' -Installapps $true -InstallOffice $true -InstallDrivers $true -VMSwitchName 'Name of your VM Switch in Hyper-V' -VMHostIPAddress 'Your IP Address' -CreateCaptureMedia $true -CreateDeploymentMedia $true -BuildUSBDrive $true -UpdateLatestCU $true -UpdateLatestNet $true -UpdateLatestDefender $true -UpdateEdge $true -UpdateOneDrive $true -verbose
|
.\BuildFFUVM.ps1 -WindowsSKU 'Pro' -Installapps $true -InstallOffice $true -InstallDrivers $true -VMSwitchName 'Name of your VM Switch in Hyper-V' -VMHostIPAddress 'Your IP Address' -CreateCaptureMedia $true -CreateDeploymentMedia $true -BuildUSBDrive $true -UpdateLatestCU $true -UpdateLatestNet $true -UpdateLatestDefender $true -UpdateEdge $true -UpdateOneDrive $true -verbose
|
||||||
@@ -237,8 +240,9 @@ param(
|
|||||||
[string]$VMLocation,
|
[string]$VMLocation,
|
||||||
[string]$FFUPrefix = '_FFU',
|
[string]$FFUPrefix = '_FFU',
|
||||||
[string]$FFUCaptureLocation,
|
[string]$FFUCaptureLocation,
|
||||||
[String]$ShareName = "FFUCaptureShare",
|
[string]$ShareName = "FFUCaptureShare",
|
||||||
[string]$Username = "ffu_user",
|
[string]$Username = "ffu_user",
|
||||||
|
[string]$CustomFFUNameTemplate,
|
||||||
[Parameter(Mandatory = $false)]
|
[Parameter(Mandatory = $false)]
|
||||||
[string]$VMHostIPAddress,
|
[string]$VMHostIPAddress,
|
||||||
[bool]$CreateCaptureMedia = $true,
|
[bool]$CreateCaptureMedia = $true,
|
||||||
@@ -318,6 +322,7 @@ param(
|
|||||||
[bool]$UpdateLatestMSRT,
|
[bool]$UpdateLatestMSRT,
|
||||||
[bool]$UpdateEdge,
|
[bool]$UpdateEdge,
|
||||||
[bool]$UpdateOneDrive,
|
[bool]$UpdateOneDrive,
|
||||||
|
[bool]$AllowVHDXCaching,
|
||||||
[bool]$CopyPPKG,
|
[bool]$CopyPPKG,
|
||||||
[bool]$CopyUnattend,
|
[bool]$CopyUnattend,
|
||||||
[bool]$CopyAutopilot,
|
[bool]$CopyAutopilot,
|
||||||
@@ -348,6 +353,23 @@ param(
|
|||||||
)
|
)
|
||||||
$version = '2410.1'
|
$version = '2410.1'
|
||||||
|
|
||||||
|
#Class definition for vhdx cache
|
||||||
|
class VhdxCacheUpdateItem {
|
||||||
|
[string]$Name
|
||||||
|
VhdxCacheUpdateItem([string]$Name) {
|
||||||
|
$this.Name = $Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VhdxCacheItem {
|
||||||
|
[string]$VhdxFileName = ""
|
||||||
|
[string]$WindowsSKU = ""
|
||||||
|
[string]$WindowsRelease = ""
|
||||||
|
[string]$WindowsVersion = ""
|
||||||
|
[string]$OptionalFeatures = ""
|
||||||
|
[VhdxCacheUpdateItem[]]$IncludedUpdates = @()
|
||||||
|
}
|
||||||
|
|
||||||
#Check if Hyper-V feature is installed (requires only checks the module)
|
#Check if Hyper-V feature is installed (requires only checks the module)
|
||||||
$osInfo = Get-WmiObject -Class Win32_OperatingSystem
|
$osInfo = Get-WmiObject -Class Win32_OperatingSystem
|
||||||
$isServer = $osInfo.Caption -match 'server'
|
$isServer = $osInfo.Caption -match 'server'
|
||||||
@@ -390,6 +412,7 @@ if (-not $PPKGFolder) { $PPKGFolder = "$FFUDevelopmentPath\PPKG" }
|
|||||||
if (-not $UnattendFolder) { $UnattendFolder = "$FFUDevelopmentPath\Unattend" }
|
if (-not $UnattendFolder) { $UnattendFolder = "$FFUDevelopmentPath\Unattend" }
|
||||||
if (-not $AutopilotFolder) { $AutopilotFolder = "$FFUDevelopmentPath\Autopilot" }
|
if (-not $AutopilotFolder) { $AutopilotFolder = "$FFUDevelopmentPath\Autopilot" }
|
||||||
if (-not $PEDriversFolder) { $PEDriversFolder = "$FFUDevelopmentPath\PEDrivers" }
|
if (-not $PEDriversFolder) { $PEDriversFolder = "$FFUDevelopmentPath\PEDrivers" }
|
||||||
|
if (-not $VHDXCacheFolder) { $VHDXCacheFolder = "$FFUDevelopmentPath\VHDXCache" }
|
||||||
if (-not $installationType) { $installationType = if ($WindowsRelease.ToString().Length -eq 2) { 'Client' } else { 'Server' } }
|
if (-not $installationType) { $installationType = if ($WindowsRelease.ToString().Length -eq 2) { 'Client' } else { 'Server' } }
|
||||||
if ($installationType -eq 'Server'){
|
if ($installationType -eq 'Server'){
|
||||||
#Map $WindowsRelease to $WindowsVersion for Windows Server
|
#Map $WindowsRelease to $WindowsVersion for Windows Server
|
||||||
@@ -2788,6 +2811,11 @@ Function Set-CaptureFFU {
|
|||||||
$ScriptContent = Get-Content -Path $CaptureFFUScriptPath
|
$ScriptContent = Get-Content -Path $CaptureFFUScriptPath
|
||||||
$UpdatedContent = $ScriptContent -replace '(net use).*', ("$SharePath")
|
$UpdatedContent = $ScriptContent -replace '(net use).*', ("$SharePath")
|
||||||
WriteLog 'Updating share command in CaptureFFU.ps1 script with new share information'
|
WriteLog 'Updating share command in CaptureFFU.ps1 script with new share information'
|
||||||
|
$UpdatedContent = $UpdatedContent -replace '^\$CustomFFUNameTemplate \= .*#Custom naming', "#Custom naming placeholder"
|
||||||
|
if (![string]::IsNullOrEmpty($CustomFFUNameTemplate)) {
|
||||||
|
$UpdatedContent = $UpdatedContent -replace '#Custom naming placeholder', ("`$CustomFFUNameTemplate = '$CustomFFUNameTemplate' #Custom naming")
|
||||||
|
WriteLog 'Updating share command in CaptureFFU.ps1 script with new ffu name template information'
|
||||||
|
}
|
||||||
Set-Content -Path $CaptureFFUScriptPath -Value $UpdatedContent
|
Set-Content -Path $CaptureFFUScriptPath -Value $UpdatedContent
|
||||||
WriteLog 'Update complete'
|
WriteLog 'Update complete'
|
||||||
}
|
}
|
||||||
@@ -2928,11 +2956,12 @@ function Optimize-FFUCaptureDrive {
|
|||||||
)
|
)
|
||||||
try {
|
try {
|
||||||
WriteLog 'Mounting VHDX for volume optimization'
|
WriteLog 'Mounting VHDX for volume optimization'
|
||||||
Mount-VHD -Path $VhdxPath
|
$mountedDisk = Mount-VHD -Path $VhdxPath -Passthru | Get-Disk
|
||||||
|
$osPartition = $mountedDisk | Get-Partition | Where-Object { $_.GptType -eq "{ebd0a0a2-b9e5-4433-87c0-68b6b72699c7}" }
|
||||||
WriteLog 'Defragmenting Windows partition...'
|
WriteLog 'Defragmenting Windows partition...'
|
||||||
Optimize-Volume -DriveLetter W -Defrag -NormalPriority
|
Optimize-Volume -DriveLetter $osPartition.DriveLetter -Defrag -NormalPriority
|
||||||
WriteLog 'Performing slab consolidation on Windows partition...'
|
WriteLog 'Performing slab consolidation on Windows partition...'
|
||||||
Optimize-Volume -DriveLetter W -SlabConsolidate -NormalPriority
|
Optimize-Volume -DriveLetter $osPartition.DriveLetter -SlabConsolidate -NormalPriority
|
||||||
WriteLog 'Dismounting VHDX'
|
WriteLog 'Dismounting VHDX'
|
||||||
Dismount-ScratchVhdx -VhdxPath $VhdxPath
|
Dismount-ScratchVhdx -VhdxPath $VhdxPath
|
||||||
WriteLog 'Mounting VHDX as read-only for optimization'
|
WriteLog 'Mounting VHDX as read-only for optimization'
|
||||||
@@ -3880,6 +3909,17 @@ if (($WindowsArch -eq 'ARM64') -and ($UpdateLatestMSRT -eq $true)) {
|
|||||||
$UpdateLatestMSRT = $false
|
$UpdateLatestMSRT = $false
|
||||||
WriteLog 'Windows Malicious Software Removal Tool is not available for the ARM64 architecture.'
|
WriteLog 'Windows Malicious Software Removal Tool is not available for the ARM64 architecture.'
|
||||||
}
|
}
|
||||||
|
#If downloading ESD from MCT, hardcode WindowsVersion to 22H2 for Windows 10 and 24H2 for Windows 11
|
||||||
|
#MCT media only provides 22H2 and 24H2 media
|
||||||
|
#This prevents issues with VHDX Caching unecessarily and with searching for CUs
|
||||||
|
if ($ISOPath -eq '') {
|
||||||
|
if ($WindowsRelease -eq '10') {
|
||||||
|
$WindowsVersion = '22H2'
|
||||||
|
}
|
||||||
|
if ($WindowsRelease -eq '11') {
|
||||||
|
$WindowsVersion = '24H2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
###END PARAMETER VALIDATION
|
###END PARAMETER VALIDATION
|
||||||
|
|
||||||
@@ -4155,34 +4195,6 @@ if ($InstallApps) {
|
|||||||
#Create VHDX
|
#Create VHDX
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if ($ISOPath) {
|
|
||||||
$wimPath = Get-WimFromISO
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$wimPath = Get-WindowsESD -WindowsRelease $WindowsRelease -WindowsArch $WindowsArch -WindowsLang $WindowsLang -MediaType $mediaType
|
|
||||||
}
|
|
||||||
#If index not specified by user, try and find based on WindowsSKU
|
|
||||||
if (-not($index) -and ($WindowsSKU)) {
|
|
||||||
$index = Get-Index -WindowsImagePath $wimPath -WindowsSKU $WindowsSKU
|
|
||||||
}
|
|
||||||
|
|
||||||
$vhdxDisk = New-ScratchVhdx -VhdxPath $VHDXPath -SizeBytes $disksize -LogicalSectorSizeBytes $LogicalSectorSizeBytes
|
|
||||||
|
|
||||||
$systemPartitionDriveLetter = New-SystemPartition -VhdxDisk $vhdxDisk
|
|
||||||
|
|
||||||
New-MSRPartition -VhdxDisk $vhdxDisk
|
|
||||||
|
|
||||||
$osPartition = New-OSPartition -VhdxDisk $vhdxDisk -OSPartitionSize $OSPartitionSize -WimPath $WimPath -WimIndex $index
|
|
||||||
$osPartitionDriveLetter = $osPartition[1].DriveLetter
|
|
||||||
$WindowsPartition = $osPartitionDriveLetter + ":\"
|
|
||||||
|
|
||||||
#$recoveryPartition = New-RecoveryPartition -VhdxDisk $vhdxDisk -OsPartition $osPartition[1] -RecoveryPartitionSize $RecoveryPartitionSize -DataPartition $dataPartition
|
|
||||||
$recoveryPartition = New-RecoveryPartition -VhdxDisk $vhdxDisk -OsPartition $osPartition[1] -RecoveryPartitionSize $RecoveryPartitionSize -DataPartition $dataPartition
|
|
||||||
|
|
||||||
WriteLog "All necessary partitions created."
|
|
||||||
|
|
||||||
Add-BootFiles -OsPartitionDriveLetter $osPartitionDriveLetter -SystemPartitionDriveLetter $systemPartitionDriveLetter[1]
|
|
||||||
|
|
||||||
#Update latest Cumulative Update if both $UpdateLatestCU is $true and $UpdatePreviewCU is $false
|
#Update latest Cumulative Update if both $UpdateLatestCU is $true and $UpdatePreviewCU is $false
|
||||||
#Changed to use MU Catalog instead of using Get-LatestWindowsKB
|
#Changed to use MU Catalog instead of using Get-LatestWindowsKB
|
||||||
#The Windows release info page is updated later than the MU Catalog
|
#The Windows release info page is updated later than the MU Catalog
|
||||||
@@ -4219,7 +4231,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#Update Latest Preview Cumlative Update for Client OS only
|
#Update Latest Preview Cumlative Update for Client OS only
|
||||||
#will take Precendence over $UpdateLastestCU if both were set to $true
|
#will take Precendence over $UpdateLatestCU if both were set to $true
|
||||||
if ($UpdatePreviewCU -and $installationType -eq 'Client') {
|
if ($UpdatePreviewCU -and $installationType -eq 'Client') {
|
||||||
Writelog "`$UpdatePreviewCU is set to true, checking for latest Preview CU"
|
Writelog "`$UpdatePreviewCU is set to true, checking for latest Preview CU"
|
||||||
$Name = """Cumulative update Preview for Windows $WindowsRelease Version $WindowsVersion for $WindowsArch"""
|
$Name = """Cumulative update Preview for Windows $WindowsRelease Version $WindowsVersion for $WindowsArch"""
|
||||||
@@ -4273,57 +4285,164 @@ try {
|
|||||||
# $KBFilePath = Save-KB -Name $Name -Path $KBPath
|
# $KBFilePath = Save-KB -Name $Name -Path $KBPath
|
||||||
# WriteLog "Latest Security Platform Update saved to $KBPath\$KBFilePath"
|
# WriteLog "Latest Security Platform Update saved to $KBPath\$KBFilePath"
|
||||||
# }
|
# }
|
||||||
|
|
||||||
|
#Search for cached VHDX and skip VHDX creation if there's a cached version
|
||||||
#Add Windows packages
|
if ($AllowVHDXCaching) {
|
||||||
if ($UpdateLatestCU -or $UpdateLatestNet -or $UpdatePreviewCU ) {
|
WriteLog 'AllowVHDXCaching is true, checking for cached VHDX file'
|
||||||
try {
|
if (Test-Path -Path $VHDXCacheFolder) {
|
||||||
WriteLog "Adding KBs to $WindowsPartition"
|
WriteLog "Found $VHDXCacheFolder"
|
||||||
WriteLog 'This can take 10+ minutes depending on how old the media is and the size of the KB. Please be patient'
|
$vhdxJsons = @(Get-ChildItem -File -Path $VHDXCacheFolder -Filter '*_config.json' | Sort-Object -Property CreationTime -Descending)
|
||||||
# If WindowsRelease is 2016, we need to add the SSU first
|
WriteLog "Found $($vhdxJsons.Count) cached VHDX files"
|
||||||
if ($WindowsRelease -eq 2016) {
|
$downloadedKBs = @(Get-ChildItem -File -Path $KBPath)
|
||||||
WriteLog "WindowsRelease is 2016, adding SSU first"
|
#$jsonDeserializer = [System.Web.Script.Serialization.JavaScriptSerializer]::new()
|
||||||
WriteLog "Adding SSU to $WindowsPartition"
|
|
||||||
# Add-WindowsPackage -Path $WindowsPartition -PackagePath $SSUFilePath -PreventPending | Out-Null
|
foreach ($vhdxJson in $vhdxJsons) {
|
||||||
# Commenting out -preventpending as it causes an issue with the SSU being applied
|
try {
|
||||||
# Seems to be because of the registry being mounted per dism.log
|
WriteLog "Processing $($vhdxJson.FullName)"
|
||||||
Add-WindowsPackage -Path $WindowsPartition -PackagePath $SSUFilePath | Out-Null
|
#$vhdxCacheItem = $jsonDeserializer.Deserialize((Get-Content -Path $vhdxJson.FullName -Raw), [VhdxCacheItem])
|
||||||
WriteLog "SSU added to $WindowsPartition"
|
$vhdxCacheItem = Get-Content -Path $vhdxJson.FullName -Raw | ConvertFrom-Json
|
||||||
WriteLog "Removing $SSUFilePath"
|
|
||||||
Remove-Item -Path $SSUFilePath -Force | Out-Null
|
if ((($vhdxCacheItem.WindowsSKU -ne $WindowsSKU) -or
|
||||||
WriteLog 'SSU removed'
|
([string]::IsNullOrEmpty($vhdxCacheItem.WindowsSKU) -xor [string]::IsNullOrEmpty($WindowsSKU)))) {
|
||||||
WriteLog "Adding CU to $WindowsPartition"
|
WriteLog 'WindowsSKU mismatch, continuing'
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((($vhdxCacheItem.WindowsRelease -ne $WindowsRelease) -or
|
||||||
|
([string]::IsNullOrEmpty($vhdxCacheItem.WindowsRelease) -xor [string]::IsNullOrEmpty($WindowsRelease)))) {
|
||||||
|
WriteLog 'WindowsRelease mismatch, continuing'
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((($vhdxCacheItem.WindowsVersion -ne $WindowsVersion) -or
|
||||||
|
([string]::IsNullOrEmpty($vhdxCacheItem.WindowsVersion) -xor [string]::IsNullOrEmpty($WindowsVersion)))) {
|
||||||
|
Writelog 'WindowsVersion mismatch, continuing'
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((($vhdxCacheItem.OptionalFeatures -ne $OptionalFeatures) -or
|
||||||
|
([string]::IsNullOrEmpty($vhdxCacheItem.OptionalFeatures) -xor [string]::IsNullOrEmpty($OptionalFeatures)))) {
|
||||||
|
WriteLog 'OptionalFeatures mismatch, continuing'
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Compare-Object -ReferenceObject $downloadedKBs -DifferenceObject $vhdxCacheItem.IncludedUpdates -Property Name).Length -gt 0) {
|
||||||
|
(Compare-Object -ReferenceObject $downloadedKBs -DifferenceObject $vhdxCacheItem.IncludedUpdates -Property Name)
|
||||||
|
$downloadedKBs.Name
|
||||||
|
$vhdxCacheItem.IncludedUpdates.Name
|
||||||
|
WriteLog 'IncludedUpdates mismatch, continuing'
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteLog "Found cached VHDX file $vhdxCacheFolder\$($vhdxCacheItem.VhdxFileName) with matching parameters and included updates"
|
||||||
|
$cachedVHDXFileFound = $true
|
||||||
|
$cachedVHDXInfo = $vhdxCacheItem
|
||||||
|
break
|
||||||
|
} catch {
|
||||||
|
WriteLog "Reading $vhdxJson Failed with error $_"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
# Add-WindowsPackage -Path $WindowsPartition -PackagePath $KBPath -PreventPending | Out-Null
|
|
||||||
Add-WindowsPackage -Path $WindowsPartition -PackagePath $KBPath | Out-Null
|
|
||||||
WriteLog "KBs added to $WindowsPartition"
|
|
||||||
WriteLog "Removing $KBPath"
|
|
||||||
Remove-Item -Path $KBPath -Recurse -Force | Out-Null
|
|
||||||
WriteLog "Clean Up the WinSxS Folder"
|
|
||||||
WriteLog 'This can take 10+ minutes depending on how old the media is and the size of the KB. Please be patient'
|
|
||||||
Dism /Image:$WindowsPartition /Cleanup-Image /StartComponentCleanup /ResetBase | Out-Null
|
|
||||||
WriteLog "Clean Up the WinSxS Folder completed"
|
|
||||||
}
|
}
|
||||||
catch {
|
|
||||||
Write-Host "Adding KB to VHDX failed with error $_"
|
|
||||||
WriteLog "Adding KB to VHDX failed with error $_"
|
|
||||||
if ($_.Exception.HResult -eq -2146498525){
|
|
||||||
Write-Host 'Missing latest Servicing Stack Update'
|
|
||||||
Write-Host 'Media likely older than 2023-09 for Windows Server 2022 (KB5030216), or 2021-08 for Windows Server 2019 (KB5005112)'
|
|
||||||
Write-Host 'Recommended to use the latest media'
|
|
||||||
WriteLog 'Missing latest Servicing Stack Update'
|
|
||||||
WriteLog 'Media likely older than 2023-09 for Windows Server 2022 (KB5030216), or 2021-08 for Windows Server 2019 (KB5005112)'
|
|
||||||
WriteLog 'Recommended to use the latest media'
|
|
||||||
}
|
|
||||||
throw $_
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (-Not $cachedVHDXFileFound) {
|
||||||
|
if ($ISOPath) {
|
||||||
|
$wimPath = Get-WimFromISO
|
||||||
|
} else {
|
||||||
|
$wimPath = Get-WindowsESD -WindowsRelease $WindowsRelease -WindowsArch $WindowsArch -WindowsLang $WindowsLang -MediaType $mediaType
|
||||||
|
}
|
||||||
|
#If index not specified by user, try and find based on WindowsSKU
|
||||||
|
if (-not($index) -and ($WindowsSKU)) {
|
||||||
|
$index = Get-Index -WindowsImagePath $wimPath -WindowsSKU $WindowsSKU
|
||||||
|
}
|
||||||
|
|
||||||
|
$vhdxDisk = New-ScratchVhdx -VhdxPath $VHDXPath -SizeBytes $disksize -LogicalSectorSizeBytes $LogicalSectorSizeBytes
|
||||||
|
|
||||||
|
$systemPartitionDriveLetter = New-SystemPartition -VhdxDisk $vhdxDisk
|
||||||
|
|
||||||
|
New-MSRPartition -VhdxDisk $vhdxDisk
|
||||||
|
|
||||||
|
$osPartition = New-OSPartition -VhdxDisk $vhdxDisk -OSPartitionSize $OSPartitionSize -WimPath $WimPath -WimIndex $index
|
||||||
|
$osPartitionDriveLetter = $osPartition[1].DriveLetter
|
||||||
|
$WindowsPartition = $osPartitionDriveLetter + ':\'
|
||||||
|
|
||||||
|
#$recoveryPartition = New-RecoveryPartition -VhdxDisk $vhdxDisk -OsPartition $osPartition[1] -RecoveryPartitionSize $RecoveryPartitionSize -DataPartition $dataPartition
|
||||||
|
$recoveryPartition = New-RecoveryPartition -VhdxDisk $vhdxDisk -OsPartition $osPartition[1] -RecoveryPartitionSize $RecoveryPartitionSize -DataPartition $dataPartition
|
||||||
|
|
||||||
|
WriteLog 'All necessary partitions created.'
|
||||||
|
|
||||||
|
Add-BootFiles -OsPartitionDriveLetter $osPartitionDriveLetter -SystemPartitionDriveLetter $systemPartitionDriveLetter[1]
|
||||||
|
|
||||||
|
#Add Windows packages
|
||||||
|
if ($UpdateLatestCU -or $UpdateLatestNet -or $UpdatePreviewCU ) {
|
||||||
|
try {
|
||||||
|
WriteLog "Adding KBs to $WindowsPartition"
|
||||||
|
WriteLog 'This can take 10+ minutes depending on how old the media is and the size of the KB. Please be patient'
|
||||||
|
# If WindowsRelease is 2016, we need to add the SSU first
|
||||||
|
if ($WindowsRelease -eq 2016) {
|
||||||
|
WriteLog 'WindowsRelease is 2016, adding SSU first'
|
||||||
|
WriteLog "Adding SSU to $WindowsPartition"
|
||||||
|
# Add-WindowsPackage -Path $WindowsPartition -PackagePath $SSUFilePath -PreventPending | Out-Null
|
||||||
|
# Commenting out -preventpending as it causes an issue with the SSU being applied
|
||||||
|
# Seems to be because of the registry being mounted per dism.log
|
||||||
|
Add-WindowsPackage -Path $WindowsPartition -PackagePath $SSUFilePath | Out-Null
|
||||||
|
WriteLog "SSU added to $WindowsPartition"
|
||||||
|
WriteLog "Removing $SSUFilePath"
|
||||||
|
Remove-Item -Path $SSUFilePath -Force | Out-Null
|
||||||
|
WriteLog 'SSU removed'
|
||||||
|
WriteLog "Adding CU to $WindowsPartition"
|
||||||
|
}
|
||||||
|
# Add-WindowsPackage -Path $WindowsPartition -PackagePath $KBPath -PreventPending | Out-Null
|
||||||
|
Add-WindowsPackage -Path $WindowsPartition -PackagePath $KBPath | Out-Null
|
||||||
|
WriteLog "KBs added to $WindowsPartition"
|
||||||
|
if ($AllowVHDXCaching) {
|
||||||
|
$cachedVHDXInfo = [VhdxCacheItem]::new()
|
||||||
|
$includedUpdates = Get-ChildItem -Path $KBPath -File
|
||||||
|
|
||||||
|
foreach ($includedUpdate in $includedUpdates) {
|
||||||
|
$cachedVHDXInfo.IncludedUpdates += ([VhdxCacheUpdateItem]::new($includedUpdate.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WriteLog "Removing $KBPath"
|
||||||
|
Remove-Item -Path $KBPath -Recurse -Force | Out-Null
|
||||||
|
WriteLog 'Clean Up the WinSxS Folder'
|
||||||
|
WriteLog 'This can take 10+ minutes depending on how old the media is and the size of the KB. Please be patient'
|
||||||
|
Dism /Image:$WindowsPartition /Cleanup-Image /StartComponentCleanup /ResetBase | Out-Null
|
||||||
|
WriteLog 'Clean Up the WinSxS Folder completed'
|
||||||
|
} catch {
|
||||||
|
Write-Host "Adding KB to VHDX failed with error $_"
|
||||||
|
WriteLog "Adding KB to VHDX failed with error $_"
|
||||||
|
if ($_.Exception.HResult -eq -2146498525) {
|
||||||
|
Write-Host 'Missing latest Servicing Stack Update'
|
||||||
|
Write-Host 'Media likely older than 2023-09 for Windows Server 2022 (KB5030216), or 2021-08 for Windows Server 2019 (KB5005112)'
|
||||||
|
Write-Host 'Recommended to use the latest media'
|
||||||
|
WriteLog 'Missing latest Servicing Stack Update'
|
||||||
|
WriteLog 'Media likely older than 2023-09 for Windows Server 2022 (KB5030216), or 2021-08 for Windows Server 2019 (KB5005112)'
|
||||||
|
WriteLog 'Recommended to use the latest media'
|
||||||
|
}
|
||||||
|
throw $_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Enable Windows Optional Features (e.g. .Net3, etc)
|
||||||
|
If ($OptionalFeatures) {
|
||||||
|
$Source = Join-Path (Split-Path $wimpath) 'sxs'
|
||||||
|
Enable-WindowsFeaturesByName -FeatureNames $OptionalFeatures -Source $Source
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
#Use cached vhdx file
|
||||||
|
WriteLog 'Using cached VHDX file to speed up build proces'
|
||||||
|
WriteLog "VHDX file is: $($cachedVHDXInfo.VhdxFileName)"
|
||||||
|
|
||||||
|
Robocopy.exe $($VHDXCacheFolder) $($VMPath) $($cachedVHDXInfo.VhdxFileName) /E /COPY:DAT /R:5 /W:5 /J
|
||||||
|
$VHDXPath = Join-Path $($VMPath) $($cachedVHDXInfo.VhdxFileName)
|
||||||
|
|
||||||
|
$vhdxDisk = Get-VHD -Path $VHDXPath | Mount-VHD -Passthru | Get-Disk
|
||||||
|
$osPartition = $vhdxDisk | Get-Partition | Where-Object { $_.GptType -eq '{ebd0a0a2-b9e5-4433-87c0-68b6b72699c7}' }
|
||||||
|
$osPartitionDriveLetter = $osPartition.DriveLetter
|
||||||
|
$WindowsPartition = $osPartitionDriveLetter + ':\'
|
||||||
|
|
||||||
#Enable Windows Optional Features (e.g. .Net3, etc)
|
|
||||||
If ($OptionalFeatures) {
|
|
||||||
$Source = Join-Path (Split-Path $wimpath) "sxs"
|
|
||||||
Enable-WindowsFeaturesByName -FeatureNames $OptionalFeatures -Source $Source
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#Set Product key
|
#Set Product key
|
||||||
@@ -4336,16 +4455,18 @@ try {
|
|||||||
Dismount-DiskImage -ImagePath $ISOPath | Out-null
|
Dismount-DiskImage -ImagePath $ISOPath | Out-null
|
||||||
WriteLog 'Done'
|
WriteLog 'Done'
|
||||||
}
|
}
|
||||||
else {
|
#If $wimPath is an esd file, remove it
|
||||||
#Remove ESD file
|
If ($wimPath -match '.esd') {
|
||||||
|
WriteLog "Deleting $wimPath file"
|
||||||
Remove-Item -Path $wimPath -Force
|
Remove-Item -Path $wimPath -Force
|
||||||
|
WriteLog "$wimPath deleted"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
If ($InstallApps) {
|
If ($InstallApps) {
|
||||||
#Copy Unattend file so VM Boots into Audit Mode
|
#Copy Unattend file so VM Boots into Audit Mode
|
||||||
WriteLog 'Copying unattend file to boot to audit mode'
|
WriteLog 'Copying unattend file to boot to audit mode'
|
||||||
New-Item -Path "$($osPartitionDriveLetter):\Windows\Panther\unattend" -ItemType Directory | Out-Null
|
New-Item -Path "$($osPartitionDriveLetter):\Windows\Panther\unattend" -ItemType Directory -Force | Out-Null
|
||||||
if($WindowsArch -eq 'x64'){
|
if($WindowsArch -eq 'x64'){
|
||||||
Copy-Item -Path "$FFUDevelopmentPath\BuildFFUUnattend\unattend_x64.xml" -Destination "$($osPartitionDriveLetter):\Windows\Panther\Unattend\Unattend.xml" -Force | Out-Null
|
Copy-Item -Path "$FFUDevelopmentPath\BuildFFUUnattend\unattend_x64.xml" -Destination "$($osPartitionDriveLetter):\Windows\Panther\Unattend\Unattend.xml" -Force | Out-Null
|
||||||
}
|
}
|
||||||
@@ -4353,6 +4474,35 @@ try {
|
|||||||
Copy-Item -Path "$FFUDevelopmentPath\BuildFFUUnattend\unattend_arm64.xml" -Destination "$($osPartitionDriveLetter):\Windows\Panther\Unattend\Unattend.xml" -Force | Out-Null
|
Copy-Item -Path "$FFUDevelopmentPath\BuildFFUUnattend\unattend_arm64.xml" -Destination "$($osPartitionDriveLetter):\Windows\Panther\Unattend\Unattend.xml" -Force | Out-Null
|
||||||
}
|
}
|
||||||
WriteLog 'Copy completed'
|
WriteLog 'Copy completed'
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($AllowVHDXCaching -and !$cachedVHDXFileFound) {
|
||||||
|
WriteLog 'New cached VHDX created'
|
||||||
|
|
||||||
|
WriteLog 'Defragmenting Windows partition...'
|
||||||
|
Optimize-Volume -DriveLetter $osPartition.DriveLetter -Defrag -NormalPriority
|
||||||
|
WriteLog 'Performing slab consolidation on Windows partition...'
|
||||||
|
Optimize-Volume -DriveLetter $osPartition.DriveLetter -SlabConsolidate -NormalPriority
|
||||||
|
WriteLog 'Dismounting VHDX'
|
||||||
|
Dismount-ScratchVhdx -VhdxPath $VHDXPath
|
||||||
|
|
||||||
|
WriteLog 'Copying to cache dir'
|
||||||
|
|
||||||
|
#Assuming there are now name collisons
|
||||||
|
Robocopy.exe $($VMPath) $($VHDXCacheFolder) $("$VMName.vhdx") /E /COPY:DAT /R:5 /W:5 /J
|
||||||
|
|
||||||
|
#Only create new instance if not created during patching
|
||||||
|
if ($null -eq $cachedVHDXInfo) {
|
||||||
|
$cachedVHDXInfo = [VhdxCacheItem]::new()
|
||||||
|
}
|
||||||
|
$cachedVHDXInfo.VhdxFileName = $("$VMName.vhdx")
|
||||||
|
$cachedVHDXInfo.WindowsSKU = $WindowsSKU
|
||||||
|
$cachedVHDXInfo.WindowsRelease = $WindowsRelease
|
||||||
|
$cachedVHDXInfo.WindowsVersion = $WindowsVersion
|
||||||
|
$cachedVHDXInfo.OptionalFeatures = $OptionalFeatures
|
||||||
|
|
||||||
|
$cachedVHDXInfo | ConvertTo-Json | Out-File -FilePath ("{0}\{1}_config.json" -f $($VHDXCacheFolder), $VMName)
|
||||||
|
} else {
|
||||||
Dismount-ScratchVhdx -VhdxPath $VHDXPath
|
Dismount-ScratchVhdx -VhdxPath $VHDXPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4605,20 +4755,30 @@ If ($CleanupAppsISO) {
|
|||||||
Writelog "Removing $AppsISO failed with error $_"
|
Writelog "Removing $AppsISO failed with error $_"
|
||||||
throw $_
|
throw $_
|
||||||
}
|
}
|
||||||
If ($CleanupDrivers){
|
}
|
||||||
|
If ($CleanupDrivers) {
|
||||||
try {
|
try {
|
||||||
If (Test-Path -Path $Driversfolder\$Make) {
|
If (Test-Path -Path $Driversfolder\$Make) {
|
||||||
WriteLog "Removing $Driversfolder\$Make"
|
WriteLog "Removing $Driversfolder\$Make"
|
||||||
Remove-Item -Path $Driversfolder\$Make -Force -Recurse
|
Remove-Item -Path $Driversfolder\$Make -Force -Recurse
|
||||||
WriteLog "Removal complete"
|
WriteLog 'Removal complete'
|
||||||
}
|
}
|
||||||
}
|
} catch {
|
||||||
catch {
|
|
||||||
Writelog "Removing $Driversfolder\$Make failed with error $_"
|
Writelog "Removing $Driversfolder\$Make failed with error $_"
|
||||||
throw $_
|
throw $_
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if ($AllowVHDXCaching) {
|
||||||
|
try {
|
||||||
|
If (Test-Path -Path $KBPath) {
|
||||||
|
WriteLog "Removing $KBPath"
|
||||||
|
Remove-Item -Path $KBPath -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
WriteLog 'Removal complete'
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Writelog "Removing $KBPath failed with error $_"
|
||||||
|
throw $_
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#Clean up dirty.txt file
|
#Clean up dirty.txt file
|
||||||
Remove-Item -Path .\dirty.txt -Force | out-null
|
Remove-Item -Path .\dirty.txt -Force | out-null
|
||||||
|
|||||||
@@ -1,20 +1,35 @@
|
|||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory = $True, Position = 0)]
|
[Parameter(Mandatory = $True, Position = 0)]
|
||||||
[io.fileinfo] $DeployISOPath,
|
$DeployISOPath,
|
||||||
[Switch]$DisableAutoPlay
|
[Switch]$DisableAutoPlay
|
||||||
)
|
)
|
||||||
|
$Host.UI.RawUI.WindowTitle = 'Imaging Tool USB Creator'
|
||||||
|
|
||||||
|
if($DeployISOPath){
|
||||||
|
$DevelopmentPath = $DeployISOPath | Split-Path
|
||||||
|
$ImagesPath = "$DevelopmentPath\FFU"
|
||||||
function WriteLog($LogText) {
|
function WriteLog($LogText) {
|
||||||
$LogFileName = '\Script.log'
|
$LogFileName = '\Script.log'
|
||||||
$LogFile = $DevelopmentPath + $LogFilename
|
$LogFile = $DevelopmentPath + $LogFilename
|
||||||
Add-Content -path $LogFile -value "$((Get-Date).ToString()) $LogText" -Force -ErrorAction SilentlyContinue
|
Add-Content -path $LogFile -value "$((Get-Date).ToString()) $LogText" -Force -ErrorAction SilentlyContinue
|
||||||
Write-Verbose $LogText
|
Write-Verbose $LogText
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get-USBDrive {
|
function Write-ProgressLog {
|
||||||
$USBDrives = (Get-WmiObject -Class Win32_DiskDrive -Filter "MediaType='Removable Media'")
|
param(
|
||||||
If ($USBDrives -and ($null -eq $USBDrives.count)) {
|
[string]$Activity,
|
||||||
|
[string]$Status
|
||||||
|
)
|
||||||
|
Write-Progress -Activity $Activity -Status $Status -PercentComplete (($currentStep / $totalSteps) * 100)
|
||||||
|
WriteLog $Status
|
||||||
|
$script:currentStep++
|
||||||
|
|
||||||
|
}
|
||||||
|
Function Get-RemovableDrive {
|
||||||
|
writelog "Get information for all removable drives"
|
||||||
|
$USBDrives = Get-WmiObject Win32_DiskDrive | Where-Object {$_.MediaType -eq "Removable media"}
|
||||||
|
If($USBDrives -and ($null -eq $USBDrives.count)) {
|
||||||
$USBDrivesCount = 1
|
$USBDrivesCount = 1
|
||||||
} else {
|
} else {
|
||||||
$USBDrivesCount = $USBDrives.Count
|
$USBDrivesCount = $USBDrives.Count
|
||||||
@@ -24,31 +39,33 @@ function Get-USBDrive {
|
|||||||
if ($null -eq $USBDrives) {
|
if ($null -eq $USBDrives) {
|
||||||
WriteLog "No removable USB drive found. Exiting"
|
WriteLog "No removable USB drive found. Exiting"
|
||||||
Write-Error "No removable USB drive found. Exiting"
|
Write-Error "No removable USB drive found. Exiting"
|
||||||
|
Pause
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
return $USBDrives, $USBDrivesCount
|
return $USBDrives, $USBDrivesCount
|
||||||
}
|
}
|
||||||
|
|
||||||
function Build-DeploymentUSB {
|
Function Build-DeploymentUSB{
|
||||||
param(
|
param(
|
||||||
[Array]$Drives
|
[Array]$Drives
|
||||||
)
|
)
|
||||||
writelog "Checking if ffu files are present in the ffu folder"
|
writelog "Creating list of FFU image files"
|
||||||
$Images = Get-ChildItem -Path $FFUPath -Filter "*.ffu" -File -Recurse
|
$Images = Get-ChildItem -Path $ImagesPath -Filter "*.ffu" -File -Recurse
|
||||||
writelog "Checking if drivers are present in the drivers folder"
|
writelog "Checking if drivers are present in the drivers folder"
|
||||||
$Drivers = Get-ChildItem -Path $DriversPath -Recurse
|
$Drivers = Get-ChildItem -Path $DriversPath -Recurse
|
||||||
$DrivesCount = $Drives.Count
|
$DrivesCount = $Drives.Count
|
||||||
Writelog "Creating partitions..."
|
Write-ProgressLog "Create Imaging Tool" "Creating partitions..."
|
||||||
foreach ($USBDrive in $Drives) {
|
writelog "Create job to partition each usb drive"
|
||||||
$DriveNumber = $USBDrive.DeviceID.Replace("\\.\PHYSICALDRIVE", "")
|
foreach ($USBDrive in $Drives) {
|
||||||
$Model = $USBDrive.model
|
$DriveNumber = $USBDrive.DeviceID.Replace("\\.\PHYSICALDRIVE", "")
|
||||||
$ScriptBlock = {
|
$Model = $USBDrive.model
|
||||||
|
$ScriptBlock = {
|
||||||
param($DriveNumber)
|
param($DriveNumber)
|
||||||
Clear-Disk -Number $DriveNumber -RemoveData -RemoveOEM -Confirm:$false
|
Clear-Disk -Number $DriveNumber -RemoveData -RemoveOEM -Confirm:$false
|
||||||
$Disk = Get-Disk -Number $DriveNumber
|
$Disk = Get-Disk -Number $DriveNumber
|
||||||
$PartitionStyle = $Disk.PartitionStyle
|
$PartitionStyle = $Disk.PartitionStyle
|
||||||
if ($PartitionStyle -ne 'MBR') {
|
if($PartitionStyle -ne 'MBR'){
|
||||||
$Disk | Set-Disk -PartitionStyle MBR
|
$Disk | Set-Disk -PartitionStyle MBR
|
||||||
}
|
}
|
||||||
$BootPartition = New-Partition -DiskNumber $DriveNumber -Size 2GB -IsActive -AssignDriveLetter
|
$BootPartition = New-Partition -DiskNumber $DriveNumber -Size 2GB -IsActive -AssignDriveLetter
|
||||||
$DeployPartition = New-Partition -DiskNumber $DriveNumber -UseMaximumSize -AssignDriveLetter
|
$DeployPartition = New-Partition -DiskNumber $DriveNumber -UseMaximumSize -AssignDriveLetter
|
||||||
@@ -60,178 +77,168 @@ function Build-DeploymentUSB {
|
|||||||
}
|
}
|
||||||
writelog "Wait for partitioning jobs to complete"
|
writelog "Wait for partitioning jobs to complete"
|
||||||
Get-Job | Wait-Job | Out-Null
|
Get-Job | Wait-Job | Out-Null
|
||||||
if ($DrivesCount -gt 1) {
|
if($DrivesCount -gt 1){
|
||||||
writelog "Get file system information for all drives"
|
writelog "Get file system information for all drives"
|
||||||
$Partitions = Get-Partition | Get-Volume
|
$Partitions = Get-Partition | Get-Volume
|
||||||
} else {
|
} else {
|
||||||
writelog "Get file system information for drive number $DiskNumber"
|
writelog "Get file system information for drive number $DiskNumber"
|
||||||
$Partitions = Get-Partition -DiskNumber $DriveNumber | Get-Volume
|
$Partitions = Get-Partition -DiskNumber $DriveNumber | Get-Volume
|
||||||
}
|
}
|
||||||
writelog "Get drive letter for all volumes labeled:BOOT"
|
writelog "Get drive letter for all volumes labeled:BOOT"
|
||||||
$BootDrives = ($Partitions | Where-Object { $_.FileSystemLabel -eq "BOOT" }).DriveLetter
|
$BootDrives = ($Partitions | Where-Object { $_.FileSystemLabel -eq "BOOT"}).DriveLetter
|
||||||
writelog "Get drive letter for all volumes labeled:Deploy"
|
writelog "Get drive letter for all volumes labeled:Deploy"
|
||||||
$DeployDrives = ($Partitions | Where-Object { $_.FileSystemLabel -eq "Deploy" }).DriveLetter
|
$DeployDrives = ($Partitions | Where-Object { $_.FileSystemLabel -eq "Deploy"}).DriveLetter
|
||||||
writelog "Mount Deployment .iso image"
|
writelog "Mount Deployment .iso image"
|
||||||
$ISOMountPoint = (Mount-DiskImage -ImagePath "$DeployISOPath" -PassThru | Get-Volume).DriveLetter + ":\"
|
$ISOMountPoint = (Mount-DiskImage -ImagePath "$DeployISOPath" -PassThru | Get-Volume).DriveLetter + ":\"
|
||||||
writelog "Copying boot files to all drives labeled BOOT concurrently"
|
writelog "Copying boot files to all drives labeled BOOT concurrently"
|
||||||
foreach ($Drive in $BootDrives) {
|
foreach ($Drive in $BootDrives) {
|
||||||
$Destination = $Drive + ":\"
|
$Destination = $Drive + ":\"
|
||||||
$jobScriptBlock = {
|
$jobScriptBlock = {
|
||||||
param (
|
param (
|
||||||
[string]$SFolder,
|
[string]$SFolder,
|
||||||
[string]$DFolder
|
[string]$DFolder
|
||||||
)
|
)
|
||||||
Robocopy $SFolder $DFolder /E /COPYALL /R:5 /W:5 /J
|
Robocopy $SFolder $DFolder /E /COPYALL /R:5 /W:5 /J
|
||||||
}
|
}
|
||||||
WriteLog "Start job to copy all boot files to $Destination"
|
WriteLog "Start job to copy all boot files to $Destination"
|
||||||
Start-Job -ScriptBlock $jobScriptBlock -ArgumentList $ISOMountPoint, $Destination | Out-Null
|
Start-Job -ScriptBlock $jobScriptBlock -ArgumentList $ISOMountPoint, $Destination | Out-Null
|
||||||
|
}
|
||||||
|
if($Images){
|
||||||
|
writelog "Copying FFU image files to all drives labeled deploy concurrently"
|
||||||
|
foreach ($Drive in $DeployDrives) {
|
||||||
|
$Destination = $Drive + ":\"
|
||||||
|
$jobScriptBlock = {
|
||||||
|
param (
|
||||||
|
[string]$SFolder,
|
||||||
|
[string]$DFolder
|
||||||
|
)
|
||||||
|
New-Item -Path $DFolder -ItemType Directory -Force -Confirm: $false | Out-Null
|
||||||
|
Robocopy $SFolder $DFolder /E /COPYALL /R:5 /W:5 /J
|
||||||
}
|
}
|
||||||
if ($Images) {
|
|
||||||
writelog "Copying FFU image files to all drives labeled deploy concurrently"
|
|
||||||
foreach ($Drive in $DeployDrives) {
|
|
||||||
$Destination = $Drive + ":\"
|
|
||||||
$jobScriptBlock = {
|
|
||||||
param (
|
|
||||||
[string]$SFolder,
|
|
||||||
[string]$DFolder
|
|
||||||
)
|
|
||||||
Robocopy $SFolder $DFolder /E /COPYALL /R:5 /W:5 /J
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteLog "Start job to copy all FFU files to $Destination"
|
WriteLog "Start job to copy all FFU files to $Destination"
|
||||||
Start-Job -ScriptBlock $jobScriptBlock -ArgumentList $FFUPath, $Destination | Out-Null
|
Start-Job -ScriptBlock $jobScriptBlock -ArgumentList $ImagesPath, $Destination | Out-Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!($Images)){
|
||||||
|
foreach ($Drive in $DeployDrives) {
|
||||||
|
WriteLog "Create images directory"
|
||||||
|
$drivepath = $Drive + ":\"
|
||||||
|
New-Item -Path "$drivepath" -Name Images -ItemType Directory -Force -Confirm: $false | Out-Null
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if($Drivers){
|
||||||
|
writelog "Copying driver files to all drives labeled deploy concurrently"
|
||||||
|
foreach ($Drive in $DeployDrives) {
|
||||||
|
$Destination = $Drive + ":\Drivers"
|
||||||
|
$jobScriptBlock = {
|
||||||
|
param (
|
||||||
|
[string]$SFolder,
|
||||||
|
[string]$DFolder
|
||||||
|
)
|
||||||
|
New-Item -Path $DFolder -ItemType Directory -Force -Confirm: $false | Out-Null
|
||||||
|
Robocopy $SFolder $DFolder /E /COPYALL /R:5 /W:5 /J
|
||||||
}
|
}
|
||||||
if ($Drivers) {
|
WriteLog "Start job to copy all drivers to $Destination"
|
||||||
writelog "Copying driver files to all drives labeled deploy concurrently"
|
Start-Job -ScriptBlock $jobScriptBlock -ArgumentList $DriversPath, $Destination | Out-Null
|
||||||
foreach ($Drive in $DeployDrives) {
|
}
|
||||||
$Destination = $Drive + ":\Drivers"
|
}
|
||||||
$jobScriptBlock = {
|
if(!($Drivers)){
|
||||||
param (
|
foreach ($Drive in $DeployDrives) {
|
||||||
[string]$SFolder,
|
WriteLog "Create drivers directory"
|
||||||
[string]$DFolder
|
$drivepath = $Drive + ":\"
|
||||||
)
|
New-Item -Path "$drivepath" -Name Drivers -ItemType Directory -Force -Confirm: $false | Out-Null
|
||||||
New-Item -Path $DFolder -ItemType Directory -Force -Confirm: $false | Out-Null
|
|
||||||
Robocopy $SFolder $DFolder /E /COPYALL /R:5 /W:5 /J
|
|
||||||
}
|
|
||||||
WriteLog "Start job to copy all drivers to $Destination"
|
|
||||||
Start-Job -ScriptBlock $jobScriptBlock -ArgumentList $DriversPath, $Destination | Out-Null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!($Drivers)) {
|
if($DrivesCount -gt 1){
|
||||||
foreach ($Drive in $DeployDrives) {
|
Write-ProgressLog "Create Imaging Tool" "Building $DrivesCount drives concurrently...Please be patient..."
|
||||||
WriteLog "Create drivers directory"
|
} else {
|
||||||
$drivepath = $Drive + ":\"
|
Write-ProgressLog "Create Imaging Tool" "Building the imaging tool on $model...Please be patient..."
|
||||||
New-Item -Path "$drivepath" -Name Drivers -ItemType Directory -Force -Confirm: $false | Out-Null
|
}
|
||||||
}
|
Get-Job | Wait-Job | Out-Null
|
||||||
}
|
|
||||||
if ($DrivesCount -gt 1) {
|
|
||||||
Writelog "Building $DrivesCount drives concurrently...Please be patient..."
|
|
||||||
} else {
|
|
||||||
Writelog "Building the imaging tool on $model...Please be patient..."
|
|
||||||
}
|
|
||||||
Get-Job | Wait-Job | Out-Null
|
|
||||||
|
|
||||||
Dismount-DiskImage -ImagePath $DeployISOPath | Out-Null
|
Dismount-DiskImage -ImagePath $DeployISOPath | Out-Null
|
||||||
Writelog "Drive creation jobs completed..."
|
Write-ProgressLog "Create Imaging Tool" "Drive creation jobs completed..."
|
||||||
}
|
}
|
||||||
|
|
||||||
function New-DeploymentUSB {
|
Function New-DeploymentUSB {
|
||||||
param(
|
param(
|
||||||
[Array]$Drives,
|
[Array]$Drives,
|
||||||
[int]$Count,
|
[int]$Count,
|
||||||
[String]$FFUPath = "$DevelopmentPath\FFU",
|
[String]$FFUPath = "$DevelopmentPath\FFU",
|
||||||
[String]$DriversPath = "$DevelopmentPath\Drivers"
|
[String]$DriversPath = "$DevelopmentPath\Drivers"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
$Drivelist = @()
|
$Drivelist = @()
|
||||||
writelog "Creating a USB drive selection list"
|
writelog "Creating a USB drive selection list"
|
||||||
for ($i = 0; $i -le $Count - 1; $i++) {
|
for($i=0;$i -le $Count -1;$i++){
|
||||||
$DriveModel = $Drives[$i].Model
|
$DriveModel = $Drives[$i].Model
|
||||||
$DriveSize = [math]::round($Drives[$i].size / 1GB, 2)
|
$DriveSize = [math]::round($Drives[$i].size/1GB, 2)
|
||||||
$DiskNumber = $Drives[$i].DeviceID.Replace("\\.\PHYSICALDRIVE", "")
|
$DiskNumber = $Drives[$i].DeviceID.Replace("\\.\PHYSICALDRIVE", "")
|
||||||
$Properties = [ordered]@{Number = $i + 1 ; DriveNumber = $DiskNumber ; DriveModel = $driveModel ; 'Size (GB)' = $DriveSize }
|
$Properties = [ordered]@{Number = $i + 1 ; DriveNumber = $DiskNumber ; DriveModel = $driveModel ; 'Size (GB)' = $DriveSize}
|
||||||
|
|
||||||
$Drivelist += New-Object PSObject -Property $Properties
|
$Drivelist += New-Object PSObject -Property $Properties
|
||||||
}
|
}
|
||||||
if ($Count -gt 1) {
|
if($Count -gt 1){
|
||||||
$Last = $Count + 1
|
$Last = $Count+1
|
||||||
$Drivelist += New-Object -TypeName PSObject -Property @{ Number = "$last"; DriveModel = "Select this option to use all ($count) inserted USB Drives" }
|
$Drivelist += New-Object -TypeName PSObject -Property @{ Number = "$last"; DriveModel = "Select this option to use all ($count) inserted USB Drives" }
|
||||||
}
|
}
|
||||||
$Drivelist | Format-Table -AutoSize -Property Number, DriveModel , 'Size (GB)'
|
$Drivelist | Format-Table -AutoSize -Property Number, DriveModel , 'Size (GB)'
|
||||||
do {
|
do {
|
||||||
try {
|
try {
|
||||||
$var = $true
|
$var = $true
|
||||||
$DriveSelected = Read-Host 'Enter the drive number to apply the .iso to'
|
$DriveSelected = Read-Host 'Enter the drive number to apply the .iso to'
|
||||||
$DriveSelected = ($DriveSelected -as [int]) - 1
|
$DriveSelected = ($DriveSelected -as [int]) -1
|
||||||
if ($Last) {
|
writelog "Drive $DriveSelected selected"
|
||||||
writelog "All drives selected"
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
writelog "Drive $DriveSelected selected"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
catch {
|
||||||
Write-Host 'Input was not in correct format. Please enter a valid FFU number'
|
Write-Host 'Input was not in correct format. Please enter a valid FFU number'
|
||||||
$var = $false
|
$var = $false
|
||||||
}
|
}
|
||||||
} until (($DriveSelected -le $Count - 1 -or $last) -and $var)
|
} until (($DriveSelected -le $Count -1 -or $last) -and $var)
|
||||||
|
if($DisableAutoPlay){
|
||||||
$DisableAutoPlayCurrentSetting = (Get-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers" -Name DisableAutoplay).DisableAutoplay
|
WriteLog "Setting the registry key to disable autoplay for all drives"
|
||||||
if ($DisableAutoPlay -and $DisableAutoPlayCurrentSetting -ne 1) {
|
Set-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers" -Name "DisableAutoplay" -Value 1 -Type DWORD
|
||||||
writelog "Disable autoPlay current setting is $DisableAutoPlayCurrentSetting"
|
|
||||||
WriteLog "Setting the registry key to disable autoplay for all drives"
|
|
||||||
Set-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers" -Name "DisableAutoplay" -Value 1 -Type DWORD
|
|
||||||
}
|
}
|
||||||
WriteLog "Closing all MMC windows to prevent drive lock errors"
|
WriteLog "Closing all MMC windows to prevent drive lock errors"
|
||||||
Stop-Process -Name mmc -ErrorAction SilentlyContinue
|
Stop-Process -Name mmc -ErrorAction SilentlyContinue
|
||||||
WriteLog "Closing all Diskpart windows to prevent drive lock errors"
|
WriteLog "Closing all Diskpart windows to prevent drive lock errors"
|
||||||
Stop-Process -Name diskpart -ErrorAction SilentlyContinue
|
Stop-Process -Name diskpart -ErrorAction SilentlyContinue
|
||||||
$Selection = $Drivelist[$DriveSelected].Number
|
$Selection = $Drivelist[$DriveSelected].Number
|
||||||
|
$totalSteps = 5
|
||||||
if ($Selection -eq $last) {
|
if($Selection -eq $last){
|
||||||
Read-Host -Prompt "ALL DRIVES SELECTED! WILL ERASE ALL CURRENTLY CONNECTED USB DRIVES!! Press ENTER to continue"
|
Read-Host -Prompt "ALL DRIVES SELECTED! WILL ERASE ALL CURRENTLY CONNECTED USB DRIVES!! Press ENTER to continue"
|
||||||
Build-DeploymentUSB -Drives $Drives
|
Build-DeploymentUSB -Drives $Drives
|
||||||
} else {
|
} else {
|
||||||
Read-Host -Prompt "Drive number $Selection was selected. Press ENTER to continue"
|
Read-Host -Prompt "Drive number $Selection was selected. Press ENTER to continue"
|
||||||
Build-DeploymentUSB -Drives $Drives[$DriveSelected]
|
Build-DeploymentUSB -Drives $Drives[$DriveSelected]
|
||||||
}
|
}
|
||||||
WriteLog "Setting the registry key to re-enable autoplay for all drives"
|
WriteLog "Setting the registry key to re-enable autoplay for all drives"
|
||||||
if ($DisableAutoPlay) {
|
if($DisableAutoPlay){
|
||||||
Writelog "Setting disable autoplay setting back to $DisableAutoPlayCurrentSetting"
|
Write-ProgressLog "Create Imaging Tool" "Enabling Autoplay"
|
||||||
Set-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers" -Name "DisableAutoplay" -Value $DisableAutoPlayCurrentSetting -Type DWORD
|
Set-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers" -Name "DisableAutoplay" -Value 0 -Type DWORD
|
||||||
}
|
}
|
||||||
Writelog "Completed!"
|
Write-ProgressLog "Create Imaging Tool" "Completed!"
|
||||||
|
}
|
||||||
|
#Get USB Drive and create log file
|
||||||
|
if(Test-Path "$DevelopmentPath\Script.log"){
|
||||||
|
Remove-Item -Path "$DevelopmentPath\Script.log" -Force -Confirm:$false
|
||||||
|
New-item -Path $DevelopmentPath -Name 'Script.log' -ItemType "file" -Force | Out-Null
|
||||||
}
|
}
|
||||||
|
WriteLog 'Begin Logging'
|
||||||
|
WriteLog 'Getting USB drive information and usb drive count'
|
||||||
|
$USBDrives,$USBDrivesCount = Get-RemovableDrive
|
||||||
|
WriteLog 'Setting first step for percentage progress bar'
|
||||||
|
$currentStep = 1
|
||||||
|
New-DeploymentUSB -Drives $USBDrives -Count $USBDrivesCount
|
||||||
|
|
||||||
$Host.UI.RawUI.WindowTitle = 'USB Imaging Tool Creator'
|
read-host -Prompt "USB drive creation complete. Press ENTER to exit"
|
||||||
|
|
||||||
# Check if path is relative
|
Exit
|
||||||
if (-not [System.IO.Path]::IsPathRooted($DeployISOPath)) {
|
|
||||||
# Path is relative, Build full path
|
|
||||||
[io.fileinfo] $DeployISOPath = (Resolve-Path $DeployISOPath).Path
|
|
||||||
Write-Verbose "Path to ISO was relative. Attempting to resolve at: $($DeployISOPath.FullName)"
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($DeployISOPath.Exists) {
|
|
||||||
$DevelopmentPath = $DeployISOPath.Directory.FullName
|
|
||||||
|
|
||||||
#Get USB Drive and create log file
|
|
||||||
if (Test-Path "$DevelopmentPath\Script.log") {
|
|
||||||
Remove-Item -Path "$DevelopmentPath\Script.log" -Force -Confirm:$false
|
|
||||||
New-item -Path $DevelopmentPath -Name 'Script.log' -ItemType "file" -Force | Out-Null
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteLog 'Begin Logging'
|
|
||||||
WriteLog 'Getting USB drive information and usb drive count'
|
|
||||||
|
|
||||||
$USBDrives, $USBDrivesCount = Get-USBDrive
|
|
||||||
|
|
||||||
New-DeploymentUSB -Drives $USBDrives -Count $USBDrivesCount
|
|
||||||
|
|
||||||
Read-Host -Prompt "USB drive creation complete. Press ENTER to exit"
|
|
||||||
Exit
|
|
||||||
} else {
|
} else {
|
||||||
Write-Error "Unable to locate ISO file at: $($DeployISOPath.FullName)"
|
Write-Host "No .ISO file selected..."
|
||||||
|
read-host "Press ENTER to Exit..."
|
||||||
|
Exit
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#Modify the net use W: \\192.168.1.158\FFUCaptureShare /user:ffu_user ddb1f077-3eed-433c-b4d9-7b8cd54ce727
|
#Modify the net use W: \\192.168.1.158\FFUCaptureShare /user:ffu_user ddb1f077-3eed-433c-b4d9-7b8cd54ce727
|
||||||
net use W: \\192.168.1.158\FFUCaptureShare /user:ffu_user ddb1f077-3eed-433c-b4d9-7b8cd54ce727
|
net use W: \\192.168.1.158\FFUCaptureShare /user:ffu_user ddb1f077-3eed-433c-b4d9-7b8cd54ce727
|
||||||
|
#Custom naming placeholder
|
||||||
|
|
||||||
$AssignDriveLetter = 'x:\AssignDriveLetter.txt'
|
$AssignDriveLetter = 'x:\AssignDriveLetter.txt'
|
||||||
Start-Process -FilePath diskpart.exe -ArgumentList "/S $AssignDriveLetter" -Wait -ErrorAction Stop | Out-Null
|
Start-Process -FilePath diskpart.exe -ArgumentList "/S $AssignDriveLetter" -Wait -ErrorAction Stop | Out-Null
|
||||||
@@ -12,7 +13,7 @@ reg load "HKLM\FFU" $Software
|
|||||||
$SKU = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'EditionID'
|
$SKU = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'EditionID'
|
||||||
[int]$CurrentBuild = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'CurrentBuild'
|
[int]$CurrentBuild = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'CurrentBuild'
|
||||||
if ($CurrentBuild -notin 14393, 17763) {
|
if ($CurrentBuild -notin 14393, 17763) {
|
||||||
$DisplayVersion = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'DisplayVersion'
|
$WindowsVersion = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'DisplayVersion'
|
||||||
}
|
}
|
||||||
$InstallationType = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'InstallationType'
|
$InstallationType = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'InstallationType'
|
||||||
$BuildDate = Get-Date -uformat %b%Y
|
$BuildDate = Get-Date -uformat %b%Y
|
||||||
@@ -37,48 +38,63 @@ $SKU = switch ($SKU) {
|
|||||||
|
|
||||||
if ($InstallationType -eq "Client") {
|
if ($InstallationType -eq "Client") {
|
||||||
if ($CurrentBuild -ge 22000) {
|
if ($CurrentBuild -ge 22000) {
|
||||||
$Name = 'Win11'
|
$WindowsRelease = 'Win11'
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$Name = 'Win10'
|
$WindowsRelease = 'Win10'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$Name = switch ($CurrentBuild) {
|
$WindowsRelease = switch ($CurrentBuild) {
|
||||||
26100 { '2025' }
|
26100 { '2025' }
|
||||||
20348 { '2022' }
|
20348 { '2022' }
|
||||||
17763 { '2019' }
|
17763 { '2019' }
|
||||||
14393 { '2016' }
|
14393 { '2016' }
|
||||||
Default { $DisplayVersion }
|
Default { $WindowsVersion }
|
||||||
}
|
}
|
||||||
if ($InstallationType -eq "Server Core") {
|
if ($InstallationType -eq "Server Core") {
|
||||||
$SKU += "_Core"
|
$SKU += "_Core"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#If Office is installed, modify the file name of the FFU
|
if ($CustomFFUNameTemplate) {
|
||||||
#$Office = Get-childitem -Path 'M:\Program Files\Microsoft Office' -ErrorAction SilentlyContinue | Out-Null
|
$CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{WindowsRelease}', $WindowsRelease
|
||||||
$Office = Get-childitem -Path 'M:\Program Files\Microsoft Office' -ErrorAction SilentlyContinue
|
$CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{WindowsVersion}', $WindowsVersion
|
||||||
if($Office){
|
$CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{SKU}', $SKU
|
||||||
$ffuFilePath = "W:\$Name`_$DisplayVersion`_$SKU`_Office`_$BuildDate.ffu"
|
$CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{BuildDate}', $BuildDate
|
||||||
$dismArgs = "/capture-ffu /imagefile=$ffuFilePath /capturedrive=\\.\PhysicalDrive0 /name:$Name$DisplayVersion$SKU /Compress:Default"
|
$CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{yyyy}', (Get-Date -UFormat '%Y')
|
||||||
|
$CustomFFUNameTemplate = $CustomFFUNameTemplate -creplace '{MM}', (Get-Date -UFormat '%m')
|
||||||
|
$CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{dd}', (Get-Date -UFormat '%d')
|
||||||
}
|
$CustomFFUNameTemplate = $CustomFFUNameTemplate -creplace '{HH}', (Get-Date -UFormat '%H')
|
||||||
else{
|
$CustomFFUNameTemplate = $CustomFFUNameTemplate -creplace '{hh}', (Get-Date -UFormat '%I')
|
||||||
$ffuFilePath = "W:\$Name`_$DisplayVersion`_$SKU`_Apps`_$BuildDate.ffu"
|
$CustomFFUNameTemplate = $CustomFFUNameTemplate -creplace '{mm}', (Get-Date -UFormat '%M')
|
||||||
$dismArgs = "/capture-ffu /imagefile=$ffuFilePath /capturedrive=\\.\PhysicalDrive0 /name:$Name$DisplayVersion$SKU /Compress:Default"
|
$CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{tt}', (Get-Date -UFormat '%p')
|
||||||
|
if($CustomFFUNameTemplate -notlike '*.ffu') {
|
||||||
|
$CustomFFUNameTemplate += '.ffu'
|
||||||
|
}
|
||||||
|
$dismArgs = "/capture-ffu /imagefile=W:\$CustomFFUNameTemplate /capturedrive=\\.\PhysicalDrive0 /name:$WindowsRelease$WindowsVersion$SKU /Compress:Default"
|
||||||
|
} else {
|
||||||
|
#If Office is installed, modify the file name of the FFU
|
||||||
|
#$Office = Get-childitem -Path 'M:\Program Files\Microsoft Office' -ErrorAction SilentlyContinue | Out-Null
|
||||||
|
$Office = Get-ChildItem -Path 'M:\Program Files\Microsoft Office' -ErrorAction SilentlyContinue
|
||||||
|
if ($Office) {
|
||||||
|
$ffuFilePath = "W:\$WindowsRelease`_$WindowsVersion`_$SKU`_Office`_$BuildDate.ffu"
|
||||||
|
} else {
|
||||||
|
$ffuFilePath = "W:\$WindowsRelease`_$WindowsVersion`_$SKU`_Apps`_$BuildDate.ffu"
|
||||||
|
}
|
||||||
|
$dismArgs = "/capture-ffu /imagefile=$ffuFilePath /capturedrive=\\.\PhysicalDrive0 /name:$WindowsRelease$WindowsVersion$SKU /Compress:Default"
|
||||||
}
|
}
|
||||||
|
|
||||||
#Unload Registry
|
#Unload Registry
|
||||||
Set-Location X:\
|
Set-Location X:\
|
||||||
Remove-Variable SKU
|
Remove-Variable SKU
|
||||||
if ($CurrentBuild -notin 14393, 17763) {
|
|
||||||
Remove-Variable DisplayVersion
|
|
||||||
}
|
|
||||||
Remove-Variable CurrentBuild
|
Remove-Variable CurrentBuild
|
||||||
Remove-Variable Office
|
if ($CurrentBuild -notin 14393, 17763) {
|
||||||
|
Remove-Variable WindowsVersion
|
||||||
|
}
|
||||||
|
if($Office) {
|
||||||
|
Remove-Variable Office
|
||||||
|
}
|
||||||
reg unload "HKLM\FFU"
|
reg unload "HKLM\FFU"
|
||||||
#This prevents Critical Process Died errors you can have during deployment of the FFU - may not happen during capture from WinPE, but adding here to be consistent with VHDX capture
|
#This prevents Critical Process Died errors you can have during deployment of the FFU - may not happen during capture from WinPE, but adding here to be consistent with VHDX capture
|
||||||
Write-Host "Sleeping for 60 seconds to allow registry to unload prior to capture"
|
Write-Host "Sleeping for 60 seconds to allow registry to unload prior to capture"
|
||||||
@@ -86,5 +102,4 @@ Start-sleep 60
|
|||||||
Start-Process -FilePath dism.exe -ArgumentList $dismArgs -Wait -PassThru -ErrorAction Stop | Out-Null
|
Start-Process -FilePath dism.exe -ArgumentList $dismArgs -Wait -PassThru -ErrorAction Stop | Out-Null
|
||||||
#Copy DISM log to Host
|
#Copy DISM log to Host
|
||||||
xcopy X:\Windows\logs\dism\dism.log W:\ /Y | Out-Null
|
xcopy X:\Windows\logs\dism\dism.log W:\ /Y | Out-Null
|
||||||
|
|
||||||
wpeutil Shutdown
|
wpeutil Shutdown
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<unattend xmlns="urn:schemas-microsoft-com:unattend" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
|
||||||
|
<settings pass="specialize">
|
||||||
|
<!--<ComputerName> must be in the first Component Element "Microsoft-Windows-Shell-Setup" . Do not change the order or remove it -->
|
||||||
|
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<ComputerName>MYCOMPUTER</ComputerName><!--Leave Default will be renamed-->
|
||||||
|
<TimeZone>Eastern Standard Time</TimeZone><!--Add Your Local TimeZone-->
|
||||||
|
</component>
|
||||||
|
<!-- Place additional Components Elements and Settings below here: -->
|
||||||
|
<component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<RunASynchronous>
|
||||||
|
<RunASynchronousCommand wcm:action="add">
|
||||||
|
<Order>1</Order>
|
||||||
|
<Path>cmd.exe /c date 09-07-2024</Path> <!--Set the device clock to the current date. Helpful when BIOS clocks out of sync. -->
|
||||||
|
<Description>Set system date to a specific date</Description>
|
||||||
|
</RunASynchronousCommand>
|
||||||
|
</RunASynchronous>
|
||||||
|
</component>
|
||||||
|
</settings>
|
||||||
|
<settings pass="oobeSystem">
|
||||||
|
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
|
<InputLocale>0409:00000409</InputLocale><!--Set your Keybaord and System Local https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-8.1-and-8/hh825682(v=win.10) -->
|
||||||
|
<SystemLocale>en-US</SystemLocale>
|
||||||
|
<UILanguage>en-US</UILanguage>
|
||||||
|
<UserLocale>en-US</UserLocale>
|
||||||
|
</component>
|
||||||
|
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
|
<OOBE>
|
||||||
|
<ProtectYourPC>3</ProtectYourPC> <!--Disable Diagnostic Data sent to Microsoft-->
|
||||||
|
<HideEULAPage>true</HideEULAPage><!--Hide the End User License agreement -->
|
||||||
|
<HideWirelessSetupInOOBE>false</HideWirelessSetupInOOBE> <!--Show Wifi Setup -->
|
||||||
|
</OOBE>
|
||||||
|
</component>
|
||||||
|
</settings>
|
||||||
|
</unattend>
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<unattend xmlns="urn:schemas-microsoft-com:unattend">
|
<unattend xmlns="urn:schemas-microsoft-com:unattend">
|
||||||
<settings pass="specialize">
|
<settings pass="specialize">
|
||||||
|
<!--<ComputerName> must be in the first Component Element "Microsoft-Windows-Shell-Setup" . Do not change the order or remove it -->
|
||||||
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="arm64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="arm64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
<ComputerName>MyComputer</ComputerName>
|
<ComputerName>MyComputer</ComputerName>
|
||||||
</component>
|
</component>
|
||||||
|
<!--Place addtional Components Elements and settings below here. -->
|
||||||
</settings>
|
</settings>
|
||||||
</unattend>
|
</unattend>
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<unattend xmlns="urn:schemas-microsoft-com:unattend">
|
<unattend xmlns="urn:schemas-microsoft-com:unattend">
|
||||||
<settings pass="specialize">
|
<settings pass="specialize">
|
||||||
|
<!--<ComputerName> must be in the first Component Element "Microsoft-Windows-Shell-Setup" . Do not change the order or remove it -->
|
||||||
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
<ComputerName>MyComputer</ComputerName>
|
<ComputerName>MyComputer</ComputerName>
|
||||||
</component>
|
</component>
|
||||||
|
<!--Place addtional Components Elements and settings below here. -->
|
||||||
</settings>
|
</settings>
|
||||||
</unattend>
|
</unattend>
|
||||||
|
|||||||
Reference in New Issue
Block a user