Public/OSDCloud/OSDCloudTemplate.ps1

function Get-OSDCloudTemplate {
    <#
    .SYNOPSIS
    Gets information returned by Get-OSDCloudTemplate.
 
    .DESCRIPTION
    Provides the implementation for Get-OSDCloudTemplate.
 
    .EXAMPLE
    Get-OSDCloudTemplate
    Runs Get-OSDCloudTemplate with common parameters.
 
    .NOTES
    Author: David Segura - Recast Software
    2026-07-09 - Updated comment-based help
 
    .LINK
    https://github.com/OSDeploy/OSD/tree/master/docs
    #>

    [CmdletBinding()]
    param ()

    #region Block
    Block-WinPE
    $CurrentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
    $CurrentPrincipal = [Security.Principal.WindowsPrincipal]::new($CurrentIdentity)
    if (-not $CurrentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
        Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Administrative rights are required"
        return
    }
    Block-WindowsVersionNe10
    Block-PowerShellVersionLt5
    #endregion

    #region template.json
    if (Test-Path "$env:ProgramData\OSDCloud\template.json") {
        $TemplateSettings = Get-Content -Path "$env:ProgramData\OSDCloud\template.json" | ConvertFrom-Json
        $TemplatePath = $TemplateSettings.TemplatePath

        if (! (Test-Path "$TemplatePath\Media\sources\boot.wim")) {
            $TemplatePath = "$env:ProgramData\OSDCloud"
            $null = Remove-Item -Path "$env:ProgramData\OSDCloud\template.json" -Force
        }
    }
    else {
        $TemplatePath = "$env:ProgramData\OSDCloud"
    }
    #endregion

    #region Incomplete Template
    if (! (Test-Path "$TemplatePath\Media\sources\boot.wim")) {
        Return $null
    }
    #endregion

    #return TemplatePath
    if (Test-Path "$env:ProgramData\OSDCloud\template.json") {
        $TemplateSettings = Get-Content -Path "$env:ProgramData\OSDCloud\template.json" | ConvertFrom-Json
        $TemplatePath = $TemplateSettings.TemplatePath
    }
    $TemplatePath
    #endregion
}
function Get-OSDCloudTemplateNames {
    <#
    .SYNOPSIS
    Gets information returned by Get-OSDCloudTemplateNames.
 
    .DESCRIPTION
    Provides the implementation for Get-OSDCloudTemplateNames.
 
    .EXAMPLE
    Get-OSDCloudTemplateNames
    Runs Get-OSDCloudTemplateNames with common parameters.
 
    .NOTES
    Author: David Segura - Recast Software
    2026-07-09 - Updated comment-based help
 
    .LINK
    https://github.com/OSDeploy/OSD/tree/master/docs
    #>

    [CmdletBinding()]
    param ()

    #region Block
    Block-WinPE
    $CurrentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
    $CurrentPrincipal = [Security.Principal.WindowsPrincipal]::new($CurrentIdentity)
    if (-not $CurrentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
        Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Administrative rights are required"
        return
    }
    Block-WindowsVersionNe10
    Block-PowerShellVersionLt5
    #endregion

    #region Build Array
    $Results = @()
    [System.Array]$Results = 'default'
    [System.Array]$Results += Get-ChildItem -Path "$env:ProgramData\OSDCloud\Templates" | Where-Object { $_.PsIsContainer -eq $true } | Select-Object -ExpandProperty Name

    #region OSDeploy Compatibility
    if (Test-Path "$env:ProgramData\OSDeploy\MyBootMedia") {
        [System.Array]$Results += Get-ChildItem -Path "$env:ProgramData\OSDeploy\MyBootMedia" | Where-Object { $_.PsIsContainer -eq $true } | Select-Object -ExpandProperty Name
    }
    if (Test-Path "$env:ProgramData\OSDeploy\WinPEBootMedia") {
        [System.Array]$Results += Get-ChildItem -Path "$env:ProgramData\OSDeploy\WinPEBootMedia" | Where-Object { $_.PsIsContainer -eq $true } | Select-Object -ExpandProperty Name
    }
    #endregion

    [System.Array]$Results
    #endregion
}
function New-OSDCloudTemplate {
    <#
    .SYNOPSIS
    Creates resources by using New-OSDCloudTemplate.
 
    .DESCRIPTION
    Provides the implementation for New-OSDCloudTemplate.
 
    .PARAMETER Name
    Specifies the value for Name.
 
    .PARAMETER Language
    Specifies the value for Language.
 
    .PARAMETER CumulativeUpdate
    Specifies the value for CumulativeUpdate.
 
    .PARAMETER SetAllIntl
    Specifies the value for SetAllIntl.
 
    .PARAMETER SetInputLocale
    Specifies the value for SetInputLocale.
 
    .PARAMETER WinRE
    Indicates whether to enable WinRE.
 
    .PARAMETER Add7Zip
    Indicates whether to enable Add7Zip.
 
    .EXAMPLE
    New-OSDCloudTemplate -Name <Name> -Language <Language>
    Runs New-OSDCloudTemplate with common parameters.
 
    .NOTES
    Author: David Segura - Recast Software
    2026-07-09 - Updated comment-based help
 
    .LINK
    https://github.com/OSDeploy/OSD/tree/master/docs
    #>

    [CmdletBinding()]
    param (
        [System.String]
        #Name of the OSDCloud Template. This determines the OSDCloud Template Path
        $Name = 'default',

        [ValidateSet (
            '*','ar-sa','bg-bg','cs-cz','da-dk','de-de','el-gr',
            'en-gb','es-es','es-mx','et-ee','fi-fi',
            'fr-ca','fr-fr','he-il','hr-hr','hu-hu','it-it',
            'ja-jp','ko-kr','lt-lt','lv-lv','nb-no','nl-nl',
            'pl-pl','pt-br','pt-pt','ro-ro','ru-ru','sk-sk',
            'sl-si','sr-latn-rs','sv-se','th-th','tr-tr',
            'uk-ua','zh-cn','zh-tw'
        )]
        [System.String[]]
        #Adds additional language ADK Packages
        $Language,

        [ValidateScript({
            if (-Not ($_ | Test-Path)) {
                throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] CumulativeUpdate must be a valid path to a file."
            }
            if (-Not ($_ | Test-Path -PathType Leaf)) {
                throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] CumulativeUpdate parameter must be a file, not a folder."
            }
            if ($_ -notmatch "(\.cab|\.msu)") {
                throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] CumulativeUpdate must be a .cab or .msu file."
            }
            return $true
        })]
        [System.IO.FileInfo]
        #Installs the specified Cumulative Update Package
        $CumulativeUpdate,

        [System.String]
        #Sets all International settings in WinPE to the specified setting
        $SetAllIntl,

        [System.String]
        #Sets the default InputLocale in WinPE to the specified Input Locale
        $SetInputLocale,

        [System.Management.Automation.SwitchParameter]
        #Uses Windows 10 WinRE.wim instead of the ADK Boot.wim
        $WinRE,

        [System.Management.Automation.SwitchParameter]
        #Adds 7Zip to Boot Image
        $Add7Zip
    )
#=================================================
# WinREDriver
#=================================================
$WinREDriver = @'
[Version]
Signature = "$WINDOWS NT$"
Class = System
ClassGuid = {4D36E97d-E325-11CE-BFC1-08002BE10318}
Provider = OSDeploy
DriverVer = 07/20/2021,2021.07.20.0
 
[DefaultInstall]
AddReg = AddReg
 
[AddReg]
;rootkey,[subkey],[value],[flags],[data]
;0x00000 REG_SZ
;0x00001 REG_BINARY
;0x10000 REG_MULTI_SZ
;0x20000 REG_EXPAND_SZ
;0x10001 REG_DWORD
;0x20001 REG_NONE
HKLM,"Software\Microsoft\Windows NT\CurrentVersion\WinPE",CustomBackground,0x10000,"X:\Windows\System32\winpe.jpg"
'@

#=================================================
# WinPE Console Registry Settings
#=================================================
$RegistryConsole = @'
Windows Registry Editor Version 5.00
 
[HKEY_LOCAL_MACHINE\Default\Console]
"ColorTable00"=dword:000c0c0c
"ColorTable01"=dword:00da3700
"ColorTable02"=dword:000ea113
"ColorTable03"=dword:00dd963a
"ColorTable04"=dword:001f0fc5
"ColorTable05"=dword:00981788
"ColorTable06"=dword:00009cc1
"ColorTable07"=dword:00cccccc
"ColorTable08"=dword:00767676
"ColorTable09"=dword:00ff783b
"ColorTable10"=dword:000cc616
"ColorTable11"=dword:00d6d661
"ColorTable12"=dword:005648e7
"ColorTable13"=dword:009e00b4
"ColorTable14"=dword:00a5f1f9
"ColorTable15"=dword:00f2f2f2
"CtrlKeyShortcutsDisabled"=dword:00000000
"CursorColor"=dword:ffffffff
"CursorSize"=dword:00000019
"DefaultBackground"=dword:ffffffff
"DefaultForeground"=dword:ffffffff
"EnableColorSelection"=dword:00000000
"ExtendedEditKey"=dword:00000001
"ExtendedEditKeyCustom"=dword:00000000
"FaceName"="Consolas"
"FilterOnPaste"=dword:00000001
"FontFamily"=dword:00000036
"FontSize"=dword:00140000
"FontWeight"=dword:00000000
"ForceV2"=dword:00000000
"FullScreen"=dword:00000000
"HistoryBufferSize"=dword:00000032
"HistoryNoDup"=dword:00000000
"InsertMode"=dword:00000001
"LineSelection"=dword:00000001
"LineWrap"=dword:00000001
"LoadConIme"=dword:00000001
"NumberOfHistoryBuffers"=dword:00000004
"PopupColors"=dword:000000f5
"QuickEdit"=dword:00000001
"ScreenBufferSize"=dword:23290078
"ScreenColors"=dword:00000007
"ScrollScale"=dword:00000001
"TerminalScrolling"=dword:00000000
"TrimLeadingZeros"=dword:00000000
"WindowAlpha"=dword:000000ff
"WindowSize"=dword:001e0078
"WordDelimiters"=dword:00000000
 
[HKEY_LOCAL_MACHINE\Default\Console\%SystemRoot%_System32_cmd.exe]
"FaceName"="Consolas"
"FilterOnPaste"=dword:00000000
"FontSize"=dword:00100000
"FontWeight"=dword:00000190
"LineSelection"=dword:00000000
"LineWrap"=dword:00000000
"WindowAlpha"=dword:00000000
"WindowPosition"=dword:00000000
"WindowSize"=dword:00110054
 
[HKEY_LOCAL_MACHINE\Default\Console\%SystemRoot%_System32_WindowsPowerShell_v1.0_powershell.exe]
"ColorTable05"=dword:00562401
"ColorTable06"=dword:00f0edee
"FaceName"="Consolas"
"FilterOnPaste"=dword:00000000
"FontFamily"=dword:00000036
"FontSize"=dword:00140000
"FontWeight"=dword:00000190
"LineSelection"=dword:00000000
"LineWrap"=dword:00000000
"PopupColors"=dword:000000f3
"QuickEdit"=dword:00000001
"ScreenBufferSize"=dword:03e8012c
"ScreenColors"=dword:00000056
"WindowAlpha"=dword:00000000
"WindowSize"=dword:0020006c
 
[HKEY_LOCAL_MACHINE\Default\Console\%SystemRoot%_SysWOW64_WindowsPowerShell_v1.0_powershell.exe]
"ColorTable05"=dword:00562401
"ColorTable06"=dword:00f0edee
"FaceName"="Consolas"
"FilterOnPaste"=dword:00000000
"FontFamily"=dword:00000036
"FontSize"=dword:00140000
"FontWeight"=dword:00000190
"LineSelection"=dword:00000000
"LineWrap"=dword:00000000
"PopupColors"=dword:000000f3
"QuickEdit"=dword:00000001
"ScreenBufferSize"=dword:03e8012c
"ScreenColors"=dword:00000056
"WindowAlpha"=dword:00000000
"WindowSize"=dword:0020006c
'@

    #region Initialize
    $TemplateStartTime = Get-Date
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] $($MyInvocation.MyCommand.Name)"
    Block-WinPE
    $CurrentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
    $CurrentPrincipal = [Security.Principal.WindowsPrincipal]::new($CurrentIdentity)
    if (-not $CurrentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
        Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Administrative rights are required"
        return
    }
    Block-WindowsVersionNe10
    Block-PowerShellVersionLt5
    Block-NoCurl
    #endregion

    <#
        Removing ARM64 Support for now
        #region Get Adk Paths
 
        if ($PSBoundParameters.ContainsKey('ARM64')) {
            $WindowsAdkPaths = Get-WindowsAdkPaths -Architecture 'arm64'
        }
        else {
            $WindowsAdkPaths = Get-WindowsAdkPaths
        }
 
        if ($OSArch -eq 'ARM64') {
            $WindowsAdkPaths = Get-WindowsAdkPaths -Architecture 'arm64'
        }
        else {
            $WindowsAdkPaths = Get-WindowsAdkPaths
        }
    #>


    $WindowsAdkPaths = Get-WindowsAdkPaths

    if ($null -eq $WindowsAdkPaths) {
        Write-Host -ForegroundColor DarkGray "========================================================================="
        Write-Warning "[$(Get-Date -format s)] Could not get ADK going, sorry"
        Write-Host -ForegroundColor DarkGray "========================================================================="
        Break
    }
    #endregion

    #region Test WinRE
    if ($PSBoundParameters.ContainsKey('WinRE')) {
        if ((Get-WinREPartition).OperationalStatus -ne 'Online') {
            Write-Host -ForegroundColor DarkGray "========================================================================="
            Write-Warning "[$(Get-Date -format s)] You can't use WinRE because of some issue. Sorry!"
            Write-Host -ForegroundColor DarkGray "========================================================================="
            Break
        }
        if ((Get-RegCurrentVersion).CurrentBuild -gt 20000) {
            #Write-Host -ForegroundColor DarkGray "========================================================================="
            #Write-Warning "[$(Get-Date -format s)] Windows 11 WinRE may not support booting some Virtual Machines"
            #Write-Warning "[$(Get-Date -format s)] It is recommended that you remove the -WinRE parameter if you need Virtual Machine support"
            #Write-Warning "[$(Get-Date -format s)] Press Ctrl+C to cancel in the next 10 seconds"
            #Start-Sleep -Seconds 10
            #Write-Host -ForegroundColor DarkGray "========================================================================="
        }
    }
    #endregion

    #region Test WimSourcePath
    $WimSourcePath = $WindowsAdkPaths.WimSourcePath
    if (-NOT (Test-Path $WimSourcePath)) {
        Write-Host -ForegroundColor DarkGray "========================================================================="
        Write-Warning "[$(Get-Date -format s)] Could not find the ADK WimSourcePath: $WimSourcePath"
        Write-Host -ForegroundColor DarkGray "========================================================================="
        Break
    }
    #endregion

    #region Template
    Write-Host -ForegroundColor DarkGray "========================================================================="
    if ($Name -eq 'default') {
        $OSDCloudTemplate = "$env:ProgramData\OSDCloud"
    }
    else {
        $OSDCloudTemplate = "$env:ProgramData\OSDCloud\Templates\$Name"
    }

    if (-NOT (Test-Path $OSDCloudTemplate)) {
        Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Creating OSDCloud Template: $OSDCloudTemplate"
        $null = New-Item -Path $OSDCloudTemplate -ItemType Directory -Force
    }
    #endregion

    #region Logging
    $TemplateLogs = "$OSDCloudTemplate\Logs\Template"
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Creating OSDCloud Template Logs at $TemplateLogs"

    if (Test-Path $TemplateLogs) {
        $null = Remove-Item -Path "$TemplateLogs\*" -Recurse -Force -ErrorAction Ignore | Out-Null
    }
    if (-NOT (Test-Path $TemplateLogs)) {
        $null = New-Item -Path $TemplateLogs -ItemType Directory -Force | Out-Null
    }

    $Transcript = "$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-New-OSDCloudTemplate.log"
    Start-Transcript -Path (Join-Path $TemplateLogs $Transcript) -ErrorAction Ignore
    #endregion

    #region Mirror ADK Media
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Mirroring ADK Media using Robocopy"
    Write-Host -ForegroundColor Yellow 'Mirroring will remove any previous WinPE and will force a full rebuild'

    $PathWinPEMedia = $WindowsAdkPaths.PathWinPEMedia
    Write-Host -ForegroundColor DarkGray "Source: $PathWinPEMedia"

    $DestinationMedia = Join-Path $OSDCloudTemplate 'Media'
    Write-Host -ForegroundColor DarkGray "Destination: $DestinationMedia"

    $null = robocopy "$PathWinPEMedia" "$DestinationMedia" *.* /mir /b /ndl /np /r:0 /w:0 /xj /LOG+:$TemplateLogs\Robocopy.log
    #endregion

    #region Copy Boot.wim
    #=================================================
    Write-Host -ForegroundColor DarkGray "========================================================================="
    $DestinationSources = Join-Path $DestinationMedia 'sources'
    if (-NOT (Test-Path "$DestinationSources")) {
        New-Item -Path "$DestinationSources" -ItemType Directory -Force -ErrorAction Stop | Out-Null
    }
    if ($PSBoundParameters.ContainsKey('WinRE')) {
        Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Copying WinRE.wim"
        Write-Host -ForegroundColor Yellow "OSD Function: Copy-WinREWIM"

        $BootWim = Join-Path $DestinationSources 'winre.wim'
        Write-Host -ForegroundColor DarkGray "Destination: $BootWim"

        Copy-WinREWIM -DestinationDirectory $DestinationSources -DestinationFileName 'winre.wim' -ErrorAction Stop | Out-Null
    }
    else {
        Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Copying ADK WinPE.wim"
        $BootWim = Join-Path $DestinationSources 'boot.wim'
        Write-Host -ForegroundColor DarkGray "Source: $WimSourcePath"
        Write-Host -ForegroundColor DarkGray "Destination: $BootWim"

        Copy-Item -Path $WimSourcePath -Destination $BootWim -Force -ErrorAction Stop | Out-Null
    }
    #endregion

    #region Test BootWim
    if (!(Test-Path $BootWim)) {
        Write-Host -ForegroundColor DarkGray "========================================================================="
        Write-Warning "I'm not sure what happened, but I can't find $BootWim"
        Write-Host -ForegroundColor DarkGray "========================================================================="
        Break
    }
    attrib -s -h -r $DestinationSources
    attrib -s -h -r $BootWim
    #endregion

    #region wgl4_boot.ttf
    #This is used to resolve issues with WinPE Resolutions in 2004/20H2
    <#
    if ((Get-RegCurrentVersion).CurrentBuild -lt 20000) {
        Write-Host -ForegroundColor DarkGray "========================================================================="
        Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Replacing Boot Media font wgl4_boot.ttf"
        Write-Host -ForegroundColor Yellow "Replacing this file resolves an issue where WinPE does not boot to the proper display resolution"
 
        $SourceUrl = 'https://github.com/OSDeploy/Archive-OSDCloud/raw/main/Media/boot/fonts/wgl4_boot.ttf'
        if (Test-WebConnection -Uri $SourceUrl) {
            Write-Host -ForegroundColor DarkGray "Source: $SourceUrl"
            Write-Host -ForegroundColor DarkGray "Destination: $DestinationMedia\boot\fonts\wgl4_boot.ttf"
            Save-WebFile -SourceUrl $SourceUrl -DestinationDirectory "$DestinationMedia\boot\fonts" -Overwrite | Out-Null
        }
 
        $SourceUrl = 'https://github.com/OSDeploy/Archive-OSDCloud/raw/main/Media/efi/microsoft/boot/fonts/wgl4_boot.ttf'
        if (Test-WebConnection -Uri $SourceUrl) {
            Write-Host -ForegroundColor DarkGray "Source: $SourceUrl"
            Write-Host -ForegroundColor DarkGray "Destination: $DestinationMedia\efi\microsoft\boot\fonts\wgl4_boot.ttf"
            Save-WebFile -SourceUrl $SourceUrl -DestinationDirectory "$DestinationMedia\efi\microsoft\boot\fonts" -Overwrite | Out-Null
        }
    }
    #>

    #endregion

    #region Mount-MyWindowsImage
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Mount Boot.wim"
    Write-Host -ForegroundColor Yellow "OSD Function: Mount-MyWindowsImage"
    $MountMyWindowsImage = Mount-MyWindowsImage $BootWim
    $MountPath = $MountMyWindowsImage.Path
    Write-Host -ForegroundColor DarkGray "MountPath: $MountPath"
    #endregion

    #region WinPE Information
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] WinPE Information"
    $WinPECurrentInfo = Get-RegCurrentVersion -Path $MountPath
    $WinPECurrentInfo
    #endregion

    #region WinRE
    #=================================================
    if ($PSBoundParameters.ContainsKey('WinRE')) {
        #=================================================
        # Wallpaper
        #=================================================
        Write-Host -ForegroundColor DarkGray "========================================================================="
        Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] WinRE Wallpaper"
        Write-Host -ForegroundColor Yellow "WinRE does not use the standard winpe.jpg and uses an all black winre.jpg"
        Write-Host -ForegroundColor Yellow "This step adds the default WinPE Wallpaper and modifies the Registry to point to winpe.jpg"

        $Wallpaper = '/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD5vooor+sD+KwooooAKKKKACiiigD/2Q=='
        [byte[]]$Bytes = [convert]::FromBase64String($Wallpaper)
        [System.IO.File]::WriteAllBytes("$env:TEMP\winpe.jpg",$Bytes)
        #[System.IO.File]::WriteAllBytes("$env:TEMP\winre.jpg",$Bytes)

        Write-Host -ForegroundColor DarkGray "Injecting $MountPath\Windows\System32\winpe.jpg"
        $null = robocopy "$env:TEMP" "$MountPath\Windows\System32" winpe.jpg /b /ndl /np /r:0 /w:0 /xj /LOG+:$TemplateLogs\Robocopy.log

        #Write-Host -ForegroundColor DarkGray "Injecting $MountPath\Windows\System32\winre.jpg"
        #$null = robocopy "$env:TEMP" "$MountPath\Windows\System32" winre.jpg /b /ndl /np /r:0 /w:0 /xj /LOG+:$TemplateLogs\Robocopy.log
        #=================================================
        # Build Driver
        #=================================================
        $InfFile = "$env:Temp\Set-WinREWallpaper.inf"
        New-Item -Path $InfFile -Force
        Set-Content -Path $InfFile -Value $WinREDriver -Encoding Unicode -Force
        #=================================================
        # Add Driver
        #=================================================
        Add-WindowsDriver -Path $MountPath -Driver $InfFile -ForceUnsigned
        #=================================================
        # Wireless
        #=================================================
        Write-Host -ForegroundColor DarkGray "========================================================================="
        Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] WinRE Wireless"
        Write-Host -ForegroundColor Yellow "These files need to be added to support Wireless"

        $SourceFile = "$env:SystemRoot\System32\dmcmnutils.dll"
        if (Test-Path $SourceFile) {
            Write-Host -ForegroundColor DarkGray $SourceFile
            $null = robocopy "$env:SystemRoot\System32" "$MountPath\Windows\System32" dmcmnutils.dll /b /ndl /np /r:0 /w:0 /xj /LOG+:$TemplateLogs\Robocopy.log
        }
        else {
            Write-Warning "Could not find $SourceFile"
        }

        $SourceFile = "$env:SystemRoot\System32\mdmpostprocessevaluator.dll"
        if (Test-Path $SourceFile) {
            Write-Host -ForegroundColor DarkGray $SourceFile
            $null = robocopy "$env:SystemRoot\System32" "$MountPath\Windows\System32" mdmpostprocessevaluator.dll /b /ndl /np /r:0 /w:0 /xj /LOG+:$TemplateLogs\Robocopy.log
        }
        else {
            Write-Warning "Could not find $SourceFile"
        }

        $SourceFile = "$env:SystemRoot\System32\mdmregistration.dll"
        if (Test-Path $SourceFile) {
            Write-Host -ForegroundColor DarkGray $SourceFile
            $null = robocopy "$env:SystemRoot\System32" "$MountPath\Windows\System32" mdmregistration.dll /b /ndl /np /r:0 /w:0 /xj /LOG+:$TemplateLogs\Robocopy.log
        }
        else {
            Write-Warning "Could not find $SourceFile"
        }

        Write-Host -ForegroundColor DarkGray "Downloading https://github.com/okieselbach/Helpers/raw/master/WirelessConnect/WirelessConnect/bin/Release/WirelessConnect.exe"
        Save-WebFile -SourceUrl 'https://github.com/okieselbach/Helpers/raw/master/WirelessConnect/WirelessConnect/bin/Release/WirelessConnect.exe' -DestinationDirectory "$MountPath\Windows" | Out-Null
    }
    #endregion

    #region Set ADK Packages
    $ErrorActionPreference = 'Ignore'
    $WinPEOCs = $WindowsAdkPaths.WinPEOCs

    $OCPackages = @(
        'WMI'
        'HTA'
        'NetFx'
        'Scripting'
        'PowerShell'
        'SecureStartup'
        'DismCmdlets'
        'Dot3Svc'
        'EnhancedStorage'
        'FMAPI'
        'GamingPeripherals'
        'HSP-Driver'
        'PPPoE'
        'PlatformId'
        'PmemCmdlets'
        'RNDIS'
        'SecureBootCmdlets'
        'StorageWMI'
        'WDS-Tools'
    )

    if ($OSArch -eq 'ARM64') {
        # Require specific order of install of packages or it fails.
        #$OCPackages =@('Dot3Svc','EnhancedStorage','MDAC','NetFx','PowerShell','Scripting','SecureBootCmdlets','WMI','StorageWMI','PmemCmdlets','DismCmdlets','SecureStartup','x64-Support','PlatformId')
        $OCPackages += 'x64-Support'
        $OCPackages += 'MDAC'
    }
    <#
    if ($PSBoundParameters.ContainsKey('ARM64')) {
        # Require specific order of install of packages or it fails.
        #$OCPackages =@('Dot3Svc','EnhancedStorage','MDAC','NetFx','PowerShell','Scripting','SecureBootCmdlets','WMI','StorageWMI','PmemCmdlets','DismCmdlets','SecureStartup','x64-Support','PlatformId')
        $OCPackages += 'x64-Support'
        $OCPackages += 'MDAC'
    }
    #>


    #endregion

    #region Install Default en-us Language
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Adding default en-US ADK Packages"
    Write-Host -ForegroundColor Yellow "Dism Function: Add-WindowsPackage"
    $Lang = 'en-us'

    foreach ($Package in $OCPackages) {
        $SourceFile = "$WinPEOCs\WinPE-$Package.cab"
        if (Test-Path $SourceFile) {
            Write-Host -ForegroundColor DarkGray "$SourceFile"
            $PackageName = "Add-WindowsPackage-WinPE-$Package"
            $CurrentLog = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-$PackageName.log"

            Try {Add-WindowsPackage -Path $MountPath -PackagePath $SourceFile -LogPath "$CurrentLog" | Out-Null}
            Catch {Write-Host -ForegroundColor Red $CurrentLog}
        }
        else {
            Write-Warning "Could not find $SourceFile"
        }
    }

    $SourceFile = "$WinPEOCs\$Lang\lp.cab"
    if (Test-Path $SourceFile) {
        Write-Host -ForegroundColor DarkGray "$SourceFile"
        $PackageName = "Add-WindowsPackage-WinPE-lp_$Lang"
        $CurrentLog = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-$PackageName.log"

        Try {Add-WindowsPackage -Path $MountPath -PackagePath $SourceFile -LogPath "$CurrentLog" | Out-Null}
        Catch {Write-Host -ForegroundColor Red $CurrentLog}
    }
    else {
        Write-Warning "Could not find $SourceFile"
    }

    foreach ($Package in $OCPackages) {
        $SourceFile = "$WinPEOCs\$Lang\WinPE-$Package`_$Lang.cab"
        if (Test-Path $SourceFile) {
            Write-Host -ForegroundColor DarkGray "$SourceFile"
            $PackageName = "Add-WindowsPackage-WinPE-$Package`_$Lang"
            $CurrentLog = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-$PackageName.log"

            Try {Add-WindowsPackage -Path $MountPath -PackagePath $SourceFile -LogPath "$CurrentLog" | Out-Null}
            Catch {Write-Host -ForegroundColor Red $CurrentLog}
        }
    }
    #endregion

    #region Save-WindowsImage
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Save Windows Image"
    Write-Host -ForegroundColor Yellow "Dism Function: Save-WindowsImage"

    $CurrentLog = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-Save-WindowsImage.log"
    Save-WindowsImage -Path $MountPath -LogPath $CurrentLog | Out-Null
    #endregion

    #region Install Selected Language
    if ($Language -contains '*') {
        $Language = Get-ChildItem $WinPEOCs -Directory | Where-Object {$_.Name -ne 'en-us'} | Select-Object -ExpandProperty Name
    }

    foreach ($Lang in $Language) {
        Write-Host -ForegroundColor DarkGray "========================================================================="
        Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Adding $Lang ADK Packages"
        Write-Host -ForegroundColor Yellow "Dism Function: Add-WindowsPackage"

        $SourceFile = "$WinPEOCs\$Lang\lp.cab"
        if (Test-Path $SourceFile) {
            Write-Host -ForegroundColor DarkGray "$SourceFile"
            $PackageName = "Add-WindowsPackage-WinPE-lp_$Lang"
            $CurrentLog = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-$PackageName.log"

            Try {Add-WindowsPackage -Path $MountPath -PackagePath $SourceFile -LogPath "$CurrentLog" | Out-Null}
            Catch {Write-Host -ForegroundColor Red $CurrentLog}
        }
        else {
            Write-Warning "Could not find $SourceFile"
        }

        foreach ($Package in $OCPackages) {
            $SourceFile = "$WinPEOCs\$Lang\WinPE-$Package`_$Lang.cab"
            if (Test-Path $SourceFile) {
                Write-Host -ForegroundColor DarkGray "$SourceFile"
                $PackageName = "Add-WindowsPackage-WinPE-$Package`_$Lang"
                $CurrentLog = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-$PackageName.log"

                Try {Add-WindowsPackage -Path $MountPath -PackagePath $SourceFile -LogPath "$CurrentLog" | Out-Null}
                Catch {Write-Host -ForegroundColor Red $CurrentLog}
            }
        }

            # Generates a new Lang.ini file which is used to define the language packs inside the image
        if ( (Test-Path -Path "$MountPath\sources\lang.ini") ) {
            Write-Host -ForegroundColor DarkGray "Updating lang.ini"
            $CurrentLog = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-Gen-LangINI.log"
            DISM /image:"$MountPath" /Gen-LangINI /distribution:"$MountPath" /LogPath:"$CurrentLog"
        }

        Write-Host -ForegroundColor DarkGray "========================================================================="
        Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Save Windows Image"
        Write-Host -ForegroundColor Yellow "Dism Function: Save-WindowsImage"
        $CurrentLog = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-Save-WindowsImage.log"
        Save-WindowsImage -Path $MountPath -LogPath $CurrentLog | Out-Null
    }
    #endregion

    #region International Settings
    if ($SetAllIntl -or $SetInputLocale) {
        Write-Host -ForegroundColor DarkGray "========================================================================="
        Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Current Get-Intl Settings"
        $CurrentLog = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-Get-Intl.log"
        Dism /image:"$MountPath" /Get-Intl /LogPath:"$CurrentLog"
    }

    if ($SetAllIntl) {
        Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Applying Set-AllIntl"
        $CurrentLog = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-Set-AllIntl.log"
        Dism /image:"$MountPath" /Set-AllIntl:$SetAllIntl /LogPath:"$CurrentLog"
    }

    if ($SetInputLocale) {
        Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Applying Set-InputLocale"
        $CurrentLog = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-Set-InputLocale.log"
        Dism /image:"$MountPath" /Set-InputLocale:$SetInputLocale /LogPath:"$CurrentLog"
    }

    if ($SetAllIntl -or $SetInputLocale) {
        Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Updated Get-Intl Settings"
        $CurrentLog = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-Get-Intl.log"
        Dism /image:"$MountPath" /Get-Intl /LogPath:"$CurrentLog"
    }
    #endregion

    #region Inject Additional Files
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] WinPE Additional Files"
    #=================================================
    # curl.exe
    #=================================================
    Write-Host -ForegroundColor Yellow "cURL is required for downloading files in WinPE"
    $SourceFile = "$env:SystemRoot\System32\curl.exe"
    Write-Host -ForegroundColor DarkGray $SourceFile
    if (Test-Path $SourceFile) {
        $null = robocopy "$env:SystemRoot\System32" "$MountPath\Windows\System32" curl.exe /b /ndl /np /r:0 /w:0 /xj /LOG+:$TemplateLogs\Robocopy.log
    }
    else {
        Write-Warning "Could not find $SourceFile"
    }
    #=================================================
    # setx.exe
    #=================================================
    Write-Host -ForegroundColor Yellow "Setx is required for setting System Variables"
    $SourceFile = "$env:SystemRoot\System32\setx.exe"
    if (Test-Path $SourceFile) {
        Write-Host -ForegroundColor DarkGray $SourceFile
        $null = robocopy "$env:SystemRoot\System32" "$MountPath\Windows\System32" setx.exe /b /ndl /np /r:0 /w:0 /xj /LOG+:$TemplateLogs\Robocopy.log
    }
    else {
        Write-Warning "Could not find $SourceFile"
    }
    #=================================================
    # msinfo32.exe
    #=================================================
    Write-Host -ForegroundColor Yellow "MSInfo32 is helpful for verifying Hardware in WinPE"
    $SourceFile = "$env:SystemRoot\System32\msinfo32.exe"
    if (Test-Path $SourceFile) {
        Write-Host -ForegroundColor DarkGray $SourceFile
        Write-Host -ForegroundColor DarkGray "$env:SystemRoot\System32\*\msinfo32.exe.mui"
        $null = robocopy "$env:SystemRoot\System32" "$MountPath\Windows\System32" msinfo32.exe /b /ndl /np /r:0 /w:0 /xj /LOG+:$TemplateLogs\Robocopy.log
        $null = robocopy "$env:SystemRoot\System32" "$MountPath\Windows\System32" msinfo32.exe.mui /s /b /ndl /np /r:0 /w:0 /xj /LOG+:$TemplateLogs\Robocopy.log
    }
    else {
        Write-Warning "Could not find $SourceFile"
    }
    #=================================================
    # osk.exe
    #=================================================
    Write-Host -ForegroundColor Yellow "OSK adds WinPE On Screen Keyboard"
    $SourceFile = "$env:SystemRoot\System32\osk.exe"
    if (Test-Path $SourceFile) {
        Write-Host -ForegroundColor DarkGray $SourceFile
        $null = robocopy "$env:SystemRoot\System32" "$MountPath\Windows\System32" osk.exe /b /ndl /np /r:0 /w:0 /xj /LOG+:$TemplateLogs\Robocopy.log
        $null = robocopy "$env:SystemRoot\System32" "$MountPath\Windows\System32" osksupport.dll /s /b /ndl /np /r:0 /w:0 /xj /LOG+:$TemplateLogs\Robocopy.log
    }
    else {
        Write-Warning "Could not find $SourceFile"
    }
    $SourceFile = "$env:SystemRoot\System32\osksupport.dll"
    if (Test-Path $SourceFile) {
        Write-Host -ForegroundColor DarkGray $SourceFile
        $null = robocopy "$env:SystemRoot\System32" "$MountPath\Windows\System32" osksupport.dll /b /ndl /np /r:0 /w:0 /xj /LOG+:$TemplateLogs\Robocopy.log
    }
    else {
        Write-Warning "Could not find $SourceFile"
    }
    #=================================================
    # 7zip x64 Portable
    #=================================================
    if ($PSBoundParameters.ContainsKey('Add7Zip')) {
        Add-7Zip2BootImage
    }


    #=================================================
    # Adding Microsoft DartConfig from MDT
    #=================================================
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Microsoft DaRT Config from MDT"
    $SourceFile = "$env:ProgramFiles\Microsoft Deployment Toolkit\Templates\DartConfig8.dat"
    if (Test-Path $SourceFile) {
        Write-Host -ForegroundColor DarkGray $SourceFile
        Copy-Item -Path $SourceFile -Destination "$MountPath\Windows\System32\DartConfig.dat" -Force
    }
    else {
        Write-Warning "Could not find $SourceFile"
    }
    #=================================================
    # Adding Microsoft DaRT
    #=================================================
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Microsoft DaRT"
    $SourceFile = "$env:ProgramFiles\Microsoft DaRT\v10\Toolsx64.cab"
    if ($Name -match 'public') {
        Write-Host -ForegroundColor DarkGray 'Skipping Microsoft DaRT for Public Template'
    }
    elseif (Test-Path $SourceFile) {
        Write-Host -ForegroundColor DarkGray $SourceFile
        expand.exe "$SourceFile" -F:*.* "$MountPath" | Out-Null
        if (!(Test-Path "$MountPath\Windows\System32\DartConfig.dat")) {
            Write-Warning "Microsoft DaRT requires MDT to be installed so DartConfig.dat can be copied"
        }
    }
    else {
        Write-Warning "Could not find $SourceFile"
    }
    #endregion

    #region Save-WindowsImage
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Save Windows Image"
    Write-Host -ForegroundColor Yellow "Dism Function: Save-WindowsImage"

    $CurrentLog = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-Save-WindowsImage.log"
    Save-WindowsImage -Path $MountPath -LogPath $CurrentLog | Out-Null
    #endregion

    #region Set PowerShell Execution Policy
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Set WinPE PowerShell ExecutionPolicy to Bypass"
    Write-Host -ForegroundColor Yellow "OSD Function: Set-WindowsImageExecutionPolicy"
    Set-WindowsImageExecutionPolicy -Path $MountPath -ExecutionPolicy Bypass | Out-Null
    #endregion

    #region Enable PowerShell Gallery
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Enable WinPE PowerShell Gallery"
    Write-Host -ForegroundColor Yellow "OSD Function: Enable-PEWindowsImagePSGallery"
    Enable-PEWindowsImagePSGallery -Path $MountPath | Out-Null
    #endregion

    #region Remove winpeshl.ini
    $SourceFile = "$MountPath\Windows\System32\winpeshl.ini"
    if (Test-Path $SourceFile) {
        Write-Host -ForegroundColor DarkGray "========================================================================="
        Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Removing WinRE $SourceFile"
        Write-Host -ForegroundColor Yellow "This file is present when using WinRE.wim and needs to be removed for WinPE compatibility"
        Remove-Item -Path $SourceFile -Force
    }
    #endregion

    #region Registry Fixes
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Modifying WinPE CMD and PowerShell Console settings"
    Write-Host -ForegroundColor Yellow "This increases the buffer and sets the window metrics and default fonts"
    $RegistryConsole | Out-File -FilePath "$env:TEMP\RegistryConsole.reg" -Encoding ascii -Width 2000 -Force

    #Mount Registry
    Invoke-Exe reg load HKLM\Default "$MountPath\Windows\System32\Config\DEFAULT"
    Invoke-Exe reg import "$env:TEMP\RegistryConsole.reg"

    #reg add "HKLM\Default\Control Panel\Colors" /t REG_SZ /v Background /d "0 99 177" /f

    #Scaling
<# reg add "HKLM\Default\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers" /t REG_SZ /v "X:\Windows\System32\WirelessConnect.exe" /d "~ HIGHDPIAWARE" /f
    reg add "HKLM\Default\Control Panel\Desktop" /t REG_DWORD /v LogPixels /d 96 /f
    reg add "HKLM\Default\Control Panel\Desktop" /v Win8DpiScaling /t REG_DWORD /d 0x00000001 /f
    reg add "HKLM\Default\Control Panel\Desktop" /v DpiScalingVer /t REG_DWORD /d 0x00001018 /f #>


    #Unload Registry
    Invoke-Exe reg unload HKLM\Default | Out-Null
    #endregion

    #region CumulativeUpdate
    if ($CumulativeUpdate) {
        Write-Host -ForegroundColor DarkGray "========================================================================="
        Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Apply Cumulative Update"

        $Params = @{
            ErrorAction = 'Stop'
            LogLevel = 'WarningsInfo'
            LogPath = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-CumulativeUpdate.log"
            PackagePath = $CumulativeUpdate
            Path = $MountPath
            Verbose = $true
        }

        Write-Host -ForegroundColor Yellow "Add-WindowsPackage -PackagePath" $Params.PackagePath
        Write-Host -ForegroundColor DarkGray "-Path" $Params.Path
        Write-Host -ForegroundColor DarkGray "-LogPath" $Params.LogPath

        try {
            Add-WindowsPackage @Params
        }
        catch {
            Write-Warning $PSItem.Exception.Message
        }
        finally {
            $Error.Clear()
        }

        Write-Host -ForegroundColor DarkGray "========================================================================="
        Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Updated WinPE Information"
        $WinPEUpdatedInfo = Get-RegCurrentVersion -Path $MountPath
        $WinPEUpdatedInfo

        if ($WinPECurrentInfo.UBR -eq $WinPEUpdatedInfo.UBR) {
            Write-Warning 'There were no changes to the UBR after applying the Cumulative Update'
            Write-Warning 'You should verify that the Cumulative Update is for this version of WinPE'
            Write-Warning 'Boot Files will not be updated'
            Write-Host
            Start-Sleep -Seconds 15
        }
        else {
            Write-Host -ForegroundColor DarkGray "========================================================================="
            Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Update Boot Files"

            #bootmgr.efi
            Write-Host -ForegroundColor DarkGray "Source: $MountPath\Windows\boot\efi\bootmgr.efi"
            Write-Host -ForegroundColor Yellow "Destination: $DestinationMedia\bootmgr.efi"
            Copy-Item -Path "$MountPath\Windows\boot\efi\bootmgr.efi" -Destination "$DestinationMedia\bootmgr.efi" -Force

            #bootmgfw.efi
            Write-Host -ForegroundColor DarkGray "Source: $MountPath\Windows\boot\efi\bootmgfw.efi"
            Write-Host -ForegroundColor Yellow "Destination: $DestinationMedia\EFI\Boot\bootx64.efi"
            Copy-Item -Path "$MountPath\Windows\boot\efi\bootmgfw.efi" -Destination "$DestinationMedia\EFI\Boot\bootx64.efi" -Force

            #bootmgfw.efi Microsoft Guidance: https://learn.microsoft.com/en-us/windows/deployment/update/media-dynamic-update#update-winpe
            #Write-Host -ForegroundColor DarkGray "Source: $MountPath\Windows\boot\efi\bootmgfw.efi"
            #Write-Host -ForegroundColor Yellow "Destination: $DestinationMedia\bootmgfw.efi"
            #Copy-Item -Path "$MountPath\Windows\boot\efi\bootmgfw.efi" -Destination "$DestinationMedia\bootmgfw.efi" -Force
        }

        Write-Host -ForegroundColor DarkGray "========================================================================="
        Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Dism Component Cleanup"

        $CurrentLog = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-DismComponentCleanup.log"
        #$CommandLine = "Dism /Cleanup-Image /StartComponentCleanup /Image:`"$MountPath`" /LogPath:`"$CurrentLog`""
        Write-Host -ForegroundColor Yellow "Dism /Image:`"$MountPath`""
        Write-Host -ForegroundColor DarkGray "/Cleanup-Image /StartComponentCleanup"
        Write-Host -ForegroundColor DarkGray "/LogPath:`"$CurrentLog`""

        DISM /Image:"$MountPath" /Cleanup-Image /StartComponentCleanup /LogPath:"$CurrentLog"
    }
    #endregion

    #region Windows Packages
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Windows Packages installed in WinPE"
    Get-WindowsPackage -Path $MountPath | Sort-Object -Property PackageName | Format-Table -AutoSize
    #endregion

    #region Dismount Windows Image and Save
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Dismounting and Saving Windows Image"
    Write-Host -ForegroundColor Yellow "OSD Function: Dismount-MyWindowsImage"
    $MountMyWindowsImage | Dismount-MyWindowsImage -Save
    #endregion

    #region Export WIM to reduce the size
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Exporting Boot.wim"
    if ($PSBoundParameters.ContainsKey('WinRE')) {
        $BootWim = Join-Path $DestinationSources 'boot.wim'
        $WinREWim = Join-Path $DestinationSources 'winre.wim'

        if (Test-Path $BootWim) {
            Remove-Item -Path $BootWim -Force -ErrorAction Stop | Out-Null
        }
        Write-Host -ForegroundColor Yellow "Dism Function: Export-WindowsImage"
        $CurrentLog = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-Export-WindowsImage.log"
        Export-WindowsImage -SourceImagePath $WinREWim -SourceIndex 1 -DestinationImagePath $BootWim -DestinationName 'Microsoft Windows PE (x64)' -LogPath $CurrentLog | Out-Null
        Remove-Item -Path $WinREWim -Force -ErrorAction Stop | Out-Null
    }
    else {
        $SourceImage = Join-Path $DestinationSources 'boot.wim'
        $DestinationImage = Join-Path $DestinationSources 'export.wim'

        if (Test-Path $DestinationImage) {
            Remove-Item -Path $DestinationImage -Force -ErrorAction Stop | Out-Null
        }
        Write-Host -ForegroundColor Yellow "Dism Function: Export-WindowsImage"
        $CurrentLog = "$TemplateLogs\$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-Export-WindowsImage.log"
        Export-WindowsImage -SourceImagePath $SourceImage -SourceIndex 1 -DestinationImagePath $DestinationImage -LogPath $CurrentLog | Out-Null
        Remove-Item -Path $SourceImage -Force -ErrorAction Stop | Out-Null
        Rename-Item -Path $DestinationImage -NewName 'boot.wim' -Force -ErrorAction Stop | Out-Null
    }
    #endregion

    #region Create Config Directories
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Create Config Directories"

    $CreateDirectories = @(
        'Config\AutopilotJSON',
        'Config\AutopilotOOBE',
        'Config\OOBEDeploy',
        'Config\Scripts\SetupComplete',
        'Config\Scripts\Shutdown',
        'Config\Scripts\Startup',
        'Config\Scripts\StartNet'
    )

    if ($Name -match 'public') {
        Write-Host -ForegroundColor DarkGray 'Skipping Config Directories for Public Template'
    }
    else {
        foreach ($Item in $CreateDirectories) {
            $SourcePath = "$OSDCloudTemplate\$Item"
            if (-NOT (Test-Path $SourcePath)) {
                Write-Host -ForegroundColor DarkGray $SourcePath
                New-Item -Path $SourcePath -ItemType Directory -Force | Out-Null
            }
        }
    }
    #endregion

    #region Create OSDCloud ISOs
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Create OSDCloud Template ISOs"
    $isoFileName = 'OSDCloud.iso'
    $isoLabel = 'OSDCloud'
    $null = New-WindowsAdkISO -MediaPath "$OSDCloudTemplate\Media" -isoFileName $isoFileName -isoLabel $isoLabel
    #endregion

    #region Set OSDCloud Template
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Set-OSDCloudTemplate -Name $Name"
    $WinPE = [PSCustomObject]@{
        BuildDate = (Get-Date).ToString('yyyy.MM.dd.HHmmss')
        Version = [Version](Get-Module -Name OSD -ListAvailable | Sort-Object Version -Descending | Select-Object -First 1).Version
    }
    $WinPE | ConvertTo-Json | Out-File "$OSDCloudTemplate\Logs\winpe.json" -Encoding ascii -Width 2000 -Force
    Set-OSDCloudTemplate -Name $Name
    #endregion

    #region Complete
    $TemplateEndTime = Get-Date
    $TemplateTimeSpan = New-TimeSpan -Start $TemplateStartTime -End $TemplateEndTime
    Write-Host -ForegroundColor DarkGray    "================================================"
    Write-Host -ForegroundColor Yellow "[$(Get-Date -format s)] $($MyInvocation.MyCommand.Name) " -NoNewline
    Write-Host -ForegroundColor Cyan "Completed in $($TemplateTimeSpan.ToString("mm' minutes 'ss' seconds'"))"
    Write-Host -ForegroundColor Cyan "OSDCloud Template created at $OSDCloudTemplate"
    Write-Host -ForegroundColor DarkGray "================================================"
    Stop-Transcript
    #endregion
}
function Set-OSDCloudTemplate {
    <#
    .SYNOPSIS
    Sets configuration values by using Set-OSDCloudTemplate.
 
    .DESCRIPTION
    Provides the implementation for Set-OSDCloudTemplate.
 
    .PARAMETER Name
    Specifies the value for Name.
 
    .EXAMPLE
    Set-OSDCloudTemplate -Name <Name>
    Runs Set-OSDCloudTemplate with common parameters.
 
    .NOTES
    Author: David Segura - Recast Software
    2026-07-09 - Updated comment-based help
 
    .LINK
    https://github.com/OSDeploy/OSD/tree/master/docs
    #>

    [CmdletBinding()]
    param (
        [Parameter(Position=0)]
        [System.String]
        #Name of the OSDCloud Template
        $Name = 'default'
    )

    #region Block
    $CurrentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
    $CurrentPrincipal = [Security.Principal.WindowsPrincipal]::new($CurrentIdentity)
    if (-not $CurrentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
        Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Administrative rights are required"
        return
    }
    Block-PowerShellVersionLt5
    Block-WinPE
    #endregion

    #region Set Template Path
    if ($Name -ne 'default') {
        # OSDeploy Compatibility
        if (Test-Path "$env:ProgramData\OSDeploy\MyBootMedia\$Name") {
            $OSDCloudTemplate = "$env:ProgramData\OSDeploy\MyBootMedia\$Name"
        }
        elseif (Test-Path "$env:ProgramData\OSDK\BootMedia\$Name") {
            $OSDCloudTemplate = "$env:ProgramData\OSDK\BootMedia\$Name"
        }
        elseif (Test-Path "C:\OSDKIT\BootMedia\$Name") {
            $OSDCloudTemplate = "C:\OSDKIT\BootMedia\$Name"
        }
        else {
            $OSDCloudTemplate = "$env:ProgramData\OSDCloud\Templates\$Name"
        }
        if (-NOT (Test-Path "$OSDCloudTemplate\Media\sources\boot.wim")) {
            $Name = 'default'
        }
    }

    if ($Name -eq 'default') {
        $OSDCloudTemplate = "$env:ProgramData\OSDCloud"
        if (Test-Path "$env:ProgramData\OSDCloud\template.json") {
            $null = Remove-Item -Path "$env:ProgramData\OSDCloud\template.json" -Force
        }
    }
    else {
        $TemplateSettings = [PSCustomObject]@{
            TemplatePath = $OSDCloudTemplate
        }

        $TemplateSettings | ConvertTo-Json | Out-File "$env:ProgramData\OSDCloud\template.json" -Encoding ascii -Width 2000 -Force
    }
    $OSDCloudTemplate
    #endregion

    #region DEV
<# if ((Test-Path "$env:ProgramData\OSDCloud\Config") -or (Test-Path "$env:ProgramData\OSDCloud\Logs") -or (Test-Path "$env:ProgramData\OSDCloud\Media")) {
        Write-Warning "[$(Get-Date -format s)] Migrating existing OSDCloud Template to $OSDCloudTemplate"
        $null = robocopy "$env:ProgramData\OSDCloud\Config" "$OSDCloudTemplate\Config" *.* /move /e /np /njh /njs /r:0 /w:0
        $null = robocopy "$env:ProgramData\OSDCloud\Autopilot\Profiles" "$OSDCloudTemplate\Config\AutopilotJSON" *.* /move /e /np /njh /njs /r:0 /w:0
        $null = robocopy "$env:ProgramData\OSDCloud\Logs" "$OSDCloudTemplate\Logs" *.* /move /e /np /njh /njs /r:0 /w:0
        $null = robocopy "$env:ProgramData\OSDCloud\Media" "$OSDCloudTemplate\Media" *.* /move /e /np /njh /njs /r:0 /w:0
        $null = robocopy "$env:ProgramData\OSDCloud" "$OSDCloudTemplate" winpe.json /move /np /njh /njs /r:0 /w:0
        $null = robocopy "$env:ProgramData\OSDCloud" "$OSDCloudTemplate" *.iso /move /np /njh /njs /r:0 /w:0
    } #>

    #endregion
}
Register-ArgumentCompleter -CommandName Set-OSDCloudTemplate -ParameterName 'Name' -ScriptBlock {Get-OSDCloudTemplateNames | ForEach-Object {if ($_.Contains(' ')) {"'$_'"} else {$_}}}
#https://github.com/PowerShell/PowerShell/issues/11330
#https://github.com/SteveL-MSFT/NetConfiguration/blob/master/NetConfiguration/NetConfiguration.psm1#L29-L45