Public/OSDCloudIPU/Invoke-OSDCloudIPU.ps1

function Invoke-OSDCloudIPU {
    <#
    Log Files for IPU: https://learn.microsoft.com/en-us/windows/deployment/upgrade/log-files
    Setup Command Line: https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-setup-command-line-options?view=windows-11
    #>

    
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param (

        [Parameter(ParameterSetName = 'Default')]
        [ValidateSet(
            'Windows 11 24H2 x64',
            'Windows 11 24H2 ARM64', 
            'Windows 11 23H2 x64',
            'Windows 11 23H2 ARM64',    
            'Windows 11 22H2 x64',
            'Windows 11 21H2 x64',
            'Windows 10 22H2 x64',
            'Windows 10 22H2 ARM64')]
        [System.String]
        $OSName = 'Windows 11 24H2 x64',

        [switch]
        $Silent,

        [switch]
        $SkipDriverPack,

        [switch]
        $NoReboot,

        [switch]
        $DownloadOnly,

        [switch]
        $DiagnosticPrompt
    )
    #region Admin Elevation
    $whoiam = [system.security.principal.windowsidentity]::getcurrent().name
    $isElevated = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
    if ($isElevated) {
        Write-Host -ForegroundColor Green "[+] Running as $whoiam and IS Admin Elevated"
    }
    else {
        Write-Warning "[-] Running as $whoiam and is NOT Admin Elevated"
        Break
    }

    #============================================================================
    #region Functions
    #============================================================================
    Function Get-TPMVer {
    $Manufacturer = (Get-WmiObject -Class:Win32_ComputerSystem).Manufacturer
    if ($Manufacturer -match "HP")
        {
        if ($((Get-CimInstance -Namespace "ROOT\cimv2\Security\MicrosoftTpm" -ClassName Win32_TPM).SpecVersion) -match "1.2")
            {
            $versionInfo = (Get-CimInstance -Namespace "ROOT\cimv2\Security\MicrosoftTpm" -ClassName Win32_TPM).ManufacturerVersionInfo
            $verMaj      = [Convert]::ToInt32($versionInfo[0..1] -join '', 16)
            $verMin      = [Convert]::ToInt32($versionInfo[2..3] -join '', 16)
            $verBuild    = [Convert]::ToInt32($versionInfo[4..6] -join '', 16)
            $verRevision = 0
            [version]$ver = "$verMaj`.$verMin`.$verBuild`.$verRevision"
            Write-Output "TPM Verion: $ver | Spec: $((Get-CimInstance -Namespace "ROOT\cimv2\Security\MicrosoftTpm" -ClassName Win32_TPM).SpecVersion)"
            }
        else {Write-Output "TPM Verion: $((Get-CimInstance -Namespace "ROOT\cimv2\Security\MicrosoftTpm" -ClassName Win32_TPM).ManufacturerVersion) | Spec: $((Get-CimInstance -Namespace "ROOT\cimv2\Security\MicrosoftTpm" -ClassName Win32_TPM).SpecVersion)"}
        }

    else
        {
        if ($((Get-CimInstance -Namespace "ROOT\cimv2\Security\MicrosoftTpm" -ClassName Win32_TPM).SpecVersion) -match "1.2")
            {
            Write-Output "TPM Verion: $((Get-CimInstance -Namespace "ROOT\cimv2\Security\MicrosoftTpm" -ClassName Win32_TPM).ManufacturerVersion) | Spec: $((Get-CimInstance -Namespace "ROOT\cimv2\Security\MicrosoftTpm" -ClassName Win32_TPM).SpecVersion)"
            }
        else {Write-Output "TPM Verion: $((Get-CimInstance -Namespace "ROOT\cimv2\Security\MicrosoftTpm" -ClassName Win32_TPM).ManufacturerVersion) | Spec: $((Get-CimInstance -Namespace "ROOT\cimv2\Security\MicrosoftTpm" -ClassName Win32_TPM).SpecVersion)"}
        }
    }

    #endregion Functions
    
    #============================================================================
    #region Device Info
    #============================================================================
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "$((Get-Date).ToString('yyyy-MM-dd-HHmmss')) Starting Invoke-OSDCloudIPU"
    Write-Host -ForegroundColor Gray "Looking of Details about this device...."


    $BIOSInfo = Get-WmiObject -Class 'Win32_Bios'

    # Get the current BIOS release date and format it to datetime
    $CurrentBIOSDate = [System.Management.ManagementDateTimeConverter]::ToDatetime($BIOSInfo.ReleaseDate).ToUniversalTime()

    $Manufacturer = (Get-WmiObject -Class:Win32_ComputerSystem).Manufacturer
    $ManufacturerBaseBoard = (Get-CimInstance -Namespace root/cimv2 -ClassName Win32_BaseBoard).Manufacturer
    $ComputerModel = (Get-WmiObject -Class:Win32_ComputerSystem).Model
    if ($ManufacturerBaseBoard -eq "Intel Corporation")
        {
        $ComputerModel = (Get-CimInstance -Namespace root/cimv2 -ClassName Win32_BaseBoard).Product
        }
    $HPProdCode = (Get-CimInstance -Namespace root/cimv2 -ClassName Win32_BaseBoard).Product
    $Serial = (Get-WmiObject -class:win32_bios).SerialNumber
    $cpuDetails = @(Get-WmiObject -Class Win32_Processor)[0]

    Write-Output "Computer Name: $env:computername"
    $CurrentOSInfo = Get-Item -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
    $WindowsRelease = $CurrentOSInfo.GetValue('ReleaseId')
    if ($WindowsRelease -eq "2009"){$WindowsRelease = $CurrentOSInfo.GetValue('DisplayVersion')}
    $Build = $($CurrentOSInfo.GetValue('CurrentBuild'))
    $BuildUBR_CurrentOS = $Build +"."+$($CurrentOSInfo.GetValue('UBR'))
    if ($Build -le 19045){$WinVer = "10"}
    else {$WinVer = "11"}
    Write-Output "Windows $WinVer $WindowsRelease | $BuildUBR_CurrentOS"
    Write-Output "Architecture ('env:PROCESSOR_ARCHITECTURE'): $env:PROCESSOR_ARCHITECTURE "
    Write-Output "Architecture (Get-NativeMatchineImage): $((Get-NativeMatchineImage).NativeMachine)"
    Write-Output "Computer Model: $ComputerModel"
    Write-Output "Serial: $Serial"
    if ($Manufacturer -like "H*"){Write-Output "Computer Product Code: $HPProdCode"}
    Write-Output $cpuDetails.Name
    Write-Output "Current BIOS Level: $($BIOSInfo.SMBIOSBIOSVersion) From Date: $CurrentBIOSDate"
    Get-TPMVer
    $TimeUTC = [System.DateTime]::UtcNow
    $TimeCLT = get-date
    Write-Output "Current Client Time: $TimeCLT"
    Write-Output "Current Client UTC: $TimeUTC"
    Write-Output "Time Zone: $(Get-TimeZone)"
    $Locale = Get-WinSystemLocale
    if ($Locale -ne "en-US"){Write-Output "WinSystemLocale: $locale"}
    $FreeSpace = (Get-CimInstance win32_LogicalDisk -Filter "DeviceID='C:'").FreeSpace/1GB -as [int]
    $DiskSize = (Get-CimInstance win32_LogicalDisk -Filter "DeviceID='C:'").Size/1GB -as [int]
    Write-Output "C:\ Drive Size: $DiskSize, Freespace: $FreeSpace"

    if ($Build -le 19045){
        $Win11 = Get-Win11Readiness
        if ($Win11.Return -eq "CAPABLE"){
            Write-Host -ForegroundColor Green "Device is Windows 11 CAPABLE"
        }
        else {
            Write-Host -ForegroundColor Yellow "Device is !NOT! Windows 11 CAPABLE"
            if ($Build -eq 19045){
                write-host -ForegroundColor Yellow "This Device is already at the latest supported Version of Windows for this Hardware"
            }
            elseif ($Build -lt 19045){
                write-host -ForegroundColor Green "But.. You can upgrade it to Windows 10 22H2"
            }
        }
    }

    #$OSVersion = "Windows $($OSName.split(" ")[1])"
    #$OSReleaseID = $OSName.split(" ")[2]
    #$Product = (Get-MyComputerProduct)
    
    $DriverPack = Get-OSDCloudDriverPack # -Product $Product -OSVersion $OSVersion -OSReleaseID $OSReleaseID
    if ($DriverPack){
        Write-host -ForegroundColor Gray "Recommended Driverpack for upgrade: $($DriverPack.Name)"
        if ($SkipDriverPack){
            write-host -ForegroundColor Yellow "Skipping Download and Integration [-SkipDriverPack]"
        }
    }

    #endregion Device Info

    #============================================================================
    #region Current Activiation
    #============================================================================

    if (!($OSEdition)){
        $OSEdition = Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name "EditionID"
    }
    if (!($OSLanguage)){
        $OSLanguage = (Get-WinSystemLocale).Name
    }
    if (!($OSActivation)){
        $OSActivation = (Get-CimInstance SoftwareLicensingProduct -Filter "Name like 'Windows%'" | Where-Object { $_.PartialProductKey }).ProductKeyChannel
    }
    if ($OSActivation -match "OEM"){
        $OSActivation = "Retail"
    }
    $OSArch = $env:PROCESSOR_ARCHITECTURE   
    if ($OSArch -eq "AMD64"){$OSArch = 'x64'}
    #endregion Current Activiation
    
    if ($OSArch -eq "ARM64"){
        #=================================================
        # OSEditionId and OSActivation ARM64
        #=================================================
        if (($OSEdition -eq 'Home') -or ($OSEdition -eq 'Core')) {
            $OSEditionId = 'Core'
            $OSActivation = 'Retail'
            $OSImageIndex = 4
        }
        if ($OSEdition -eq 'Home Single Language') {
            $OSEditionId = 'CoreSingleLanguage'
            $OSActivation = 'Retail'
            $OSImageIndex = 5
        }
        if (($OSEdition -eq 'Pro') -or ($OSEdition -eq 'Professional'))  {
            $OSEditionId = 'Professional'
            if ($OSActivation -eq 'Retail') {$OSImageIndex = 6}
            if ($OSActivation -eq 'Volume') {$OSImageIndex = 8}
        }
    }
    else {
        #=================================================
        # OSEditionId and OSActivation x64 (AMD64)
        #=================================================
        if (($OSEdition -eq 'Home') -or ($OSEdition -eq 'Core')) {
            $OSEditionId = 'Core'
            $OSActivation = 'Retail'
            $OSImageIndex = 4
        }
        if (($OSEdition -eq 'Home N') -or ($OSEdition -eq 'CoreN')) {
            $OSEditionId = 'CoreN'
            $OSActivation = 'Retail'
            $OSImageIndex = 5
        }
        if ($OSEdition -eq 'Home Single Language') {
            $OSEditionId = 'CoreSingleLanguage'
            $OSActivation = 'Retail'
            $OSImageIndex = 6
        }
        if ($OSEdition -eq 'Enterprise') {
            $OSEditionId = 'Enterprise'
            $OSActivation = 'Volume'
            $OSImageIndex = 6
        }
        if (($OSEdition -eq 'Enterprise N') -or ($OSEdition -eq 'EnterpriseN')) {
            $OSEditionId = 'EnterpriseN'
            $OSActivation = 'Volume'
            $OSImageIndex = 7
        }
        if ($OSEdition -eq 'Education') {
            $OSEditionId = 'Education'
            if ($OSActivation -eq 'Retail') {$OSImageIndex = 7}
            if ($OSActivation -eq 'Volume') {$OSImageIndex = 4}
        }
        if (($OSEdition -eq 'Education N') -or ($OSEdition -eq 'EducationN')) {
            $OSEditionId = 'EducationN'
            if ($OSActivation -eq 'Retail') {$OSImageIndex = 8}
            if ($OSActivation -eq 'Volume') {$OSImageIndex = 5}
        }
        if (($OSEdition -eq 'Pro') -or ($OSEdition -eq 'Professional'))  {
            $OSEditionId = 'Professional'
            if ($OSActivation -eq 'Retail') {$OSImageIndex = 9}
            if ($OSActivation -eq 'Volume') {$OSImageIndex = 8}
        }
        if (($OSEdition -eq 'Pro N') -or ($OSEdition -eq 'ProfessionalN')) {
            $OSEditionId = 'ProfessionalN'
            if ($OSActivation -eq 'Retail') {$OSImageIndex = 10}
            if ($OSActivation -eq 'Volume') {$OSImageIndex = 9}
        }
    }
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor DarkCyan "These are set automatically based on your current OS"
    Write-Host -ForegroundColor Cyan "OSEditionId: " -NoNewline
    Write-Host -ForegroundColor Green $OSEditionId
    Write-Host -ForegroundColor Cyan "OSImageIndex: " -NoNewline
    Write-Host -ForegroundColor Green $OSImageIndex
    Write-Host -ForegroundColor Cyan "OSLanguage: " -NoNewline
    Write-Host -ForegroundColor Green $OSLanguage
    Write-Host -ForegroundColor Cyan "OSActivation: " -NoNewline
    Write-Host -ForegroundColor Green $OSActivation
    Write-Host -ForegroundColor Cyan "OSArch: " -NoNewline
    Write-Host -ForegroundColor Green $OSArch

    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "$((Get-Date).ToString('yyyy-MM-dd-HHmmss')) Starting Feature Update lookup and Download"

    #============================================================================
    #region Detect & Download ESD File
    #============================================================================

    $ScratchLocation = 'c:\OSDCloud\IPU'
    $OSMediaLocation = 'c:\OSDCloud\OS'
    $MediaLocation = "$ScratchLocation\Media"
    if (!(Test-Path -Path $OSMediaLocation)){New-Item -Path $OSMediaLocation -ItemType Directory -Force | Out-Null}
    if (!(Test-Path -Path $ScratchLocation)){New-Item -Path $ScratchLocation -ItemType Directory -Force | Out-Null}
    if (Test-Path -Path $MediaLocation){Remove-Item -Path $MediaLocation -Force -Recurse}
    New-Item -Path $MediaLocation -ItemType Directory -Force | Out-Null

    $ESD = Get-FeatureUpdate -OSName $OSName -OSActivation $OSActivation -OSLanguage $OSLanguage -OSArchitecture $OSArch
    if (!($ESD)){
        Write-Host -ForegroundColor Red "Unable to Determine proper ESD Upgrade File"
        throw "Unable to Determine proper ESD Upgrade File"
    }
    Write-Host -ForegroundColor Cyan "Name: " -NoNewline
    Write-Host -ForegroundColor Green $ESD.Name
    Write-Host -ForegroundColor Cyan "Architecture: " -NoNewline
    Write-Host -ForegroundColor Green $ESD.Architecture
    Write-Host -ForegroundColor Cyan "Activation: " -NoNewline
    Write-Host -ForegroundColor Green $ESD.Activation
    Write-Host -ForegroundColor Cyan "Build: " -NoNewline
    Write-Host -ForegroundColor Green $ESD.Build    
    Write-Host -ForegroundColor Cyan "FileName: " -NoNewline
    Write-Host -ForegroundColor Green $ESD.FileName   
    Write-Host -ForegroundColor Cyan "Url: " -NoNewline
    Write-Host -ForegroundColor Green $ESD.Url   
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "$((Get-Date).ToString('yyyy-MM-dd-HHmmss')) Getting Content for Upgrade Media"   

    #Build Media Paths
    $SubFolderName = "$($ESD.Version) $($ESD.ReleaseId)"
    $ImageFolderPath = "$OSMediaLocation\$SubFolderName"
    if (!(Test-Path -Path $ImageFolderPath)){New-Item -Path $ImageFolderPath -ItemType Directory -Force | Out-Null}
    $ImagePath = "$ImageFolderPath\$($ESD.FileName)"
    $ImageDownloadRequired = $true

    #Check Flash Drive for Media
    $OSDCloudUSB = Get-Volume.usb | Where-Object {($_.FileSystemLabel -match 'OSDCloud') -or ($_.FileSystemLabel -match 'BHIMAGE')} | Select-Object -First 1
    if ($OSDCloudUSB){
        $USBImagePath = "$($OSDCloudUSB.DriveLetter):\OSDCloud\OS\$SubFolderName\$($ESD.FileName)"
        if ((Test-Path -path $USBImagePath) -and (!(Test-Path -path $ImagePath))){
            Write-Host -ForegroundColor Green "Found media on OSDCloudUSB - Copying Local"
            Copy-Item -Path $USBImagePath -Destination $ImagePath
        }
    }
    
    #Test for Media
    if (Test-path -path $ImagePath){
        Write-Host -ForegroundColor Gray "Found previously downloaded media, getting SHA1 Hash"
        $SHA1Hash = Get-FileHash $ImagePath -Algorithm SHA1
        if ($SHA1Hash.Hash -eq $esd.SHA1){
            Write-Host -ForegroundColor Gray "SHA1 Match on $ImagePath, skipping Download"
            $ImageDownloadRequired = $false
        }
        else {
            Write-Host -ForegroundColor Gray "SHA1 Match Failed on $ImagePath, removing content"
        }
        
    }
    if ($ImageDownloadRequired -eq $true){
        #Save-WebFile -SourceUrl $ESD.Url -DestinationDirectory $ScratchLocation -DestinationName $ESD.FileName
        Write-Host -ForegroundColor Gray "Starting Download to $ImagePath, this takes awhile"
            
        <# This was taking way too long for some files
        #Get ESD Size
        $req = [System.Net.HttpWebRequest]::Create("$($ESD.Url)")
        $res = $req.GetResponse()
        (Invoke-WebRequest $ESD.Url -Method Head).Headers.'Content-Length'
        $ESDSizeMB = $([Math]::Round($res.ContentLength /1000000))
        Write-Host "Total Size: $ESDSizeMB MB"
        #>


        #Clear Out any Previous Attempts
        $ExistingBitsJob = Get-BitsTransfer -Name "$($ESD.FileName)" -AllUsers -ErrorAction SilentlyContinue
        If ($ExistingBitsJob) {
            Remove-BitsTransfer -BitsJob $ExistingBitsJob
        }
    
        if ((Get-Service -name BITS).Status -ne "Running"){
            Write-Host -ForegroundColor Yellow "BITS Service is not Running, which is required to download ESD File, attempting to Start"
            $StartBITS = Start-Service -Name BITS -PassThru
            Start-Sleep -Seconds 2
            if ($StartBITS.Status -ne "Running"){

            }
        }
        #Start Download using BITS
        Write-Host -ForegroundColor DarkGray "Start-BitsTransfer -Source $ESD.Url -Destination $ImageFolderPath -DisplayName $($ESD.FileName) -Description 'Windows Media Download' -RetryInterval 60"
        $BitsJob = Start-BitsTransfer -Source $ESD.Url -Destination $ImageFolderPath -DisplayName "$($ESD.FileName)" -Description "Windows Media Download" -RetryInterval 60
        If ($BitsJob.JobState -eq "Error"){
            write-Host "BITS tranfer failed: $($BitsJob.ErrorDescription)"
        }

    }

    #endregion Detect & Download ESD File

    #============================================================================
    #region Extract of ESD file to create Setup Content
    #============================================================================


    #Grab ESD File and create bootable ISO
    if ((!(Test-Path -Path $ImagePath)) -or (!(Test-Path -Path $MediaLocation))){
        if (!(Test-Path -Path $ImagePath)){
            Write-Host -ForegroundColor Red "Missing $ImagePath, double check download process"
            throw "Failed to find $ImagePath, double check download process"
        }
        if (!(Test-Path -Path $MediaLocation)){
            Write-Host -ForegroundColor Red "Missing $MediaLocation, double check folder exist"
            throw "Faield to find $MediaLocation, double check folder exist"
        }
    }
    if ((Test-Path -Path $ImagePath) -and (Test-Path -Path $MediaLocation)){
        Write-Host -ForegroundColor DarkGray "========================================================================="
        Write-Host -ForegroundColor Cyan "$((Get-Date).ToString('yyyy-MM-dd-HHmmss')) Starting Extract of ESD file to create Setup Content"
        $ApplyPath = $MediaLocation
        Write-Host -ForegroundColor Gray "Expanding $ImagePath Index 1 to $ApplyPath"
        $Expand = Expand-WindowsImage -ImagePath $ImagePath -Index 1 -ApplyPath $ApplyPath
        ##Export-WindowsImage -SourceImagePath $ImagePath -SourceIndex 2 -DestinationImagePath "$ApplyPath\Sources\boot.wim" -CompressionType max -CheckIntegrity
        ##Export-WindowsImage -SourceImagePath $ImagePath -SourceIndex 3 -DestinationImagePath "$ApplyPath\Sources\boot.wim" -CompressionType max -CheckIntegrity -Setbootable
        Write-Host -ForegroundColor Gray "Expanding $ImagePath Index $OSImageIndex to $ApplyPath\Sources\install.wim"
        $Expand = Export-WindowsImage -SourceImagePath $ImagePath -SourceIndex $OSImageIndex -DestinationImagePath "$ApplyPath\Sources\install.wim" -CheckIntegrity
        ##Export-WindowsImage -SourceImagePath $ImagePath -SourceIndex 5 -DestinationImagePath "$ApplyPath\Sources\install.wim" -CompressionType max -CheckIntegrity
        $null = $Expand
    }
    
    #endregion Extract of ESD file to create Setup Content

    if (!(Test-Path -Path "$MediaLocation\Setup.exe")){
        Write-Host -ForegroundColor Red "Setup.exe not found, something went wrong"
        throw
    }
    if (!(Test-Path -Path "$MediaLocation\sources\install.wim")){
        Write-Host -ForegroundColor Red "install.wim not found, something went wrong"
        throw
    }


    if (($DriverPack) -and (!($SkipDriverPack))){
        Write-Host -ForegroundColor DarkGray "========================================================================="
        Write-Host -ForegroundColor Cyan "$((Get-Date).ToString('yyyy-MM-dd-HHmmss')) Getting Driver Pack for IPU Integration"           
        $DriverPackDownloadRequired = $true
        if (!(Test-Path -Path "C:\Drivers")){New-Item -Path "C:\Drivers" -ItemType Directory -Force | Out-Null}
        $DriverPackPath = "C:\Drivers\$($DriverPack.FileName)"
        if (Test-path -path $DriverPackPath){
            Write-Host -ForegroundColor Gray "Found previously downloaded DriverPack File, getting MD5 Hash"
            $MD5Hash = Get-FileHash $DriverPackPath -Algorithm MD5
            if ($MD5Hash.Hash -eq $DriverPack.HashMD5){
                Write-Host -ForegroundColor Gray "MD5 Match on $DriverPackPath, skipping Download"
                $DriverPackDownloadRequired = $false
            }
            else {
                Write-Host -ForegroundColor Gray "MD5 Match Failed on $DriverPackPath, removing content"
            }
        }
        
        IF ($DriverPackDownloadRequired -eq $true){
            Write-Host -ForegroundColor Gray "Starting Download to $DriverPackPath, this takes awhile"
            <#
            #Get DrivePack Size
            $req = [System.Net.HttpWebRequest]::Create("$($DriverPack.Url)")
            $res = $req.GetResponse()
            (Invoke-WebRequest $ESD.Url -Method Head).Headers.'Content-Length'
            $SizeMB = $([Math]::Round($res.ContentLength /1000000))
            Write-Host "Total Size: $SizeMB MB"
            #>


            #Clear Out any Previous Attempts
            $ExistingBitsJob = Get-BitsTransfer -Name "$($DriverPack.FileName)" -AllUsers -ErrorAction SilentlyContinue
            If ($ExistingBitsJob) {
                Remove-BitsTransfer -BitsJob $ExistingBitsJob
            }
    
            #Start Download using BITS
            $BitsJob = Start-BitsTransfer -Source $DriverPack.Url -Destination $DriverPackPath -DisplayName "$($DriverPack.FileName)" -Description "Driver Pack Download" -RetryInterval 60
            If ($BitsJob.JobState -eq "Error"){
                write-Host "BITS tranfer failed: $($BitsJob.ErrorDescription)"
            }
        }
        #Expand Driver Pack
        if (Test-path -path $DriverPackPath){
            Write-Host -ForegroundColor DarkGray "========================================================================="
            Write-Host -ForegroundColor Cyan "$((Get-Date).ToString('yyyy-MM-dd-HHmmss')) Expanding DriverPack for Upgrade Media"   
            Expand-StagedDriverPack
            $DriverPackFile = Get-ChildItem -Path $DriverPackPath -Filter $DriverPack.FileName
            $DriverPackExpandPath = Join-Path $DriverPackFile.Directory $DriverPackFile.BaseName
            if (Test-Path -Path $DriverPackExpandPath){

            }
        }
    }
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "$((Get-Date).ToString('yyyy-MM-dd-HHmmss')) Triggering Windows Upgrade Setup"   
    
    if ($DownloadOnly){
        Write-Host -ForegroundColor Yellow "Download Complete, exiting script before install based on 'DownloadOnly' switch"
    }
    else {
        #============================================================================
        #region Creating Arguments based on Parameters
        #============================================================================
        #Driver Integration - Adds .inf-style drivers to the new Windows 10 installation.
        if ($DriverPack){
            if ($DriverPackPath){
                if (Test-path -path $DriverPackPath){
                    $driverarg = "/InstallDrivers $DriverPackExpandPath"
                }
            }
        }
        else {
            $DriverArg = ""
        }
        
        #Run Silently - This will suppress any Windows Setup user experience including the rollback user experience.
        if ($Silent){
            $SilentArg = "/quiet"
        }
        else{
            $SilentArg = ""
        }
        
        #Dynamic Updates - Specifies whether Windows Setup will perform Dynamic Update operations (search, download, and install updates).
        if ($DynamicUpdate){
            $DynamicUpdateArg = "/DynamicUpdate Enable"
        }
        else{
            $DynamicUpdateArg = "/DynamicUpdate Disable"
        }
        
        #Diagnostic Prompt - Specifies that the Command Prompt is available during Windows Setup.
        if ($DiagnosticPrompt){
            $DiagnosticPromptArg = "/diagnosticprompt enable"
        }
        else{
            $DiagnosticPromptArg  = ""
        }
        #Diagnostic Prompt - Specifies that the Command Prompt is available during Windows Setup.
        if ($NoReboot){
            $NoRebootArg = "/noreboot"
        }
        else{
            $NoRebootArg  = ""
        }
        
        $ParamStartProcess = @{
            FilePath = "$MediaLocation\Setup.exe"
            ArgumentList = "/Auto Upgrade $DynamicUpdateArg /EULA accept $DriverArg /Priority High $SilentArg $DiagnosticPromptArg $NoRebootArg"
        } 

        Write-Host -ForegroundColor Cyan "Setup Path: " -NoNewline
        Write-Host -ForegroundColor Green $ParamStartProcess.FilePath
        Write-Host -ForegroundColor Cyan "Arguments: " -NoNewline
        Write-Host -ForegroundColor Green $ParamStartProcess.ArgumentList


        #endregion Creating Arguments based on Parameters

        Start-Process @ParamStartProcess
    }
}