Test-CorrelationInSandbox.ps1 (12231B)
1 # Started by copying from: 2 # https://github.com/microsoft/winget-pkgs/blob/c393e50b66448cc25a5cd27aa754d37677f42ce2/Tools/SandboxTest.ps1 3 4 Param( 5 [Parameter(Position = 0, HelpMessage = "The package identifiers to test.")] 6 [String[]] $PackageIdentifiers, 7 [Parameter(Position = 1, HelpMessage = "The source name that the package identifiers are from.")] 8 [String] $Source, 9 [Parameter(HelpMessage = "The directory where the correlation program is located.")] 10 [String] $ExePath, 11 [Parameter(HelpMessage = "Indicates that the local dev build should be used rather than the published package.")] 12 [Switch] $UseDev, 13 [Parameter(HelpMessage = "The directory where local dev build is located; only the release build works.")] 14 [String] $DevPackagePath, 15 [Parameter(HelpMessage = "The results output path.")] 16 [String] $ResultsPath, 17 [Parameter(HelpMessage = "The path to registry files that should be injected before the test.")] 18 [String] $RegFileDirectory, 19 [Parameter(HelpMessage = "Indicates that the metadata collection process should be run.")] 20 [Switch] $MetadataCollection, 21 [Parameter(HelpMessage = "The path to WinGetUtil.dll.")] 22 [String] $WingetUtilPath, 23 [Parameter(HelpMessage = "Wait for user input before tearing down each sandbox.")] 24 [Switch] $Wait 25 ) 26 27 $ErrorActionPreference = "Stop" 28 29 # Validate that the ExePath points to a reasonable location 30 31 if (-not $ExePath) 32 { 33 $ExePath = Join-Path $PSScriptRoot "InstallAndCheckCorrelation\x64\Release" 34 } 35 36 $ExePath = [System.IO.Path]::GetFullPath($ExePath) 37 38 if (-not (Test-Path (Join-Path $ExePath "InstallAndCheckCorrelation.exe"))) 39 { 40 Write-Error -Category InvalidArgument -Message @" 41 InstallAndCheckCorrelation.exe does not exist in the path $ExePath 42 Either build it, or provide the location using -ExePath 43 "@ 44 } 45 46 # Validate that the local dev manifest exists 47 48 if ($UseDev) 49 { 50 if (-not $DevPackagePath) 51 { 52 $DevPackagePath = Join-Path $PSScriptRoot "..\..\src\AppInstallerCLIPackage\bin\x64\Release\AppX" 53 } 54 55 $DevPackagePath = [System.IO.Path]::GetFullPath($DevPackagePath) 56 57 if ($DevPackagePath.ToLower().Contains("debug")) 58 { 59 Write-Error -Category InvalidArgument -Message @" 60 The Debug dev package does not work for unknown reasons. 61 Use the Release build or figure out how to make debug work and fix the scripts. 62 "@ 63 } 64 65 if (-not (Test-Path (Join-Path $DevPackagePath "AppxManifest.xml"))) 66 { 67 Write-Error -Category InvalidArgument -Message @" 68 AppxManifest.xml does not exist in the path $DevPackagePath 69 Either build the local dev package, or provide the location using -DevPackagePath 70 "@ 71 } 72 } 73 74 # Validate that WinGetUtil.dll exists if metadata collection is requested 75 76 if ($MetadataCollection) 77 { 78 if (-not $WingetUtilPath) 79 { 80 $WingetUtilPath = Join-Path $PSScriptRoot "..\..\src\x64\Debug\WinGetUtil\WinGetUtil.dll" 81 } 82 83 $WingetUtilPath = [System.IO.Path]::GetFullPath($WingetUtilPath) 84 85 if (-not (Test-Path $WingetUtilPath)) 86 { 87 Write-Error -Category InvalidArgument -Message @" 88 WinGetUtil.dll does not exist in the path $WingetUtilPath 89 Either build the binary, or provide the location using -WingetUtilPath 90 "@ 91 } 92 } 93 94 # Check if Windows Sandbox is enabled 95 96 if (-Not (Get-Command 'WindowsSandbox' -ErrorAction SilentlyContinue)) 97 { 98 Write-Error -Category NotInstalled -Message @' 99 Windows Sandbox does not seem to be available. Check the following URL for prerequisites and further details: 100 https://docs.microsoft.com/windows/security/threat-protection/windows-sandbox/windows-sandbox-overview 101 102 You can run the following command in an elevated PowerShell for enabling Windows Sandbox: 103 $ Enable-WindowsOptionalFeature -Online -FeatureName 'Containers-DisposableClientVM' 104 '@ 105 } 106 107 # Close Windows Sandbox 108 109 function Close-WindowsSandbox { 110 $sandbox = Get-Process 'WindowsSandboxClient' -ErrorAction SilentlyContinue 111 if ($sandbox) 112 { 113 Write-Host '--> Closing Windows Sandbox' 114 115 $sandboxServer = Get-Process 'WindowsSandbox' -ErrorAction SilentlyContinue 116 117 $sandbox | Stop-Process 118 $sandbox | Wait-Process -Timeout 120 119 120 # Also wait for the server to close 121 if ($sandboxServer) 122 { 123 try 124 { 125 $sandboxServer | Wait-Process -Timeout 120 126 } 127 catch [System.TimeoutException] 128 { 129 # Force stop the server if it does not automatically stop 130 $sandboxServer | Stop-Process 131 $sandboxServer | Wait-Process -Timeout 120 132 } 133 134 } 135 136 Write-Host 137 } 138 Remove-Variable sandbox 139 } 140 141 Close-WindowsSandbox 142 143 # Create output location for results 144 145 if (-not $ResultsPath) 146 { 147 $ResultsPath = Join-Path ([System.IO.Path]::GetTempPath()) (New-Guid) 148 } 149 150 $ResultsPath = [System.IO.Path]::GetFullPath($ResultsPath) 151 152 if (Test-Path $ResultsPath) 153 { 154 Remove-Item -Recurse $ResultsPath -Force 155 } 156 157 New-Item -ItemType Directory $ResultsPath | Out-Null 158 159 # Initialize Temp Folder 160 161 $tempFolderName = 'CorrelationTestStaging' 162 $tempFolder = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath $tempFolderName 163 164 New-Item $tempFolder -ItemType Directory -ErrorAction SilentlyContinue | Out-Null 165 166 # Set dependencies 167 168 $desktopInSandbox = 'C:\Users\WDAGUtilityAccount\Desktop' 169 170 $apiLatestUrl = 'https://api.github.com/repos/microsoft/winget-cli/releases/latest' 171 172 [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 173 $WebClient = New-Object System.Net.WebClient 174 175 $vcLibsUwp = @{ 176 fileName = 'Microsoft.VCLibs.x64.14.00.Desktop.appx' 177 url = 'https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx' 178 hash = '9BFDE6CFCC530EF073AB4BC9C4817575F63BE1251DD75AAA58CB89299697A569' 179 folderInLocal = Join-Path ${env:ProgramFiles(x86)} "Microsoft SDKs\Windows Kits\10\ExtensionSDKs\Microsoft.VCLibs.Desktop\14.0\Appx\Retail\x64" 180 } 181 182 if ($UseDev) 183 { 184 $dependencies = @($vcLibsUwp) 185 } 186 187 # Clean temp directory 188 189 Get-ChildItem $tempFolder -Recurse -Exclude $dependencies.fileName | Remove-Item -Force -Recurse 190 191 # Download dependencies 192 193 Write-Host '--> Checking dependencies' 194 195 foreach ($dependency in $dependencies) 196 { 197 $dependency.pathInSandbox = Join-Path -Path $desktopInSandbox -ChildPath (Join-Path -Path $tempFolderName -ChildPath $dependency.fileName) 198 199 # First see if the file exists locally to copy instead of downloading 200 if ($dependency.folderInLocal -ne $null) 201 { 202 $dependencyFilePath = Join-Path -Path $dependency.folderInLocal -ChildPath $dependency.fileName 203 if (Test-Path -Path $dependencyFilePath -PathType Leaf) 204 { 205 $dependencyFilePath 206 $tempFolder 207 Copy-Item -Path $dependencyFilePath -Destination $tempFolder -Force 208 continue 209 } 210 } 211 212 # File does not exist locally, we need to download 213 214 $dependency.file = Join-Path -Path $tempFolder -ChildPath $dependency.fileName 215 216 # Only download if the file does not exist, or its hash does not match. 217 if (-Not ((Test-Path -Path $dependency.file -PathType Leaf) -And $dependency.hash -eq $(Get-FileHash $dependency.file).Hash)) 218 { 219 Write-Host @" 220 - Downloading: 221 $($dependency.url) 222 "@ 223 224 try 225 { 226 $WebClient.DownloadFile($dependency.url, $dependency.file) 227 } 228 catch 229 { 230 #Pass the exception as an inner exception 231 throw [System.Net.WebException]::new("Error downloading $($dependency.url).",$_.Exception) 232 } 233 if (-not ($dependency.hash -eq $(Get-FileHash $dependency.file).Hash)) 234 { 235 throw [System.Activities.VersionMismatchException]::new('Dependency hash does not match the downloaded file') 236 } 237 } 238 } 239 240 if ($MetadataCollection) 241 { 242 Copy-Item -Path $WingetUtilPath -Destination $tempFolder -Force 243 } 244 245 # Copy main script 246 247 $mainPs1FileName = 'InSandboxScript.ps1' 248 Copy-Item (Join-Path $PSScriptRoot $mainPs1FileName) (Join-Path $tempFolder $mainPs1FileName) 249 250 foreach ($packageIdentifier in $PackageIdentifiers) 251 { 252 253 # Create temporary location for output 254 $outPath = Join-Path $ResultsPath $packageIdentifier 255 New-Item -ItemType Directory $outPath | Out-Null 256 257 $outPathInSandbox = Join-Path -Path $desktopInSandbox -ChildPath (Split-Path -Path $outPath -Leaf) 258 $system32PathInSandbox = Join-Path -Path $desktopInSandbox -ChildPath "hostSystem32" 259 260 if ($UseDev) 261 { 262 $dependenciesPathsInSandbox = "@('$($vcLibsUwp.pathInSandbox)')" 263 } 264 265 $bootstrapPs1Content = ".\$mainPs1FileName -DesktopAppInstallerDependencyPath @($dependenciesPathsInSandbox) -PackageIdentifier '$packageIdentifier' -SourceName '$Source' -OutputPath '$outPathInSandbox' -System32Path '$system32PathInSandbox'" 266 267 if ($UseDev) 268 { 269 $bootstrapPs1Content += " -UseDev" 270 } 271 272 if ($MetadataCollection) 273 { 274 $bootstrapPs1Content += " -MetadataCollection" 275 } 276 277 $bootstrapPs1FileName = 'Bootstrap.ps1' 278 $bootstrapPs1Content | Out-File (Join-Path $tempFolder $bootstrapPs1FileName) -Force 279 280 # Create Windows Sandbox configuration file 281 282 $bootstrapPs1InSandbox = Join-Path -Path $desktopInSandbox -ChildPath (Join-Path -Path $tempFolderName -ChildPath $bootstrapPs1FileName) 283 $tempFolderInSandbox = Join-Path -Path $desktopInSandbox -ChildPath $tempFolderName 284 $exePathInSandbox = Join-Path -Path $desktopInSandbox -ChildPath "InstallAndCheckCorrelation" 285 286 $devPackageInSandbox = Join-Path -Path $desktopInSandbox -ChildPath "DevPackage" 287 $devPackageXMLFragment = "" 288 289 if ($UseDev) 290 { 291 $devPackageXMLFragment = @" 292 <MappedFolder> 293 <HostFolder>$DevPackagePath</HostFolder> 294 <SandboxFolder>$devPackageInSandbox</SandboxFolder> 295 </MappedFolder> 296 "@ 297 } 298 299 $regFileDirInSandbox = Join-Path -Path $desktopInSandbox -ChildPath "RegFiles" 300 $regFileDirXMLFragment = "" 301 302 if ($RegFileDirectory) 303 { 304 $regFileDirXMLFragment = @" 305 <MappedFolder> 306 <HostFolder>$RegFileDirectory</HostFolder> 307 <SandboxFolder>$regFileDirInSandbox</SandboxFolder> 308 <ReadOnly>true</ReadOnly> 309 </MappedFolder> 310 "@ 311 } 312 313 $sandboxTestWsbContent = @" 314 <Configuration> 315 <MappedFolders> 316 <MappedFolder> 317 <HostFolder>$tempFolder</HostFolder> 318 <ReadOnly>true</ReadOnly> 319 </MappedFolder> 320 <MappedFolder> 321 <HostFolder>$ExePath</HostFolder> 322 <SandboxFolder>$exePathInSandbox</SandboxFolder> 323 <ReadOnly>true</ReadOnly> 324 </MappedFolder> 325 <MappedFolder> 326 <HostFolder>C:\Windows\System32</HostFolder> 327 <SandboxFolder>$system32PathInSandbox</SandboxFolder> 328 <ReadOnly>true</ReadOnly> 329 </MappedFolder> 330 $devPackageXMLFragment 331 $regFileDirXMLFragment 332 <MappedFolder> 333 <HostFolder>$outPath</HostFolder> 334 </MappedFolder> 335 </MappedFolders> 336 <LogonCommand> 337 <Command>PowerShell Start-Process PowerShell -WindowStyle Maximized -WorkingDirectory '$tempFolderInSandbox' -ArgumentList '-ExecutionPolicy Bypass -NoExit -NoLogo -File $bootstrapPs1InSandbox'</Command> 338 </LogonCommand> 339 </Configuration> 340 "@ 341 342 $sandboxTestWsbFileName = 'SandboxTest.wsb' 343 $sandboxTestWsbFile = Join-Path -Path $tempFolder -ChildPath $sandboxTestWsbFileName 344 $sandboxTestWsbContent | Out-File $sandboxTestWsbFile -Force 345 346 Write-Host @" 347 --> Starting Windows Sandbox: 348 - Package: $packageIdentifier 349 - Output directory: $outPath 350 "@ 351 352 Write-Host 353 354 WindowsSandbox $SandboxTestWsbFile 355 356 $outputFileBlockerPath = Join-Path $outPath "done.txt" 357 358 # The correlation program should time out on its own after 10m. 359 $waitTimeout = [System.TimeSpan]::new(0, 15, 0) 360 $startWaitTime = Get-Date 361 362 while (-not (Test-Path $outputFileBlockerPath)) 363 { 364 $elapsedTime = (Get-Date) - $startWaitTime 365 if ($elapsedTime -gt $waitTimeout) 366 { 367 break 368 } 369 Start-Sleep 1 370 } 371 372 if ($Wait) 373 { 374 Read-Host "Press Enter to close sandbox and continue..." 375 } 376 377 Close-WindowsSandbox 378 } 379 380 Write-Host @" 381 --> Results are located at $ResultsPath 382 "@