Public/OSDCloud/OSDCloudWinPE.ps1

function Edit-OSDCloudWinPE {
    <#
    .SYNOPSIS
    Edits content by using Edit-OSDCloudWinPE.
 
    .DESCRIPTION
    Provides the implementation for Edit-OSDCloudWinPE.
 
    .PARAMETER CloudDriver
    Specifies the value for CloudDriver.
 
    .PARAMETER StartOSDCloudGUI
    Indicates whether to enable StartOSDCloudGUI.
 
    .PARAMETER DriverHWID
    Specifies the value for DriverHWID.
 
    .PARAMETER DriverPath
    Specifies the value for DriverPath.
 
    .PARAMETER PSModuleCopy
    Specifies the value for PSModuleCopy.
 
    .PARAMETER PSModuleInstall
    Specifies the value for PSModuleInstall.
 
    .PARAMETER Startnet
    Specifies the value for Startnet.
 
    .PARAMETER StartOSDCloud
    Specifies the value for StartOSDCloud.
 
    .PARAMETER StartOSDPad
    Specifies the value for StartOSDPad.
 
    .PARAMETER StartPSCommand
    Specifies the value for StartPSCommand.
 
    .PARAMETER StartURL
    Specifies the value for StartURL.
 
    .PARAMETER UpdateUSB
    Indicates whether to enable UpdateUSB.
 
    .PARAMETER Wallpaper
    Specifies the value for Wallpaper.
 
    .PARAMETER UseDefaultWallpaper
    Indicates whether to enable UseDefaultWallpaper.
 
    .PARAMETER Brand
    Specifies the value for Brand.
 
    .PARAMETER WorkspacePath
    Specifies the value for WorkspacePath.
 
    .PARAMETER WirelessConnect
    Indicates whether to enable WirelessConnect.
 
    .PARAMETER WifiProfile
    Specifies the value for WifiProfile.
 
    .PARAMETER Add7Zip
    Indicates whether to enable Add7Zip.
 
    .EXAMPLE
    Edit-OSDCloudWinPE -CloudDriver <CloudDriver> -StartOSDCloudGUI
    Runs Edit-OSDCloudWinPE 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(PositionalBinding = $false)]
    param (
        [ValidateSet('*','Dell','HP','IntelNet','LenovoDock','Surface','Nutanix','USB','VMware','WiFi')]
        [System.String[]]
        #WinPE Driver: Download and install in WinPE drivers from Dell,HP,IntelNet,LenovoDock,Nutanix,Surface,USB,VMware,WiFi
        $CloudDriver,

        [System.Management.Automation.SwitchParameter]
        #WinPE Startup: Modifies Startnet.cmd to execute Start-OSDCloudGUI
        $StartOSDCloudGUI,

        [Alias('HardwareID')]
        [System.String[]]
        #WinPE Driver: HardwareID of the Driver to add to WinPE
        $DriverHWID,

        [System.String[]]
        #WinPE Driver: Path to additional Drivers you want to add to WinPE
        $DriverPath,

        [System.String[]]
        #PowerShell: Copies named PowerShell Modules from the running OS to WinPE
        #This is useful for adding Modules that are customized or not on PowerShell Gallery
        $PSModuleCopy,

        [Alias('Modules')]
        [System.String[]]
        #PowerShell: Installs named PowerShell Modules from PowerShell Gallery to WinPE
        $PSModuleInstall,

        [System.String]
        #WinPE Startup: Modifies Startnet.cmd to execute the specified string
        $Startnet,

        [System.String]
        #WinPE Startup: Modifies Startnet.cmd to execute Start-OSDCloud with the specified string parameters
        $StartOSDCloud,

        [System.String]
        #WinPE Startup: Modifies Startnet.cmd to execute Start-OSDPad with the specified string
        $StartOSDPad,

        [System.String]
        #WinPE Startup: Modifies Startnet.cmd to execute the specified string before OSDCloud
        $StartPSCommand,

        [Alias('WebPSScript','StartWebScript','StartCloudScript')]
        [System.String]
        #WinPE Startup: Modifies Startnet.cmd to execute the specified string before OSDCloud
        $StartURL,

        [System.Management.Automation.SwitchParameter]
        #After WinPE has been updated, the contents of the OSDCloud Workspace will be updated on any OSDCloud USB Drives
        $UpdateUSB,

        [ValidateScript({
            if (!($_ | Test-Path)) {
                throw 'Wallpaper JPG file does not exist'
            }
            if (!($_ | Test-Path -PathType Leaf)) {
                throw 'Wallpaper JPG must be a file'
            }
            if ($_ -notmatch "(\.jpg)") {
                throw 'Wallpaper must be a JPG file'
            }
            return $true
        })]
        [System.IO.FileInfo]
        #Sets the specified Wallpaper JPG file as the WinPE Background
        $Wallpaper,

        [System.Management.Automation.SwitchParameter]
        #Uses the default OSDCloud Wallpaper
        $UseDefaultWallpaper,

        [System.String]
        #Sets the custom Brand for OSDCloudGUI
        $Brand = 'OSDCloud',

        [System.String]
        #Directory for the OSDCloudWorkspace which contains Media directory
        #This is optional as the OSDCloudWorkspace is returned by Get-OSDCloudWorkspace automatically
        $WorkspacePath,

        [Switch]
        #Will leverage WirelessConnect.EXE instead of the Commandline Tools to connect to WiFi
        $WirelessConnect,

        [ValidateScript( {
            if (Test-Path -Path $_) {
                $true
            } else {
                throw "$_ doesn't exists"
            }
            if ($_ -notmatch "\.xml$") {
                throw "$_ isn't xml file"
            }
            if (!(([xml](Get-Content $_ -Raw)).WLANProfile.Name) -or (([xml](Get-Content $_ -Raw)).WLANProfile.MSM.security.sharedKey.protected) -ne "false") {
                throw "$_ isn't valid Wi-Fi XML profile (is the password correctly in plaintext?). Use command like this, to create it: netsh wlan export profile name=`"MyWifiSSID`" key=clear folder=C:\Wifi"
            }
        })]
        [System.IO.FileInfo]
        #Imports and uses a WiFi Profile to connect to WiFi
        $WifiProfile,

        [System.Management.Automation.SwitchParameter]
        #Adds 7Zip to Boot Image
        $Add7Zip
    )
    #=================================================
    # Start the Clock
    #=================================================
    $WinpeStartTime = Get-Date
    #=================================================
    # 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
    Block-NoCurl
    #=================================================
    # Get-OSDCloudTemplate
    #=================================================
    if (-NOT (Get-OSDCloudTemplate)) {
        Write-Warning "Setting up a new OSDCloudTemplate"
        New-OSDCloudTemplate -Verbose
    }

    $OSDCloudTemplate = Get-OSDCloudTemplate
    if (-NOT ($OSDCloudTemplate)) {
        Write-Warning "Something bad happened. I have to go"
        Break
    }
    #=================================================
    # Set WorkspacePath
    #=================================================
    if ($PSBoundParameters.ContainsKey('WorkspacePath')) {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Setting Workspace Path"
        Set-OSDCloudWorkspace -WorkspacePath $WorkspacePath -ErrorAction Stop | Out-Null
    }
    $WorkspacePath = Get-OSDCloudWorkspace
    #=================================================
    # Setup Workspace
    #=================================================
    if (-NOT ($WorkspacePath)) {
        Write-Warning "You need to provide a path to your Workspace with one of the following examples"
        Write-Warning "Set-OSDCloudWorkspace -WorkspacePath C:\OSDCloud"
        Write-Warning "Edit-OSDCloudWinPE -WorkspacePath C:\OSDCloud"
        Break
    }

    if (-NOT (Test-Path $WorkspacePath)) {
        New-OSDCloudWorkspace -WorkspacePath $WorkspacePath -Verbose -ErrorAction Stop
    }

    if (-NOT (Test-Path "$WorkspacePath\Media")) {
        New-OSDCloudWorkspace -WorkspacePath $WorkspacePath -Verbose -ErrorAction Stop
    }

    if (-NOT (Test-Path "$WorkspacePath\Media\sources\boot.wim")) {
        Write-Warning "Nothing is going well for you today my friend"
        Break
    }
    #=================================================
    # Remove Old Autopilot Content
    #=================================================
    if (Test-Path "$(Get-OSDCloudTemplate)\Autopilot") {
        Write-Warning "Move all your Autopilot Profiles to $(Get-OSDCloudTemplate)\Config\AutopilotJSON"
        Write-Warning "You will be unable to create or update an OSDCloud Workspace until $(Get-OSDCloudTemplate)\Autopilot is manually removed"
        Break
    }
    if (Test-Path "$WorkspacePath\Autopilot") {
        Write-Warning "Move all your Autopilot Profiles to $WorkspacePath\Config\AutopilotJSON"
        Write-Warning "You will be unable to create or update an OSDCloud Workspace until $WorkspacePath\Autopilot is manually removed"
        Break
    }
    #=================================================
    # Mount-MyWindowsImage
    #=================================================
    Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Mounting $WorkspacePath\Media\Sources\boot.wim"
    $MountMyWindowsImage = Mount-MyWindowsImage -ImagePath "$WorkspacePath\Media\Sources\boot.wim"
    $MountPath = $MountMyWindowsImage.Path
    #=================================================
    # Robocopy Config
    #=================================================
    if (Test-Path "$WorkspacePath\Config") {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Copying $WorkspacePath\Config to X:\OSDCloud\Config"
        robocopy "$WorkspacePath\Config" "$MountPath\OSDCloud\Config" *.* /mir /ndl /njh /njs /b /np
    }
    #=================================================
    # Robocopy ODT Config
    #=================================================
    if (Test-Path "$WorkspacePath\ODT") {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Copying $WorkspacePath\ODT to X:\OSDCloud\ODT"
        robocopy "$WorkspacePath\ODT" "$MountPath\OSDCloud\ODT" *.xml /mir /ndl /njh /njs /b /np
        robocopy "$WorkspacePath\ODT" "$MountPath\OSDCloud\ODT" setup.exe /mir /ndl /njh /njs /b /np
    }
    #region DriverHWID
    if ($DriverHWID) {
        $AddWindowsDriverPath = Join-Path $env:TEMP (Get-Random)
        foreach ($Item in $DriverHWID) {
            Save-MsUpCatDriver -HardwareID $Item -DestinationDirectory $AddWindowsDriverPath
        }
        try {
            Add-WindowsDriver -Path "$MountPath" -Driver $AddWindowsDriverPath -Recurse -ForceUnsigned -Verbose
        }
        catch {
            Write-Warning "Unable to find a driver for $Item"
        }
    }
    #endregion

    #region CloudDriver
    if ($CloudDriver) {
        foreach ($Driver in $CloudDriver) {
            Write-Verbose "Downloading $Driver Driver Pack"
            $AddWindowsDriverPath = Save-WinPECloudDriver -CloudDriver $Driver -Path (Join-Path $env:TEMP (Get-Random))
            Write-Verbose "Adding $AddWindowsDriverPath to WinPE Drivers mounted at $MountPath"
            Add-WindowsDriver -Path "$MountPath" -Driver "$AddWindowsDriverPath" -Recurse -ForceUnsigned -Verbose
        }
        $null = Save-WindowsImage -Path $MountPath
    }
    #endregion

    #region DriverPath
    foreach ($AddWindowsDriverPath in $DriverPath) {
        Write-Verbose "Adding $AddWindowsDriverPath to WinPE Drivers mounted at $MountPath"
        Add-WindowsDriver -Path "$MountPath" -Driver "$AddWindowsDriverPath" -Recurse -ForceUnsigned -Verbose
    }
    #endregion

    #region WifiProfile
    if ($WifiProfile) {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Adding WiFi Profile $WifiProfile"
        Copy-Item -Path $WifiProfile -Destination "$env:TEMP\WiFiProfile.xml" -Force | Out-Null
        robocopy "$env:TEMP" "$MountPath\OSDCloud\Config\Scripts" WiFiProfile.xml /ndl /njh /njs /b /np /r:0 /w:0
    }
    #endregion

    #region Default Startnet.cmd
    $OSDVersion = (Get-Module -Name OSD -ListAvailable | Sort-Object Version -Descending | Select-Object -First 1).Version
    if ($WirelessConnect){
        $InitializeOSDCloudStartnetCommand = "Initialize-OSDCloudStartnet -WirelessConnect"
    }
    elseif ($WifiProfile) {
        $InitializeOSDCloudStartnetCommand = "Initialize-OSDCloudStartnet -WifiProfile"
    }
    else {
        $InitializeOSDCloudStartnetCommand = "Initialize-OSDCloudStartnet"
    }

$StartnetCMD = @"
@ECHO OFF
wpeinit
cd\
title OSD $OSDVersion
PowerShell -Nol -C $InitializeOSDCloudStartnetCommand
PowerShell -Nol -C Initialize-OSDCloudStartnetUpdate
"@

    Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Startnet.cmd: Reset to defaults"
    $StartnetCMD
    $StartnetCMD | Out-File -FilePath "$MountPath\Windows\System32\Startnet.cmd" -Encoding ascii -Width 2000 -Force
    #endregion

    #region StartPSCommand
    if ($StartPSCommand) {
        Write-Warning "The StartPSCommand parameter is adding your Cloud PowerShell script to Startnet.cmd"
        Write-Warning "This must be set every time you run Edit-OSDCloudWinPE or it will revert back to defaults"

        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Startnet.cmd: start /wait PowerShell -NoL -C `"$StartPSCommand`""
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value "start /wait PowerShell -NoL -C `"$StartPSCommand`"" -Force
    }
    #endregion

    #region Startup Parameter: StartURL
    if ($StartURL) {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Startnet.cmd: Launch URL on WinPE Startup"

        Write-Host '@ECHO OFF'
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value '@ECHO OFF' -Force

        Write-Host '@ECHO OFF'
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value 'ECHO Invoke-WebPSScript' -Force

        Write-Host '@ECHO ON'
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value '@ECHO ON' -Force

        Write-Host "start /wait PowerShell -NoL -C Invoke-WebPSScript '$StartURL'"
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value "start /wait PowerShell -NoL -C Invoke-WebPSScript '$StartURL'" -Force
    }
    #endregion

    #region Startup Parameter: StartOSDCloud
    if ($StartOSDCloud) {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Startnet.cmd: Launch Start-OSDCloud on WinPE Startup"

        Write-Host '@ECHO OFF'
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value '@ECHO OFF' -Force

        Write-Host 'ECHO Start-OSDCloud'
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value 'ECHO Start-OSDCloud' -Force

        Write-Host "start /wait PowerShell -NoL -C Start-OSDCloud $StartOSDCloud"
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value "start /wait PowerShell -NoL -C Start-OSDCloud $StartOSDCloud"

        Write-Host '@ECHO ON'
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value '@ECHO ON' -Force
    }
    #endregion

    #region Startup Parameter: StartOSDCloudGUI
    if ($StartOSDCloudGUI) {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Startnet.cmd: Launch Start-OSDCloudGUI on WinPE Startup"

        Write-Host '@ECHO OFF'
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value '@ECHO OFF' -Force

        Write-Host 'ECHO Start-OSDCloudGUI'
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value 'ECHO Start-OSDCloudGUI' -Force

        Write-Host "start /wait PowerShell -NoL -W Mi -C Start-OSDCloudGUI -Brand '$Brand'"
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value "start /wait PowerShell -NoL -W Mi -C Start-OSDCloudGUI -Brand '$Brand'"

        Write-Host '@ECHO ON'
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value '@ECHO ON' -Force
    }
    #endregion

    #region Startup Parameter: StartOSDPad
    if ($StartOSDPad) {
        Write-Warning "The StartOSDPad parameter is adding OSDPad to Startnet.cmd"
        Write-Warning "This must be set every time you run Edit-OSDCloudWinPE or it will revert back to defaults"

        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Startnet.cmd: start /wait PowerShell -NoL -C OSDPad $StartOSDPad"
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value '@ECHO OFF' -Force
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value 'ECHO OSDPad' -Force
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value '@ECHO ON' -Force
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value "start /wait PowerShell -NoL -C OSDPad $StartOSDPad"
    }
    #endregion

    #region Startup Parameter: Startnet
    if ($Startnet) {
        Write-Warning "The Startnet string is added to Startnet.cmd"
        Write-Warning "This must be set every time you run Edit-OSDCloudWinPE or it will revert back to defaults"

        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value $Startnet -Force
    }
    #endregion

    #region No Startup Parameter
    if ($StartOSDCloud -or $StartOSDCloudGUI -or $StartURL -or $StartOSDPad -or $Startnet) {
        #Do Nothing
    }
    else {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Startnet.cmd: Start PowerShell in new Window"
        Write-Host '@ECHO OFF'
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value '@ECHO OFF' -Force
        Write-Host 'start PowerShell -NoL'
        Add-Content -Path "$MountPath\Windows\System32\Startnet.cmd" -Value 'start PowerShell -NoL' -Force
    }
    #endregion

    #region Wallpaper
    if ($UseDefaultWallpaper) {
        $Wallpaper = Join-Path (Get-Module -Name OSD -ListAvailable | Sort-Object Version -Descending | Select-Object -First 1).ModuleBase "Resources\Images\OSDCloud.jpg"
    }
    if ($Wallpaper) {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Adding Wallpaper $Wallpaper"
        Copy-Item -Path $Wallpaper -Destination "$env:TEMP\winpe.jpg" -Force | Out-Null
        Copy-Item -Path $Wallpaper -Destination "$env:TEMP\winre.jpg" -Force | Out-Null
        robocopy "$env:TEMP" "$MountPath\Windows\System32" winpe.jpg /ndl /njh /njs /b /np /r:0 /w:0
        robocopy "$env:TEMP" "$MountPath\Windows\System32" winre.jpg /ndl /njh /njs /b /np /r:0 /w:0
    }
    #endregion

    #region Add7Zip
    if ($PSBoundParameters.ContainsKey('Add7Zip')) {
        Write-Host -ForegroundColor Yellow "[$(Get-Date -format s)] Adding 7zip (7za.exe) to WinPE"
        Add-7Zip2BootImage
    }
    #endregion

    #region CMTrace
    #Copy CMTrace from WorkSpace to WinPE - Gary Blok 25.1.22
    if (Test-Path "$WorkspacePath\cmtrace.exe") {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Copy CMTrace from WorkSpace to WinPE"
        Copy-Item -Path "$WorkspacePath\cmtrace.exe" -Destination "$env:TEMP\cmtrace.exe" -Force | Out-Null
        robocopy "$env:TEMP" "$MountPath\Windows\System32" cmtrace.exe /ndl /njh /njs /b /np /r:0 /w:0
    }
    #endregion
    #region OSD PowerShell Module
    Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Saving OSD Module to X:\Program Files\WindowsPowerShell\Modules"
    Save-Module -Name OSD -Path "$MountPath\Program Files\WindowsPowerShell\Modules" -Force
    #endregion

    #region Azure PowerShell Modules
    if ($AddAzure.IsPresent) {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Saving Azure Modules to X:\Program Files\WindowsPowerShell\Modules"
        Save-Module -Name Az.Accounts -Path "$MountPath\Program Files\WindowsPowerShell\Modules" -Force
        Save-Module -Name Az.Storage -Path "$MountPath\Program Files\WindowsPowerShell\Modules" -Force
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Saving AzCopy to X:\Windows"
        $AzCopy = Save-WebFile -SourceUrl (Invoke-WebRequest -UseBasicParsing 'https://aka.ms/downloadazcopy-v10-windows' -MaximumRedirection 0 -ErrorAction SilentlyContinue).headers.location
        if ($AzCopy) {
            Expand-Archive -Path $AzCopy.FullName -DestinationPath $env:windir\Temp\AzCopy -Force
            Get-ChildItem -Path $env:windir\Temp\AzCopy -Recurse -Include azcopy.exe | foreach {Copy-Item $_.FullName -Destination "$MountPath\Windows\azcopy.exe" -Force -ErrorAction SilentlyContinue}
        }
    }
    #endregion

    #region AWS PowerShell Modules
    if ($AddAws.IsPresent) {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Saving AWS Modules to X:\Program Files\WindowsPowerShell\Modules"
        Save-Module -Name AWS.Tools.Common "$MountPath\Program Files\WindowsPowerShell\Modules" -Force
        Save-Module -Name AWS.Tools.S3 -Path "$MountPath\Program Files\WindowsPowerShell\Modules" -Force
    }
    #endregion

    #region PSModuleInstall
    foreach ($Module in $PSModuleInstall) {
        if ($Module -eq 'DellBiosProvider') {
            if (Test-Path "$env:SystemRoot\System32\msvcp140.dll") {
                Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Copying $env:SystemRoot\System32\msvcp140.dll to WinPE"
                Copy-Item -Path "$env:SystemRoot\System32\msvcp140.dll" -Destination "$MountPath\Windows\System32\msvcp140.dll" -Force | Out-Null
            }
            if (Test-Path "$env:SystemRoot\System32\vcruntime140.dll") {
                Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Copying $env:SystemRoot\System32\vcruntime140.dll to WinPE"
                Copy-Item -Path "$env:SystemRoot\System32\vcruntime140.dll" -Destination "$MountPath\Windows\System32\vcruntime140.dll" -Force | Out-Null
            }
            if (Test-Path "$env:SystemRoot\System32\vcruntime140_1.dll") {
                Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Copying $env:SystemRoot\System32\vcruntime140_1.dll to WinPE"
                Copy-Item -Path "$env:SystemRoot\System32\vcruntime140_1.dll" -Destination "$MountPath\Windows\System32\vcruntime140_1.dll" -Force | Out-Null
            }
        }

        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Saving $Module to $MountPath\Program Files\WindowsPowerShell\Modules"
        if ($Module -eq 'HPCMSL'){
            Save-Module -Name $Module -Path "$MountPath\Program Files\WindowsPowerShell\Modules" -Force -AcceptLicense
        }
        else {
            Save-Module -Name $Module -Path "$MountPath\Program Files\WindowsPowerShell\Modules" -Force
        }
    }
    #endregion

    #region PSModuleCopy
    foreach ($Module in $PSModuleCopy) {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Copy-PSModuleToWindowsImage -Name $Module -Path $MountPath"
        Copy-PSModuleToWindowsImage -Name $Module -Path $MountPath
    }
    #endregion

    #region Dismount-MyWindowsImage
    $MountMyWindowsImage | Dismount-MyWindowsImage -Save
    #endregion

    #region Create OSDCloud ISOs
    Write-Host -ForegroundColor DarkGray "========================================================================="
    Write-Host -ForegroundColor Cyan "[$(Get-Date -format s)] Create OSDCloud Workspace ISOs"
    New-OSDCloudISO
    #endregion

    #region UpdateUSB
    if ($UpdateUSB) {
        $WinpeVolumes = (Get-USBVolume | Where-Object {$_.FileSystemLabel -eq 'WinPE'}).DriveLetter

        if ($WinpeVolumes) {
            foreach ($WinpeVolume in $WinpeVolumes) {
                Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] Copying $WorkspacePath\Media to $($WinpeVolume):\"
                robocopy "$WorkspacePath\Media" "$($WinpeVolume):\" *.* /e /ndl /np /njh /njs /b /r:0 /w:0 /zb /xd "$RECYCLE.BIN" "System Volume Information"
            }
        }
    }
    #endregion

    #region Complete
    $WinpeEndTime = Get-Date
    $WinpeTimeSpan = New-TimeSpan -Start $WinpeStartTime -End $WinpeEndTime
    Write-Host -ForegroundColor DarkGray "================================================"
    Write-Host -ForegroundColor Yellow "[$(Get-Date -format s)] $($MyInvocation.MyCommand.Name) " -NoNewline
    Write-Host -ForegroundColor Cyan "Completed in $($WinpeTimeSpan.ToString("mm' minutes 'ss' seconds'"))"
    #endregion
}