mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-14 02:09:35 -06:00
revamped automation
This commit is contained in:
@@ -0,0 +1,563 @@
|
||||
#Requires -Modules Hyper-V, Storage
|
||||
#Requires -PSEdition Desktop
|
||||
|
||||
# To do list (will get around to this stuff sometime next week)
|
||||
|
||||
# Change from using variables to parameters - this way you don't even need to open the script to edit it.
|
||||
# Clean up the output it sends to powershell so you know what step you're on
|
||||
# Do some real logging incase folks get in trouble and need my help
|
||||
# Edit the WinPECaptureFFUFiles\CaptureFFU.ps1 file within this script instead of doing it manually.
|
||||
# Make Capture/Deploy media creation optional
|
||||
# Change DownloadFFU.xml file to match C:\FFUDevelopment path
|
||||
# If drivers = true, check if drivers folder exists
|
||||
# C:\VM\VMFolder isn't being deleted
|
||||
|
||||
#Modify Required variables
|
||||
$ISOPath = "E:\software\ISOs\Windows\Windows 11\en-us_windows_11_consumer_editions_version_22h2_updated_feb_2023_x64_dvd_4fa87138.iso"
|
||||
$WindowsSKU = 'Pro'
|
||||
$FFUDevelopmentPath = 'C:\FFUDevelopment'
|
||||
$AppsISO = "$FFUDevelopmentPath\Apps.iso"
|
||||
$AppsPath = "$FFUDevelopmentPath\Apps"
|
||||
$InstallOffice = $true
|
||||
$InstallApps = $true
|
||||
$InstallDrivers = $true
|
||||
$memory = 8GB
|
||||
$disksize = 30GB
|
||||
$processors = 4
|
||||
$VMSwitchName = '*intel*'
|
||||
|
||||
#Optional variables
|
||||
$rand = get-random
|
||||
$VMName = "_FFU-$rand"
|
||||
$VMLocation = "c:\VM"
|
||||
$VMPath = $VMLocation + $VMName
|
||||
$VHDXPath = "$VMPath\$VMName.vhdx"
|
||||
|
||||
#FUNCTIONS
|
||||
Function Get-ADK {
|
||||
# Define the registry key and value name to query
|
||||
$adkRegKey = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots"
|
||||
$adkRegValueName = "KitsRoot10"
|
||||
|
||||
# Check if the registry key exists
|
||||
if (Test-Path $adkRegKey) {
|
||||
# Get the registry value for the Windows ADK installation path
|
||||
$adkPath = (Get-ItemProperty -Path $adkRegKey -Name $adkRegValueName).$adkRegValueName
|
||||
|
||||
if ($adkPath) {
|
||||
return $adkPath
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw "Windows ADK is not installed or the installation path could not be found."
|
||||
}
|
||||
}
|
||||
function Get-ODTURL {
|
||||
|
||||
[String]$MSWebPage = Invoke-RestMethod 'https://www.microsoft.com/en-us/download/confirmation.aspx?id=49117'
|
||||
|
||||
$MSWebPage | ForEach-Object {
|
||||
if ($_ -match 'url=(https://.*officedeploymenttool.*\.exe)') {
|
||||
$matches[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Get-Office {
|
||||
#Download ODT
|
||||
$ODTUrl = Get-ODTURL
|
||||
$ODTInstallFile = "$env:TEMP\odtsetup.exe"
|
||||
Invoke-WebRequest -Uri $ODTUrl -OutFile $ODTInstallFile
|
||||
|
||||
# Extract ODT
|
||||
$ODTPath = "$AppsPath\Office"
|
||||
Start-Process -FilePath $ODTInstallFile -ArgumentList "/extract:$ODTPath /quiet" -Wait
|
||||
|
||||
# Run setup.exe with config.xml
|
||||
$ConfigXml = "$ODTPath\DownloadFFU.xml"
|
||||
#Set-Location $ODTPath
|
||||
Start-Process -FilePath "$ODTPath\setup.exe" -ArgumentList "/download $ConfigXml" -Wait
|
||||
|
||||
#Clean up default configuration files
|
||||
Remove-Item -Path "$ODTPath\configuration*" -Force
|
||||
}
|
||||
|
||||
function New-AppsISO {
|
||||
#Create Apps ISO file
|
||||
$OSCDIMG = 'C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg\oscdimg.exe'
|
||||
Start-Process -FilePath $OSCDIMG -ArgumentList "-n -m -d $Appspath $AppsISO" -wait
|
||||
|
||||
#Remove the Office Download and ODT
|
||||
if ($InstallOffice) {
|
||||
$ODTPath = "$AppsPath\Office"
|
||||
$OfficeDownloadPath = "$ODTPath\Office"
|
||||
Remove-Item -Path $OfficeDownloadPath -Recurse -Force
|
||||
Remove-Item -Path "$ODTPath\setup.exe"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function Get-WimFromISO {
|
||||
# Mount the ISO file using Mount-DiskImage cmdlet
|
||||
$mountResult = Mount-DiskImage -ImagePath $isoPath -PassThru
|
||||
|
||||
# Get the drive letter of the mounted ISO
|
||||
$driveLetter = ($mountResult | Get-Volume).DriveLetter
|
||||
|
||||
# Construct the path to the install.wim file
|
||||
$wimPath = $driveLetter + ":\sources\install.wim"
|
||||
|
||||
# Display the path to the install.wim file
|
||||
Write-Host "The path to the install.wim file is: $wimPath"
|
||||
|
||||
return $wimpath
|
||||
|
||||
}
|
||||
|
||||
function Get-WimIndex {
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$WindowsSKU
|
||||
|
||||
$wimindex = switch ($WindowsSKU) {
|
||||
Home { 1 }
|
||||
Home_N { 2 }
|
||||
Home_SL { 3 }
|
||||
EDU { 4 }
|
||||
EDU_N { 5 }
|
||||
Pro { 6 }
|
||||
Pro_N { 7 }
|
||||
Pro_EDU { 8 }
|
||||
Pro_Edu_N { 9 }
|
||||
Pro_WKS { 10 }
|
||||
Pro_WKS_N { 11 }
|
||||
Default { 6 }
|
||||
}
|
||||
Return $WimIndex
|
||||
}
|
||||
|
||||
#Build VHDX
|
||||
#Create VHDX
|
||||
function New-ScratchVhdx {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$VhdxPath,
|
||||
[uint64]$SizeBytes = 30GB,
|
||||
[ValidateSet(512, 4096)]
|
||||
[uint32]$LogicalSectorSizeBytes = 512,
|
||||
[switch]$Dynamic,
|
||||
[Microsoft.PowerShell.Cmdletization.GeneratedTypes.Disk.PartitionStyle]$PartitionStyle = [Microsoft.PowerShell.Cmdletization.GeneratedTypes.Disk.PartitionStyle]::GPT
|
||||
)
|
||||
|
||||
Write-Host "Creating new Scratch VHDX..."
|
||||
|
||||
$newVHDX = New-VHD -Path $VhdxPath -SizeBytes $disksize -LogicalSectorSizeBytes $LogicalSectorSizeBytes -Fixed:$true
|
||||
$toReturn = $newVHDX | Mount-VHD -Passthru | Initialize-Disk -PassThru -PartitionStyle GPT
|
||||
|
||||
#Remove auto-created system partition so we can create the correct partition layout
|
||||
remove-partition $toreturn.DiskNumber -PartitionNumber 1 -Confirm:$False
|
||||
|
||||
Write-Host "Done."
|
||||
return $toReturn
|
||||
}
|
||||
#Add System Partition
|
||||
function New-SystemPartition {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ciminstance]$VhdxDisk,
|
||||
[uint64]$SystemPartitionSize = 256MB
|
||||
)
|
||||
|
||||
Write-Host "Creating System partition..."
|
||||
|
||||
$sysPartition = $VhdxDisk | New-Partition -AssignDriveLetter -Size $SystemPartitionSize -GptType "{c12a7328-f81f-11d2-ba4b-00a0c93ec93b}" -IsHidden
|
||||
$sysPartition | Format-Volume -FileSystem FAT32 -Force -NewFileSystemLabel "System"
|
||||
|
||||
Write-Host "Done. System partition at drive $($sysPartition.DriveLetter):"
|
||||
return $sysPartition.DriveLetter
|
||||
}
|
||||
#Add MSRPartition - skip this initially unless needed
|
||||
function New-MSRPartition {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ciminstance]$VhdxDisk
|
||||
)
|
||||
|
||||
Write-Host "Creating MSR partition..."
|
||||
|
||||
$toReturn = $VhdxDisk | New-Partition -AssignDriveLetter -Size 16MB -GptType "{e3c9e316-0b5c-4db8-817d-f92df00215ae}" -IsHidden
|
||||
|
||||
Write-Host "Done."
|
||||
|
||||
return $toReturn
|
||||
}
|
||||
#Add OS Partition
|
||||
function New-OSPartition {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ciminstance]$VhdxDisk,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$WimPath,
|
||||
[uint32]$WimIndex,
|
||||
[uint64]$OSPartitionSize = 0
|
||||
)
|
||||
|
||||
Write-Host "Creating OS partition..."
|
||||
|
||||
if ($OSPartitionSize -gt 0) {
|
||||
$osPartition = $vhdxDisk | New-Partition -AssignDriveLetter -Size $OSPartitionSize
|
||||
}
|
||||
else {
|
||||
$osPartition = $vhdxDisk | New-Partition -AssignDriveLetter -UseMaximumSize
|
||||
}
|
||||
|
||||
$osPartition | Format-Volume -FileSystem NTFS -Confirm:$false -Force -NewFileSystemLabel "Windows"
|
||||
Write-Host "Done. OS partition at drive $($osPartition.DriveLetter):"
|
||||
|
||||
Write-Host "Writing WIM at $WimPath to OS partition at drive $($osPartition.DriveLetter):..."
|
||||
|
||||
#Server 2019 is missing the Windows Overlay Filter (wof.sys), likely other Server SKUs are missing it as well. Script will error if trying to use the -compact switch on Server OSes
|
||||
if ((Get-CimInstance Win32_OperatingSystem).Caption -match "Server") {
|
||||
Write-Host (Expand-WindowsImage -ImagePath $WimPath -Index $WimIndex -ApplyPath "$($osPartition.DriveLetter):\")
|
||||
}
|
||||
else {
|
||||
Write-Host (Expand-WindowsImage -ImagePath $WimPath -Index $WimIndex -ApplyPath "$($osPartition.DriveLetter):\" -Compact)
|
||||
}
|
||||
|
||||
Write-Host "Done."
|
||||
|
||||
return $osPartition
|
||||
}
|
||||
|
||||
#Add Recovery partition
|
||||
function New-RecoveryPartition {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ciminstance]$VhdxDisk,
|
||||
[Parameter(Mandatory = $true)]
|
||||
$OsPartition,
|
||||
[uint64]$RecoveryPartitionSize = 0,
|
||||
[ciminstance]$DataPartition
|
||||
)
|
||||
|
||||
Write-Host "Creating empty Recovery partition (to be filled on first boot automatically)..."
|
||||
|
||||
$calculatedRecoverySize = 0
|
||||
$recoveryPartition = $null
|
||||
|
||||
if ($RecoveryPartitionSize -gt 0) {
|
||||
$calculatedRecoverySize = $RecoveryPartitionSize
|
||||
}
|
||||
else {
|
||||
$winReWim = Get-ChildItem "$($OsPartition.DriveLetter):\Windows\System32\Recovery\Winre.wim"
|
||||
|
||||
if (($null -ne $winReWim) -and ($winReWim.Count -eq 1)) {
|
||||
# Wim size + 52MB is minimum WinRE partition size.
|
||||
# NTFS and other partitioning size differences account for about 17MB of space that's unavailable.
|
||||
# Adding 32MB as a buffer to ensure there's enough space.
|
||||
$calculatedRecoverySize = $winReWim.Length + 52MB + 32MB
|
||||
|
||||
Write-Host "Calculated space needed for recovery in bytes: $calculatedRecoverySize"
|
||||
|
||||
if ($null -ne $DataPartition) {
|
||||
$DataPartition | Resize-Partition -Size ($DataPartition.Size - $calculatedRecoverySize)
|
||||
Write-Host "Data partition shrunk by $calculatedRecoverySize bytes for Recovery partition."
|
||||
}
|
||||
else {
|
||||
$OsPartition | Resize-Partition -Size ($OsPartition.Size - $calculatedRecoverySize)
|
||||
Write-Host "OS partition shrunk by $calculatedRecoverySize bytes for Recovery partition."
|
||||
}
|
||||
|
||||
$recoveryPartition = $VhdxDisk | New-Partition -AssignDriveLetter -UseMaximumSize -GptType "{de94bba4-06d1-4d40-a16a-bfd50179d6ac}" `
|
||||
| Format-Volume -FileSystem NTFS -Confirm:$false -Force -NewFileSystemLabel "WinRE"
|
||||
|
||||
Write-Host "Done. Recovery partition at drive $($recoveryPartition.DriveLetter):"
|
||||
}
|
||||
else {
|
||||
Write-Host "No WinRE.WIM found in the OS partition under \Windows\System32\Recovery."
|
||||
Write-Host "Skipping creating the Recovery partition."
|
||||
Write-Host "If a Recovery partition is desired, please re-run the script setting the -RecoveryPartitionSize flag as appropriate."
|
||||
}
|
||||
}
|
||||
|
||||
return $recoveryPartition
|
||||
}
|
||||
#Add boot files
|
||||
function Add-BootFiles {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$OsPartitionDriveLetter,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$SystemPartitionDriveLetter,
|
||||
[string]$FirmwareType = 'UEFI'
|
||||
)
|
||||
|
||||
Write-Host "Adding boot files for `"$($OsPartitionDriveLetter):\Windows`" to System partition `"$($SystemPartitionDriveLetter):`"..."
|
||||
|
||||
bcdboot "$($OsPartitionDriveLetter):\Windows" /S "$($SystemPartitionDriveLetter):" /F "$FirmwareType"
|
||||
|
||||
Write-Host "Done."
|
||||
}
|
||||
|
||||
#Dismount VHDX
|
||||
function Dismount-ScratchVhdx {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$VhdxPath
|
||||
)
|
||||
|
||||
if (Test-Path $VhdxPath) {
|
||||
Write-Host "Dismounting scratch VHDX..."
|
||||
Dismount-VHD -Path $VhdxPath
|
||||
Write-Host "Done."
|
||||
}
|
||||
}
|
||||
|
||||
#Delete old VMs and remove old certs
|
||||
function Remove-FFUVM {
|
||||
$certPath = 'Cert:\LocalMachine\Shielded VM Local Certificates\'
|
||||
$OLDFFUVMs = get-vm _ffu-* | Where-Object { $_.state -ne 'running' }
|
||||
|
||||
If ($null -ne $OLDFFUVMs) {
|
||||
Foreach ($OLDFFUVM in $OLDFFUVMs) {
|
||||
$OldVMName = $OLDFFUVM.VMName
|
||||
Remove-VM -Name $OLDFFUVM.name -Force -ErrorAction SilentlyContinue
|
||||
#Remove-Item -Path "C:\VM\$OldVMName" -Force -Recurse -ErrorAction SilentlyContinue
|
||||
Remove-Item -Path "$VMLocation\$OLDVMName" -Force -Recurse -ErrorAction SilentlyContinue
|
||||
Remove-HgsGuardian -Name $OldVMName
|
||||
$certs = Get-ChildItem -Path $certPath -Recurse | Where-Object { $_.Subject -like "*$OldVMName*" }
|
||||
foreach ($cert in $Certs) {
|
||||
Remove-item -Path $cert.PSPath -force
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function New-FFUVM {
|
||||
#Create new Gen2 VM
|
||||
$VM = New-VM -Name $VMName -Path $VMPath -MemoryStartupBytes $memory -VHDPath $VHDXPath -Generation 2
|
||||
Set-VMProcessor -VMName $VMName -Count $processors
|
||||
#Mount Office ISO
|
||||
Add-VMDvdDrive -VMName $VMName -Path $AppsISO
|
||||
$VMHardDiskDrive = Get-VMHarddiskdrive -VMName $VMName
|
||||
Set-VMFirmware -VMName $VMName -FirstBootDevice $VMHardDiskDrive
|
||||
Set-VM -Name $VMName -AutomaticCheckpointsEnabled $false -StaticMemory
|
||||
|
||||
#Configure TPM
|
||||
New-HgsGuardian -Name $VMName -GenerateCertificates
|
||||
$owner = get-hgsguardian -Name $VMName
|
||||
$kp = New-HgsKeyProtector -Owner $owner -AllowUntrustedRoot
|
||||
Set-VMKeyProtector -VMName $VMName -KeyProtector $kp.RawData
|
||||
Enable-VMTPM -VMName $VMName
|
||||
|
||||
#Connect to VM
|
||||
vmconnect $VM.ComputerName $VMName
|
||||
|
||||
#Start VM
|
||||
Start-VM -Name $VMName
|
||||
return $VM
|
||||
}
|
||||
function New-PEMedia {
|
||||
param (
|
||||
[Parameter()]
|
||||
[switch]
|
||||
$Capture,
|
||||
[Parameter()]
|
||||
[switch]
|
||||
$Deploy
|
||||
)
|
||||
#Need to use the Demployment and Imaging tools environment to create winPE media
|
||||
$DandIEnv = "$adkPath`Assessment and Deployment Kit\Deployment Tools\DandISetEnv.bat"
|
||||
$WinPEFFUPath = "$FFUDevelopmentPath\WinPE"
|
||||
|
||||
If (Test-path -Path "$WinPEFFUPath") {
|
||||
#Dismount-WindowsImage -Path "$WinPEFFUPath\mount" -discard
|
||||
Remove-Item -Path "$WinPEFFUPath" -Recurse -Force
|
||||
}
|
||||
|
||||
& cmd /c """$DandIEnv"" && copype amd64 $WinPEFFUPath"
|
||||
Mount-WindowsImage -ImagePath "$WinPEFFUPath\media\sources\boot.wim" -Index 1 -Path "$WinPEFFUPath\mount"
|
||||
|
||||
$Packages = @(
|
||||
"WinPE-WMI.cab",
|
||||
"en-us\WinPE-WMI_en-us.cab",
|
||||
"WinPE-NetFX.cab",
|
||||
"en-us\WinPE-NetFX_en-us.cab",
|
||||
"WinPE-Scripting.cab",
|
||||
"en-us\WinPE-Scripting_en-us.cab",
|
||||
"WinPE-PowerShell.cab",
|
||||
"en-us\WinPE-PowerShell_en-us.cab",
|
||||
"WinPE-StorageWMI.cab",
|
||||
"en-us\WinPE-StorageWMI_en-us.cab",
|
||||
"WinPE-DismCmdlets.cab",
|
||||
"en-us\WinPE-DismCmdlets_en-us.cab"
|
||||
)
|
||||
|
||||
$PackagePathBase = "$adkPath`Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\"
|
||||
|
||||
foreach ($Package in $Packages) {
|
||||
$PackagePath = Join-Path $PackagePathBase $Package
|
||||
Add-WindowsPackage -Path "$WinPEFFUPath\mount" -PackagePath $PackagePath | Out-Null
|
||||
}
|
||||
If($Capture){
|
||||
Copy-Item -Path "$FFUDevelopmentPath\WinPECaptureFFUFiles\*" -Destination "$WinPEFFUPath\mount" -Recurse -Force
|
||||
#Remove Bootfix.bin if capturing from BIOS systems
|
||||
Remove-Item -Path "$WinPEFFUPath\media\boot\bootfix.bin" -Force
|
||||
}
|
||||
If($Deploy){
|
||||
Copy-Item -Path "$FFUDevelopmentPath\WinPEDeployFFUFiles\*" -Destination "$WinPEFFUPath\mount" -Recurse -Force
|
||||
# If you need to add drivers (storage/keyboard most likely), remove the '#' from the below line and change the /Driver:Path to a folder of drivers
|
||||
# & dism /image:$WinPEFFUPath\mount /Add-Driver /Driver:<Path to Drivers folder e.g c:\drivers> /Recurse
|
||||
}
|
||||
Dismount-WindowsImage -Path "$WinPEFFUPath\mount" -Save
|
||||
#Make ISO
|
||||
$OSCDIMGPath = "$adkPath`Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg"
|
||||
$OSCDIMG = "$OSCDIMGPath\oscdimg.exe"
|
||||
& "$OSCDIMG" -m -o -u2 -udfver102 -bootdata:2`#p0,e,b$OSCDIMGPath\etfsboot.com`#pEF,e,b$OSCDIMGPath\Efisys_noprompt.bin $WinPEFFUPath\media $FFUDevelopmentPath\WinPE_FFU_Capture.iso
|
||||
Remove-Item -Path "$WinPEFFUPath" -Recurse -Force
|
||||
}
|
||||
function New-FFU {
|
||||
#Need to use the Demployment and Imaging tools environment to use dism from the Insider ADK to optimize the FFU. This is only needed until Windows 23H2.
|
||||
$DandIEnv = "$adkPath`Assessment and Deployment Kit\Deployment Tools\DandISetEnv.bat"
|
||||
#Mount the Capture ISO to the VM
|
||||
|
||||
$CaptureISOPath = "$FFUDevelopmentPath\WinPE_FFU_Capture.iso"
|
||||
$FFUVMs = get-vm _ffu-* | Where-Object { $_.state -ne 'running' }
|
||||
|
||||
If ($null -ne $FFUVMs) {
|
||||
Foreach ($FFUVM in $FFUVMs) {
|
||||
$VMName = $FFUVM.name
|
||||
$VMDVDDrive = Get-VMDvdDrive -VMName $VMName
|
||||
Set-VMFirmware -VMName $VMName -FirstBootDevice $VMDVDDrive
|
||||
Set-VMDvdDrive -VMName $VMName -Path $CaptureISOPath
|
||||
$VMSwitch = Get-VMSwitch -name $VMSwitchName
|
||||
get-vm $VMName | Get-VMNetworkAdapter | Connect-VMNetworkAdapter -SwitchName $VMSwitch.Name
|
||||
#vmconnect $FFUVM.ComputerName $VMName
|
||||
}
|
||||
}
|
||||
#Start VM
|
||||
Start-VM -Name $VMName
|
||||
|
||||
# Wait for the VM to turn off
|
||||
do {
|
||||
$FFUVM = Get-VM -Name $VMName
|
||||
Start-Sleep -Seconds 5
|
||||
} while ($FFUVM.State -ne 'Off')
|
||||
|
||||
# Check for .ffu files in the FFUDevelopment folder
|
||||
$FFUFiles = Get-ChildItem -Path $FFUDevelopmentPath -Filter "*.ffu" -File
|
||||
|
||||
# If there's more than one .ffu file, get the most recent and store its path in $FFUFile
|
||||
if ($FFUFiles.Count -gt 0) {
|
||||
$FFUFile = ($FFUFiles | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1).FullName
|
||||
Write-Host "Most recent .ffu file: $FFUFile"
|
||||
}
|
||||
else {
|
||||
Write-Host "No .ffu files found in $FFUFolderPath"
|
||||
}
|
||||
#Add drivers
|
||||
If ($InstallDrivers){
|
||||
New-Item -Path "$FFUDevelopmentPath\Mount" -ItemType Directory -Force
|
||||
Mount-WindowsImage -ImagePath $FFUFile -Index 1 -Path "$FFUDevelopmentPath\Mount"
|
||||
Add-WindowsDriver -Path "$FFUDevelopmentPath\Mount" -Driver "$FFUDevelopmentPath\Drivers" -Recurse
|
||||
Dismount-WindowsImage -Path "$FFUDevelopmentPath\Mount" -Save
|
||||
Remove-Item -Path "$FFUDevelopmentPath\Mount" -Recurse -Force
|
||||
}
|
||||
#Optimize FFU
|
||||
& cmd /c """$DandIEnv"" && dism /optimize-ffu /imagefile:$FFUFile"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
try {
|
||||
#Check if the Windows ADK is installed
|
||||
$adkPath = Get-ADK
|
||||
}
|
||||
catch {
|
||||
throw $_
|
||||
}
|
||||
|
||||
#Build ISO for Office and Apps
|
||||
try{
|
||||
if($InstallOffice){
|
||||
Get-Office
|
||||
}
|
||||
if($InstallApps){
|
||||
New-AppsISO
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host "Getting Office and/or building the AppsISO failed"
|
||||
throw $_
|
||||
}
|
||||
|
||||
#Create VHDX
|
||||
try {
|
||||
$wimPath = Get-WimFromISO
|
||||
|
||||
$WimIndex = Get-WimIndex
|
||||
|
||||
$vhdxDisk = New-ScratchVhdx -VhdxPath $VHDXPath -SizeBytes $disksize -Dynamic:$true
|
||||
|
||||
$systemPartitionDriveLetter = New-SystemPartition -VhdxDisk $vhdxDisk
|
||||
|
||||
New-MSRPartition -VhdxDisk $vhdxDisk
|
||||
|
||||
$osPartition = New-OSPartition -VhdxDisk $vhdxDisk -OSPartitionSize $OSPartitionSize -WimPath $WimPath -WimIndex $WimIndex[1]
|
||||
$osPartitionDriveLetter = $osPartition[1].DriveLetter
|
||||
|
||||
$recoveryPartition = New-RecoveryPartition -VhdxDisk $vhdxDisk -OsPartition $osPartition[1] -RecoveryPartitionSize $RecoveryPartitionSize -DataPartition $dataPartition
|
||||
|
||||
Write-Host "All necessary partitions created."
|
||||
|
||||
Add-BootFiles -OsPartitionDriveLetter $osPartitionDriveLetter -SystemPartitionDriveLetter $systemPartitionDriveLetter[1]
|
||||
New-Item -Path "$($osPartitionDriveLetter):\Windows\Panther\unattend" -ItemType Directory
|
||||
Copy-Item -Path "$FFUDevelopmentPath\BuildFFUUnattend\unattend.xml" -Destination "$($osPartitionDriveLetter):\Windows\Panther\Unattend\Unattend.xml" -Force
|
||||
}
|
||||
finally {
|
||||
Dismount-ScratchVhdx -VhdxPath $VHDXPath
|
||||
Dismount-DiskImage -ImagePath $ISOPath
|
||||
}
|
||||
|
||||
#Clean up old VMs
|
||||
try {
|
||||
Remove-FFUVM
|
||||
}
|
||||
catch {
|
||||
Write-Host "VM cleanup failed"
|
||||
throw $_
|
||||
}
|
||||
|
||||
#Create VM and attach VHDX
|
||||
try {
|
||||
$FFUVM = New-FFUVM
|
||||
}
|
||||
catch {
|
||||
Write-Host 'VM creation failed'
|
||||
throw $_
|
||||
}
|
||||
#Create Capture Media
|
||||
try{
|
||||
#This should happen while the FFUVM is building
|
||||
New-PEMedia -Capture
|
||||
}
|
||||
catch{
|
||||
throw $_
|
||||
}
|
||||
#Capture FFU file
|
||||
try {
|
||||
#Check if VM is done provisioning
|
||||
do {
|
||||
$FFUVM = Get-VM -Name $FFUVM.Name
|
||||
Start-Sleep -Seconds 10
|
||||
} while ($FFUVM.State -ne 'Off')
|
||||
|
||||
#Capture FFU file
|
||||
New-FFU
|
||||
}
|
||||
Catch {
|
||||
throw $_
|
||||
}
|
||||
Reference in New Issue
Block a user