diff --git a/assets/wix/Product.wxs b/assets/wix/Product.wxs index b4a69fa8e25..01b5dadee87 100644 --- a/assets/wix/Product.wxs +++ b/assets/wix/Product.wxs @@ -84,6 +84,16 @@ Execute="deferred" Return="ignore" Impersonate="no" /> + + Installed AND NOT UPGRADINGPRODUCTCODE @@ -93,6 +103,9 @@ + + + @@ -135,6 +148,7 @@ + @@ -176,6 +190,13 @@ + + USE_MU=1 + + + + + @@ -317,6 +338,37 @@ + + + + + + + + + + + + + + + + + See the Microsoft Update FAQ]]> + + + Read the Microsoft Update Priacy Statement]]> + + + + + + + 1 + + + + @@ -325,6 +377,7 @@ - WixUI_WelcomeDlg - WixUI_InstallDirDlg - ExplorerContextMenuDialog + - MuDialog - WixUI_VerifyReadyDlg - WixUI_DiskCostDlg Maintenance dialog sequence: @@ -364,7 +417,9 @@ Installed AND PATCH 1 - 1 + 1 + 1 + 1 1 1 @@ -375,7 +430,7 @@ 1 1 - NOT Installed + NOT Installed Installed AND NOT PATCH Installed AND PATCH diff --git a/test/packaging/windows/msi.tests.ps1 b/test/packaging/windows/msi.tests.ps1 index d58357a1cd1..9d1c218c4c0 100644 --- a/test/packaging/windows/msi.tests.ps1 +++ b/test/packaging/windows/msi.tests.ps1 @@ -3,6 +3,7 @@ Describe -Name "Windows MSI" -Fixture { BeforeAll { + Set-StrictMode -Off function Test-Elevated { [CmdletBinding()] [OutputType([bool])] @@ -14,6 +15,43 @@ Describe -Name "Windows MSI" -Fixture { return (([Security.Principal.WindowsIdentity]::GetCurrent()).Groups -contains "S-1-5-32-544") } + function Test-IsMuEnabled { + $sm = (New-Object -ComObject Microsoft.Update.ServiceManager) + $mu = $sm.Services | Where-Object { $_.ServiceId -eq '7971f918-a847-4430-9279-4a52d1efe18d' } + if ($mu) { + return $true + } + return $false + } + + function Invoke-TestAndUploadLogOnFailure { + param ( + [scriptblock] $Test + ) + + try { + & $Test + } + catch { + Send-VstsLogFile -Path $msiLog + throw + } + } + + function Get-UseMU { + $useMu = 0 + $key = 'HKLM:\SOFTWARE\Microsoft\PowerShellCore\' + if ($runtime -like '*x86*') { + $key = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\PowerShellCore\' + } + + try { + $useMu = Get-ItemPropertyValue -Path $key -Name UseMU -ErrorAction SilentlyContinue + } catch {} + + return $useMu + } + function Invoke-Msiexec { param( [Parameter(ParameterSetName = 'Install', Mandatory)] @@ -45,6 +83,7 @@ Describe -Name "Windows MSI" -Fixture { } $argumentList = "$switch $MsiPath /quiet /l*vx $msiLog $additionalOptions" + Write-Verbose -Message "running msiexec $argumentList" $msiExecProcess = Start-Process msiexec.exe -Wait -ArgumentList $argumentList -NoNewWindow -PassThru if ($msiExecProcess.ExitCode -ne 0) { $exitCode = $msiExecProcess.ExitCode @@ -55,6 +94,7 @@ Describe -Name "Windows MSI" -Fixture { $msiX64Path = $env:PsMsiX64Path $channel = $env:PSMsiChannel $runtime = $env:PSMsiRuntime + $muEnabled = Test-IsMuEnabled # Get any existing powershell in the path $beforePath = @(([System.Environment]::GetEnvironmentVariable('PATH', 'MACHINE')) -split ';' | @@ -71,16 +111,14 @@ Describe -Name "Windows MSI" -Fixture { } $uploadedLog = $false } + + AfterAll { + Set-StrictMode -Version 3.0 + } + BeforeEach { $error.Clear() } - AfterEach { - if ($error.Count -ne 0 -and !$uploadedLog) { - Copy-Item -Path $msiLog -Destination $env:temp -Force - Write-Verbose "MSI log is at $env:temp\msilog.txt" -Verbose - $uploadedLog = $true - } - } Context "Upgrade code" { BeforeAll { @@ -149,7 +187,7 @@ Describe -Name "Windows MSI" -Fixture { Context "Add Path disabled" { It "MSI should install without error" -Skip:(!(Test-Elevated)) { { - Invoke-MsiExec -Install -MsiPath $msiX64Path -Properties @{ADD_PATH = 0} + Invoke-MsiExec -Install -MsiPath $msiX64Path -Properties @{ADD_PATH = 0; USE_MU = 1; ENABLE_MU = 1} } | Should -Not -Throw } @@ -160,6 +198,34 @@ Describe -Name "Windows MSI" -Fixture { $psPath | Should -BeNullOrEmpty } + It "UseMU should be 1" -Skip:(!(Test-Elevated)) { + Invoke-TestAndUploadLogOnFailure -Test { + $useMu = Get-UseMU + $useMu | Should -Be 1 + } + } + + It "MSI should uninstall without error" -Skip:(!(Test-Elevated)) { + { + Invoke-MsiExec -Uninstall -MsiPath $msiX64Path + } | Should -Not -Throw + } + } + + Context "USE_MU disabled" { + It "MSI should install without error" -Skip:(!(Test-Elevated)) { + { + Invoke-MsiExec -Install -MsiPath $msiX64Path -Properties @{USE_MU = 0} + } | Should -Not -Throw + } + + It "UseMU should be 0" -Skip:(!(Test-Elevated)) { + Invoke-TestAndUploadLogOnFailure -Test { + $useMu = Get-UseMU + $useMu | Should -Be 0 + } + } + It "MSI should uninstall without error" -Skip:(!(Test-Elevated)) { { Invoke-MsiExec -Uninstall -MsiPath $msiX64Path diff --git a/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 b/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 index 0071f16fcdc..894a85ff14d 100644 --- a/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 +++ b/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 @@ -219,22 +219,21 @@ function Send-VstsLogFile { } } + $newName = ([System.Io.Path]::GetRandomFileName() + "-$LogName.txt") if($Contents) { - $logFile = Join-Path -Path $logFolder -ChildPath ([System.Io.Path]::GetRandomFileName() + "-$LogName.txt") - $name = Split-Path -Leaf -Path $logFile + $logFile = Join-Path -Path $logFolder -ChildPath $newName $Contents | Out-File -path $logFile -Encoding ascii } else { - $name = Split-Path -Leaf -Path $path - $logFile = Join-Path -Path $logFolder -ChildPath ([System.Io.Path]::GetRandomFileName() + '-' + $name) + $logFile = Join-Path -Path $logFolder -ChildPath $newName Copy-Item -Path $Path -Destination $logFile } - Write-Host "##vso[artifact.upload containerfolder=$name;artifactname=$name]$logFile" - Write-Verbose "Log file captured as $name" -Verbose + Write-Host "##vso[artifact.upload containerfolder=$newName;artifactname=$newName]$logFile" + Write-Verbose "Log file captured as $newName" -Verbose } # Tests if the Linux or macOS user is root diff --git a/tools/ci.psm1 b/tools/ci.psm1 index afdf5b81bab..0272cb42f6b 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -546,23 +546,21 @@ function Invoke-CIFinish Start-PSBuild -Restore -Runtime win-arm64 -PSModuleRestore -Configuration 'Release' -ReleaseTag $releaseTag $arm64Package = Start-PSPackage -Type zip -WindowsRuntime win-arm64 -ReleaseTag $releaseTag -SkipReleaseChecks $artifacts.Add($arm64Package) - + } + finally { $pushedAllArtifacts = $true $artifacts | ForEach-Object { Write-Log -Message "Pushing $_ as CI artifact" - if(Test-Path $_) - { + if (Test-Path $_) { Push-Artifact -Path $_ -Name 'artifacts' - } - else - { + } else { $pushedAllArtifacts = $false Write-Warning "Artifact $_ does not exist." } } - if(!$pushedAllArtifacts) - { + + if (!$pushedAllArtifacts) { throw "Some artifacts did not exist!" } } diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 861dfc95c24..c8a71baa43f 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -3278,7 +3278,8 @@ function Start-MsiBuild { Write-Log "running light..." # suppress ICE61, because we allow same version upgrades # suppress ICE57, this suppresses an error caused by our shortcut not being installed per user - Start-NativeExecution -VerboseOutputOnError {& $wixPaths.wixLightExePath -sice:ICE61 -sice:ICE57 -out $msiLocationPath -pdbout $msiPdbLocationPath $objectPaths $extensionArgs } + # suppress ICE40, REINSTALLMODE is defined in the Property table. + Start-NativeExecution -VerboseOutputOnError {& $wixPaths.wixLightExePath -sice:ICE61 -sice:ICE40 -sice:ICE57 -out $msiLocationPath -pdbout $msiPdbLocationPath $objectPaths $extensionArgs } foreach($file in $objectPaths) {