| 1 | <# |
| 2 | .SYNOPSIS |
| 3 | Runs all WSL tests; optionally sets-up a WSL distribution and environment prior to running the tests. |
| 4 | .PARAMETER Version |
| 5 | The version of WSL to run the tests in. |
| 6 | .PARAMETER DistroPath |
| 7 | Path to a .tar/.tar.gz file of the distro to be imported to run the tests with, if specified. |
| 8 | .PARAMETER DistroName |
| 9 | The name to be given to the imported distro. |
| 10 | .PARAMETER Package |
| 11 | Path to the wsl.msix package to install. Optional. |
| 12 | .PARAMETER UnitTestsPath |
| 13 | Path to the linux/unit_tests directory to copy and install the unit tests. Optional. |
| 14 | .PARAMETER PostInstallCommand |
| 15 | Command to run post-installation and set-up of the WSL distro used for testing, if specified. |
| 16 | .PARAMETER AllowUnsigned |
| 17 | Imports .\private-wsl.cert to the LocalMachine\Root store. |
| 18 | #> |
| 19 | |
| 20 | [CmdletBinding()] |
| 21 | Param ( |
| 22 | [Parameter(Mandatory = $true)]$Version, |
| 23 | $DistroPath, |
| 24 | $DistroName, |
| 25 | $Package = $null, |
| 26 | $UnitTestsPath = $null, |
| 27 | $PostInstallCommand = $null, |
| 28 | [switch]$AllowUnsigned) |
| 29 | |
| 30 | $ErrorActionPreference = "Stop" |
| 31 | Set-StrictMode -Version Latest |
| 32 | |
| 33 | function Run { |
| 34 | [CmdletBinding()] |
| 35 | param([ScriptBlock]$cmd) |
| 36 | |
| 37 | Invoke-Command -ScriptBlock $cmd |
| 38 | if ($lastexitcode -ne 0) { |
| 39 | throw ("$cmd failed with exit code: " + $lastexitcode) |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | if ($Package) { |
| 44 | $installedPackage = Get-AppxPackage MicrosoftCorporationII.WindowsSubsystemforLinux -AllUsers |
| 45 | if ($installedPackage) { |
| 46 | Write-Host "Removing previous package installation" |
| 47 | Remove-AppxPackage $installedPackage -AllUsers |
| 48 | } |
| 49 | |
| 50 | $installedMsi = (Get-ItemProperty -Path "HKLM:Software\Microsoft\Windows\CurrentVersion\Lxss\MSI" -Name ProductCode -ErrorAction Ignore) |
| 51 | if ($installedMsi) |
| 52 | { |
| 53 | Write-Host "Removing MSI package: $($installedMsi.ProductCode)" |
| 54 | $MSIArguments = @( |
| 55 | "/norestart" |
| 56 | "/qn" |
| 57 | "/x" |
| 58 | "$($installedMsi.ProductCode)" |
| 59 | ) |
| 60 | |
| 61 | $exitCode = (Start-Process -Wait "msiexec.exe" -ArgumentList $MSIArguments -NoNewWindow -PassThru).ExitCode |
| 62 | # 1605 means that ProductCode was not present on the system |
| 63 | if ($exitCode -Eq 1605) |
| 64 | { |
| 65 | Write-Host "MSI product $($installedMsi.ProductCode) was not found, registry HKLM:Software\Microsoft\Windows\CurrentVersion\Lxss\MSI appears to have been leaked." |
| 66 | exit 1 |
| 67 | } |
| 68 | elseif ($exitCode -Ne 0) |
| 69 | { |
| 70 | Write-Host "Failed to remove package: $exitCode" |
| 71 | exit 1 |
| 72 | } |
| 73 | |
| 74 | } |
| 75 | |
| 76 | Write-Host "Installing package: $Package" |
| 77 | try { |
| 78 | if ($AllowUnsigned) |
| 79 | { |
| 80 | # Try to add with -AllowUnsigned first (supported in newer PowerShell) |
| 81 | try { |
| 82 | Add-AppxPackage $Package -AllowUnsigned -ErrorAction Stop |
| 83 | } |
| 84 | catch { |
| 85 | # Fallback: manually import the certificate and trust it |
| 86 | Write-Host "Attempting to import package certificate..." |
| 87 | $signature = Get-AuthenticodeSignature -LiteralPath $Package |
| 88 | if (-not $signature.SignerCertificate) { |
| 89 | Write-Error "Package is not signed or has no certificate. Cannot import certificate." |
| 90 | exit 1 |
| 91 | } |
| 92 | |
| 93 | $cert = $signature.SignerCertificate |
| 94 | $certPath = Join-Path $env:TEMP "wsl-package-cert.cer" |
| 95 | try { |
| 96 | $cert | Export-Certificate -FilePath $certPath | Out-Null |
| 97 | Import-Certificate -FilePath $certPath -CertStoreLocation Cert:\LocalMachine\Root | Out-Null |
| 98 | Write-Host "Certificate imported successfully. Retrying package installation..." |
| 99 | } |
| 100 | finally { |
| 101 | Remove-Item -Path $certPath -ErrorAction SilentlyContinue |
| 102 | } |
| 103 | |
| 104 | # Retry installation after importing certificate |
| 105 | Add-AppxPackage $Package -ErrorAction Stop |
| 106 | } |
| 107 | } |
| 108 | else { |
| 109 | Add-AppxPackage $Package -ErrorAction Stop |
| 110 | } |
| 111 | } |
| 112 | catch { |
| 113 | Write-Host "Error installing package: $_" |
| 114 | Get-AppPackageLog | Select-Object -First 64 | Format-List |
| 115 | exit 1 |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | # Disable OOBE during testing |
| 120 | $UserLxssRegistryPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss" |
| 121 | If (-NOT (Test-Path $UserLxssRegistryPath)) |
| 122 | { |
| 123 | New-Item -Path $UserLxssRegistryPath -Force | Out-Null |
| 124 | } |
| 125 | |
| 126 | New-ItemProperty -Path $UserLxssRegistryPath -Name "OOBEComplete" -Value "1" -PropertyType DWORD -Force | Out-Null |
| 127 | |
| 128 | if ($DistroPath) |
| 129 | { |
| 130 | Write-Host "Importing distro $DistroName($Version) from $DistroPath" |
| 131 | & wsl.exe --unregister "$DistroName" # Ignore non-zero return for this call |
| 132 | Run { wsl.exe --import "$DistroName" "$env:LocalAppData\lxss" "$DistroPath" --version "$Version" } |
| 133 | Run { wsl.exe --set-default "$DistroName" } |
| 134 | } |
| 135 | |
| 136 | if ($UnitTestsPath) { |
| 137 | # get wslpath to unit tests |
| 138 | $WslUnitTestPath = Run { wsl.exe --exec wslpath "$UnitTestsPath" } |
| 139 | |
| 140 | # set-up the folder structure for the tests and copy them into the linux distro |
| 141 | Run { wsl.exe --exec bash -c "umask 0; mkdir -p /data;" } |
| 142 | Run { wsl.exe --exec bash -c "umask 0; cp -r $WslUnitTestPath /data/test" } |
| 143 | Run { wsl.exe --exec bash -c "umask 0; mkdir -p /data/test/log" } |
| 144 | |
| 145 | # ensure that /etc/fstab exists for the unit tests that expect it |
| 146 | Run { wsl.exe --exec bash -c "( [ -e `"/etc/fstab`" ] || touch `"/etc/fstab`" )" } |
| 147 | } |
| 148 | |
| 149 | |
| 150 | if ($PostInstallCommand) { |
| 151 | Run { wsl.exe "$PostInstallCommand" } |
| 152 | } |