FunctionsToExport/Function_Set-WindowsImageVHD.ps1


Function Set-WindowsImageVHD {

    [CmdletBinding()]
    Param(
        [Parameter(ValueFromPipeline)]
        [ValidateScript({
                $Item = $_ | Get-Item -ErrorAction SilentlyContinue
                if (-not $Item) { throw 'Item ("{0}") does not exist' -f $_ }
                elseif ($Item.Attributes -notmatch "Directory") { throw 'Item ("{0}") is not a directory' -f $_ }
                $true
            }
        )]
        [string]$Location = $PWD,        
        [string]$Name = "WindowsImage",
        [string[]]$DisableWindowsOptionalFeature,
        [string[]]$RemoveAppxProvisionedPackage,
        [string[]]$RemoveWindowsCapability,
        [string[]]$AddWindowsPackage,
        [string[]]$AddWindowsDriver,
        [string[]]$MergeFolder,
        [string[]]$AddAppxProvisionedPackage,
        [string]$UnattendPath,
        [string]$StartBinPath
    )
   
    $PSDefaultParameterValues['*-VHDChain:Location'] = $Location
    $PSDefaultParameterValues['*-VHDChain:Name'] = $Name
    
    $MountPath = Add-VHDChain | Mount-VHDChain

    if ($DisableWindowsOptionalFeature) {
        # Disable-WindowsOptionalFeature
        # FeatureName
        # State: Enabled|Disabled
        'Disable-WindowsOptionalFeature' | Write-Verbose
        Get-WindowsOptionalFeature -Path $MountPath | Where-Object { $_.State -eq 'Enabled' -and $DisableWindowsOptionalFeature -contains $_.FeatureName } | ForEach-Object {
            'Disable-WindowsOptionalFeature FeatureName: "{0}"' -f $_.FeatureName | Write-Verbose
            $_ | ConvertTo-Json | Write-Verbose
            $_ | Disable-WindowsOptionalFeature | ConvertTo-Json | Write-Verbose
        }
    }
    
    if ($RemoveWindowsCapability) {
        # Remove-WindowsCapability
        # Name
        # State: Installed|NotPresent
        'Remove-WindowsCapability' | Write-Verbose
        Get-WindowsCapability -Path $MountPath | Where-Object { $_.State -eq 'Installed' -and $RemoveWindowsCapability -contains $_.Name } | ForEach-Object {
            'Remove-WindowsCapability Name: "{0}"' -f $_.Name | Write-Verbose
            $_ | ConvertTo-Json | Write-Verbose
            $_ | Remove-WindowsCapability | ConvertTo-Json | Write-Verbose
        }
    }

    if ($RemoveAppxProvisionedPackage) {
        # Remove-AppxProvisionedPackage
        # DisplayName / PackageName
        # no State
        'Remove-AppxProvisionedPackage' | Write-Verbose
        $ExceptionRegex = @(
            'Microsoft.DesktopAppInstaller'    
            'Microsoft.SecHealthUI'
            'Microsoft.VCLibs' 
            'Microsoft.UI.Xaml'
        ) -join "|"
        Get-AppxProvisionedPackage -Path $MountPath | Where-Object { ($RemoveAppxProvisionedPackage -contains $_.DisplayName -or $RemoveAppxProvisionedPackage -contains $_.PackageName) -and $_.PackageName -notmatch $ExceptionRegex } | ForEach-Object {
            'Remove-AppxProvisionedPackage PackageName:"{0}"' -f $_.PackageName | Write-Verbose
            $_ | ConvertTo-Json | Write-Verbose
            $_ | Remove-AppxProvisionedPackage | ConvertTo-Json | Write-Verbose
        }
    }    

    if ($AddWindowsPackage) {
        'Add-WindowsPackage' | Write-Verbose
        $AddWindowsPackage | ForEach-Object {
            $Splat = @{
                Path        = $MountPath 
                PackagePath = $_
            }
            $Splat | ConvertTo-Json | Write-Verbose
            Add-WindowsPackage @Splat | ConvertTo-Json | Write-Verbose
        }
    }
        
    
    if ($AddWindowsDriver) {
        'Add-WindowsDriver' | Write-Verbose
        $AddWindowsDriver | ForEach-Object {
            $Splat = @{
                Path    = $MountPath
                Driver  = $_
                Recurse = $true
            }
            $Splat | ConvertTo-Json | Write-Verbose
            Add-WindowsDriver @Splat | ConvertTo-Json | Write-Verbose
        } 
    }
        
    if ($MergeFolder) {
        'Mergefolder' | Write-Verbose
        $MergeFolder | ForEach-Object {
            $Splat = @{
                Path        = $_ + '\*'
                Destination = $MountPath
                Recurse     = $true
            }
            $Splat | ConvertTo-Json | Write-Verbose
            Copy-Item @Splat | ConvertTo-Json | Write-Verbose
        }    
    }
                    
    if ($AddAppxProvisionedPackage) {
        'Add-AppxProvisionedPackage' | Write-Verbose
        $AddAppxProvisionedPackage | ForEach-Object {
            $Splat = @{
                Path        = $MountPath
                PackagePath = $_
                Verbose     = $true
                SkipLicense = $true
            }
            $Splat | ConvertTo-Json | Write-Verbose
            Add-AppxProvisionedPackage @Splat | ConvertTo-Json | Write-Verbose
        }
    }

    if ($StartBinPath) {
        'Copy start.bin' | Write-Verbose
        $Splat = @{
            Type    = 'Directory'
            Path    = Join-Path $MountPath 'Users\Default\AppData\Local\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState'
            Force   = $true
            Verbose = $true
        }
        New-Item @Splat
        $Splat = @{
            Path        = $StartBinPath
            Destination = Join-Path $MountPath 'Users\Default\AppData\Local\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState\start.bin'
            Verbose     = $true
        }
        Copy-Item @Splat | ConvertTo-Json | Write-Verbose
    }        

    if ($UnattendPath) {
        'Copy unattend.xml' | Write-Verbose
        $Splat = @{
            Path        = $UnattendPath
            Destination = Join-Path $MountPath 'unattend.xml'
            Verbose     = $true
        }
        Copy-Item @Splat | ConvertTo-Json | Write-Verbose
    }
    
    Dismount-VHDChain

}