|
#Requires -Version 5 |
|
#Requires -RunAsAdministrator |
|
|
|
Param( |
|
[switch] $PreRelease |
|
) |
|
|
|
|
|
Function Enable-WindowsSandbox { |
|
if (!(Get-Command 'WindowsSandbox.exe' -ErrorAction 'SilentlyContinue')) { |
|
try { |
|
Enable-WindowsOptionalFeature -FeatureName 'Containers-DisposableClientVM' -All -Online |
|
Write-Output 'Windows must be restarted to finish enabling Windows Sandbox' |
|
} catch { |
|
Write-Error 'Windows Sandbox cannot be enabled on your machine. Please ensure your system meets the prerequisites shown at https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-sandbox/windows-sandbox-overview.' |
|
exit 1 |
|
} |
|
} else { |
|
Write-Output 'WindowsSandbox is already installed' |
|
} |
|
} |
|
|
|
Function Close-WindowsSandbox { |
|
$_Sandbox = Get-Process 'WindowsSandboxClient' -ErrorAction SilentlyContinue |
|
if ($_Sandbox) { |
|
Write-Output 'Windows Sandbox must be closed to modify the base image' |
|
Write-Output 'Closing Windows Sandbox' |
|
$_Sandbox | Stop-Process |
|
Start-Sleep -Seconds 5 |
|
} else { |
|
Write-Output 'Windows Sandbox is not running. Installation will proceed' |
|
} |
|
} |
|
|
|
Function Set-CMServiceStatus() { |
|
Param( |
|
[boolean] $Enabled |
|
) |
|
$_ContainerManagerService = Get-Service -Name 'CmService' |
|
switch ($Enabled) { |
|
$true { |
|
if ($_ContainerManagerService.Status -eq 'Stopped') { |
|
Write-Output 'Starting Container Manager Service' |
|
$_ContainerManagerService | Start-Service |
|
} else { |
|
Write-Output 'Container Manager Service is running' |
|
} |
|
} |
|
$false { |
|
if ($_ContainerManagerService.Status -ne 'Stopped') { |
|
Write-Output 'Stopping Container Manager Service' |
|
$_ContainerManagerService | Stop-Service -Force |
|
} else { |
|
Write-Output 'Container Manager Service is stopped' |
|
} |
|
} |
|
default { |
|
Write-Error "Unknown parameter value - Set-CMServiceStatus $Enabled" |
|
exit 1 |
|
} |
|
} |
|
} |
|
|
|
Function Mount-SandboxImage { |
|
Write-Output 'Attempting to find the virtual hard disk' |
|
$script:BaseImageFolder = Resolve-Path("$ENV:PROGRAMDATA\Microsoft\Windows\Containers\BaseImages") -ErrorAction 'SilentlyContinue' |
|
if ($null -eq $BaseImageFolder) { |
|
Write-Error 'Could not locate BaseImages Folder' |
|
exit 1 |
|
} |
|
$script:GUIDFolder = @((Get-ChildItem $BaseImageFolder -Directory).Where({ $_.Name -match '[a-z0-9]{8}(-[a-z0-9]{4}){3}-[a-z0-9]{12}' }))[0] |
|
if ($null -eq $GUIDFolder) { |
|
Write-Error 'Could not locate Sandbox GUID Folder' |
|
exit 1 |
|
} |
|
$script:BaseLayerVHDX = @((Get-ChildItem $GUIDFolder.FullName -File).Where({ $_.FullName -cmatch 'BaseLayer\.vhdx$' }))[0] |
|
if ($null -eq $BaseLayerVHDX) { |
|
Write-Error 'Could not locate Sandbox Virtual Hard Disk' |
|
exit 1 |
|
} |
|
Write-Output 'Virtual hard disk found. Attempting to mount the disk' |
|
Mount-VHD $BaseLayerVHDX.FullName |
|
$script:VHDXDriveLetter = (Get-VHD $BaseLayerVHDX.FullName | Get-Disk | Get-Partition | Get-Volume).DriveLetter |
|
Write-Output "Virtual hard disk mounted at $VHDXDriveLetter`:\" |
|
} |
|
|
|
Function Dismount-SandboxImage { |
|
Write-Output 'Dismounting the virtual hard disk' |
|
Dismount-VHD $BaseLayerVHDX.FullName |
|
} |
|
|
|
Function Mount-SandboxRegistry { |
|
$_NTUserDatFile = Resolve-Path "$VHDXDriveLetter`:\Files\Users\WDAGUtilityAccount\ntuser.dat" |
|
if ($null -eq $_NTUserDatFile) { |
|
Write-Error 'Unable to locate sandbox user registry' |
|
exit 1 |
|
} |
|
Write-Output 'Loading Sandbox User Registry' |
|
$_GUID = (New-Guid).ToString() |
|
Write-Output "Assigning Temporary User GUID - $_GUID" |
|
$script:SandboxRegKey = "HKEY_Users\$_GUID" |
|
REG LOAD $SandboxRegKey $_NTUserDatFile.Path |
|
Write-Output 'Sandbox User Registry Loaded!' |
|
} |
|
|
|
Function Dismount-SandboxRegistry { |
|
Write-Output 'Unloading Sandbox User Registry' |
|
$null = REG UNLOAD $SandboxRegKey |
|
} |
|
|
|
Function Publish-BinaryFiles { |
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 |
|
$WebClient = New-Object System.Net.WebClient |
|
$_WindowsPath = Resolve-Path "$VHDXDriveLetter`:\Files\Windows" |
|
Write-Output 'Fetching Latest Winget CLI Release' |
|
$_LatestUrl = ((Invoke-WebRequest 'https://api.github.com/repos/microsoft/winget-cli/releases' -UseBasicParsing | ConvertFrom-Json).Where({ $_.prerelease -eq $PreRelease }) | Select-Object -First 1).assets.Where({ $_.name -match '^Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle$' }).browser_download_url |
|
Write-Output 'Downloading Winget to Sandbox' |
|
$WebClient.DownloadFile($_LatestUrl, $(Join-Path -Path $_WindowsPath -ChildPath 'Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle')) |
|
Write-Output 'Downloading VCLibs to Sandbox' |
|
$WebClient.DownloadFile('https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx', $(Join-Path -Path $_WindowsPath -ChildPath 'Microsoft.VCLibs.x64.14.00.Desktop.appx')) |
|
Write-Output 'Fetching Microsoft UI Nuget Package' |
|
$_UILibsZipPath = Join-Path -Path $env:TEMP -ChildPath 'Microsoft.UI.Xaml.2.7.zip' |
|
$WebClient.DownloadFile('https://www.nuget.org/api/v2/package/Microsoft.UI.Xaml/2.7.0', $_UILibsZipPath) |
|
Write-Output 'Extracting Microsoft UI Appx to Sandbox' |
|
Expand-Archive -Path $_UILibsZipPath -DestinationPath $(Join-Path -Path $env:TEMP -ChildPath 'Microsoft.UI.Xaml.2.7') -Force |
|
$_UILibsAppxPath = Join-Path -Path $env:TEMP -ChildPath 'Microsoft.UI.Xaml.2.7\tools\AppX\x64\Release\Microsoft.UI.Xaml.2.7.appx' |
|
Copy-Item -Path $_UILibsAppxPath -Destination $(Join-Path -Path $_WindowsPath -ChildPath 'Microsoft.UI.Xaml.2.7.appx') |
|
|
|
Write-Output 'Writing registry key to install Winget' |
|
$_RunKey = Get-Item Registry::$SandboxRegKey\SOFTWARE\Microsoft\Windows\CurrentVersion\Run -ErrorAction 'SilentlyContinue' |
|
if ($null -eq $_RunKey) { |
|
$_RunKey = New-Item Registry::$SandboxRegKey\SOFTWARE\Microsoft\Windows\CurrentVersion\Run -Force |
|
} |
|
$null = New-ItemProperty -Path $_RunKey.PSPath -Name 'InstallWingetAndDependencies' -Value 'powershell.exe "Add-AppxPackage C:\Windows\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle -DependencyPath "C:\Windows\Microsoft.UI.Xaml.2.7.appx","C:\Windows\Microsoft.VCLibs.x64.14.00.Desktop.appx""' -PropertyType 'String' -Force |
|
$_RunKey.Close() |
|
|
|
Write-Output 'Writing registry key to enable powershell script execution' |
|
$_PowershellKey = Get-Item Registry::$SandboxRegKey\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell -ErrorAction 'SilentlyContinue' |
|
if ($null -eq $_PowershellKey) { |
|
$_PowershellKey = New-Item Registry::$SandboxRegKey\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell -Force |
|
} |
|
$null = New-ItemProperty -Path $_PowershellKey.PSPath -Name 'ExecutionPolicy' -Value 'RemoteSigned' -PropertyType 'String' -Force |
|
$null = New-ItemProperty -Path $_PowershellKey.PSPath -Name 'Path' -Value 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe' -PropertyType 'String' -Force |
|
$_PowershellKey.Close() |
|
[GC]::Collect() |
|
Write-Output 'Setup complete' |
|
} |
|
|
|
Enable-WindowsSandbox |
|
Close-WindowsSandbox |
|
Set-CMServiceStatus -Enabled $false |
|
Mount-SandboxImage |
|
Mount-SandboxRegistry |
|
Publish-BinaryFiles |
|
Dismount-SandboxRegistry |
|
Dismount-SandboxImage |
|
Set-CMServiceStatus -Enabled $true |
Yes that worked, actually running into another issues, i get an error when running the script that it cant find the sandbox virtual hard drive?
"WindowsSandbox is already installed
Windows Sandbox is not running. Installation will proceed
Container Manager Service is stopped
Attempting to find the virtual hard disk
Mount-SandboxImage : Could not locate Sandbox Virtual Hard Disk
At C:\ProgramData\Microsoft\Windows\Containers\WingetSandbox.ps1:152 char:1