winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 "@