From 3c87114e6db030f4e59294cd9b5d0b8304fd95c7 Mon Sep 17 00:00:00 2001 From: Jacques Eloff Date: Tue, 4 May 2021 20:55:39 -0700 Subject: [PATCH] Optional Workload: Finalizer (#10356) MSI finalizer to remove optional workloads when uninstalling the SDK. --- .vsts-ci.yml | 8 +- Native.sln | 42 ++++ eng/Build.props | 8 + eng/Versions.props | 3 + eng/configure-toolset.ps1 | 2 + eng/configure-toolset.sh | 5 +- eng/native.proj | 16 ++ eng/version.csproj | 8 + global.json | 6 +- src/finalizer/CMakeLists.txt | 39 ++++ src/finalizer/finalizer.cpp | 211 ++++++++++++++++++ src/finalizer/finalizer.proj | 14 ++ src/finalizer/native.rc | Bin 0 -> 3024 bytes src/finalizer/precomp.h | 26 +++ src/finalizer_shim/finalizer_shim.csproj | 35 +++ src/redist/targets/GenerateMSIs.targets | 3 + .../packaging/windows/clisdk/bundle.wxs | 18 +- .../windows/clisdk/generatebundle.ps1 | 2 + .../packaging/windows/clisdk/variables.wxi | 2 + 19 files changed, 440 insertions(+), 8 deletions(-) create mode 100644 Native.sln create mode 100644 eng/Build.props create mode 100644 eng/native.proj create mode 100644 eng/version.csproj create mode 100644 src/finalizer/CMakeLists.txt create mode 100644 src/finalizer/finalizer.cpp create mode 100644 src/finalizer/finalizer.proj create mode 100644 src/finalizer/native.rc create mode 100644 src/finalizer/precomp.h create mode 100644 src/finalizer_shim/finalizer_shim.csproj diff --git a/.vsts-ci.yml b/.vsts-ci.yml index 95a18d7a928e..db8b04ad317a 100644 --- a/.vsts-ci.yml +++ b/.vsts-ci.yml @@ -46,10 +46,10 @@ stages: pool: ${{ if eq(variables['System.TeamProject'], 'public') }}: name: NetCorePublic-Pool - queue: buildpool.windows.10.amd64.vs2017.open + queue: buildpool.windows.10.amd64.vs2019.open ${{ if eq(variables['System.TeamProject'], 'internal') }}: name: NetCoreInternal-Pool - queue: buildpool.windows.10.amd64.vs2017 + queue: buildpool.windows.10.amd64.vs2019 timeoutInMinutes: 180 strategy: matrix: @@ -103,10 +103,10 @@ stages: pool: ${{ if eq(variables['System.TeamProject'], 'public') }}: name: NetCorePublic-Pool - queue: buildpool.windows.10.amd64.vs2017.open + queue: buildpool.windows.10.amd64.vs2019.open ${{ if eq(variables['System.TeamProject'], 'internal') }}: name: NetCoreInternal-Pool - queue: buildpool.windows.10.amd64.vs2017 + queue: buildpool.windows.10.amd64.vs2019 timeoutInMinutes: 180 strategy: matrix: diff --git a/Native.sln b/Native.sln new file mode 100644 index 000000000000..7ce79b609c03 --- /dev/null +++ b/Native.sln @@ -0,0 +1,42 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28603.18 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED2FE3E2-F7E7-4389-8231-B65123F2076F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "finalizer_shim", "src\finalizer_shim\finalizer_shim.csproj", "{688E2883-C5A9-4D66-A207-772C9160989C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Debug|x64 = Debug|x64 + Debug|arm64 = Debug|arm64 + Release|x86 = Release|x86 + Release|x64 = Release|x64 + Release|arm64 = Release|arm64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {688E2883-C5A9-4D66-A207-772C9160989C}.Debug|x86.ActiveCfg = Debug|x86 + {688E2883-C5A9-4D66-A207-772C9160989C}.Debug|x86.Build.0 = Debug|x86 + {688E2883-C5A9-4D66-A207-772C9160989C}.Debug|x64.ActiveCfg = Debug|x64 + {688E2883-C5A9-4D66-A207-772C9160989C}.Debug|x64.Build.0 = Debug|x64 + {688E2883-C5A9-4D66-A207-772C9160989C}.Debug|arm64.ActiveCfg = Debug|arm64 + {688E2883-C5A9-4D66-A207-772C9160989C}.Debug|arm64.Build.0 = Debug|arm64 + {688E2883-C5A9-4D66-A207-772C9160989C}.Release|x86.ActiveCfg = Release|x86 + {688E2883-C5A9-4D66-A207-772C9160989C}.Release|x86.Build.0 = Release|x86 + {688E2883-C5A9-4D66-A207-772C9160989C}.Release|x64.ActiveCfg = Release|x64 + {688E2883-C5A9-4D66-A207-772C9160989C}.Release|x64.Build.0 = Release|x64 + {688E2883-C5A9-4D66-A207-772C9160989C}.Release|arm64.ActiveCfg = Release|arm64 + {688E2883-C5A9-4D66-A207-772C9160989C}.Release|arm64.Build.0 = Release|arm64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {688E2883-C5A9-4D66-A207-772C9160989C} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {18FCFCA3-D1A8-4D3A-9763-6A658D0D726F} + EndGlobalSection +EndGlobal diff --git a/eng/Build.props b/eng/Build.props new file mode 100644 index 000000000000..917aa8993518 --- /dev/null +++ b/eng/Build.props @@ -0,0 +1,8 @@ + + + + + + diff --git a/eng/Versions.props b/eng/Versions.props index f5b269b143fd..402e77f662ab 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -99,6 +99,9 @@ $(MicrosoftNETCoreAppRuntimePackageVersion) $(MicrosoftNETCoreAppRuntimePackageVersion) + + 3.14.0-dotnet + $(MicrosoftDotnetWinFormsProjectTemplatesPackageVersion) diff --git a/eng/configure-toolset.ps1 b/eng/configure-toolset.ps1 index 87375243e337..c6cc32f0c4f6 100644 --- a/eng/configure-toolset.ps1 +++ b/eng/configure-toolset.ps1 @@ -2,3 +2,5 @@ $script:useInstalledDotNetCli = $false +# Add CMake to the path. +$env:PATH = "$PSScriptRoot\..\.tools\bin;$env:PATH" diff --git a/eng/configure-toolset.sh b/eng/configure-toolset.sh index d890b1b0207f..1e0b58a364a6 100644 --- a/eng/configure-toolset.sh +++ b/eng/configure-toolset.sh @@ -1,3 +1,6 @@ # SdkTests do not currently work with globally installed CLI as they use dotnet-install.ps1 to install more runtimes -useInstalledDotNetCli="false" \ No newline at end of file +useInstalledDotNetCli="false" + +# Working around issue https://github.com/dotnet/arcade/issues/7327 +DisableNativeToolsetInstalls=true \ No newline at end of file diff --git a/eng/native.proj b/eng/native.proj new file mode 100644 index 000000000000..736b175c3a90 --- /dev/null +++ b/eng/native.proj @@ -0,0 +1,16 @@ + + + + $(Architecture) + + + + + + + + + + + + diff --git a/eng/version.csproj b/eng/version.csproj new file mode 100644 index 000000000000..c745a34740ed --- /dev/null +++ b/eng/version.csproj @@ -0,0 +1,8 @@ + + + $(CoreSdkTargetFramework) + $(ArtifactsObjDir)sdk_version.h + + + + diff --git a/global.json b/global.json index 825c7cd6f634..5b01eaf09d86 100644 --- a/global.json +++ b/global.json @@ -7,7 +7,11 @@ ] } }, + "native-tools": { + "cmake": "3.16.4" + }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21253.2" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21253.2", + "Microsoft.DotNet.CMake.Sdk": "6.0.0-beta.21253.2" } } diff --git a/src/finalizer/CMakeLists.txt b/src/finalizer/CMakeLists.txt new file mode 100644 index 000000000000..fe1b531ea9eb --- /dev/null +++ b/src/finalizer/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.15.5) + +# Create project named finalizer, this will +# will generate Finalizer.vcxproj +project(Finalizer) + +set(CMAKE_MACOSX_RPATH 1) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /ENTRY:wmainCRTStartup") + +# The WiX SDK is extracted from a NuGet package using an SDK .csproj (finalizer_shim) +# that copies the "lib" and "inc" folders to a stable location. + +include_directories(../../artifacts/WixSdk/inc) +include_directories(../../artifacts/obj) +link_directories(../../artifacts/WixSdk/lib/${Platform}) + +add_compile_options(/MT) + +add_executable(Finalizer + finalizer.cpp + native.rc +) + +# These are normally part of a .vcxproj in Visual Studio, but +# appears to be missing when CMAKE generates a .vcxproj +# for arm64. +target_link_libraries(Finalizer shell32.lib) +target_link_libraries(Finalizer advapi32.lib) +target_link_libraries(Finalizer version.lib) +target_link_libraries(Finalizer msi.lib) + +# Add WiX libraries +target_link_libraries(Finalizer wcautil.lib) +target_link_libraries(Finalizer dutil.lib) + +install(TARGETS Finalizer) diff --git a/src/finalizer/finalizer.cpp b/src/finalizer/finalizer.cpp new file mode 100644 index 000000000000..5860d3df0878 --- /dev/null +++ b/src/finalizer/finalizer.cpp @@ -0,0 +1,211 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "precomp.h" + +extern "C" HRESULT Initialize(int argc, wchar_t* argv[]) +{ + HRESULT hr = S_OK; + + // We're not going to do any clever parsing. This is intended to be called from + // the standalone bundle only and there will only be two parameters: + // 1. The path of the log file, created by the bundle. + // 2. The dependent we're trying to clean up. + if (argc != 3) + { + return HRESULT_FROM_WIN32(ERROR_INVALID_COMMAND_LINE); + } + + LogInitialize(::GetModuleHandleW(NULL)); + +#ifdef _DEBUG + LogSetLevel(REPORT_DEBUG, FALSE); +#else + LogSetLevel(REPORT_VERBOSE, FALSE); // FALSE means don't write an additional text line to the log saying the level changed +#endif + + hr = LogOpen(NULL, argv[1], NULL, NULL, FALSE, TRUE, NULL); + ExitOnFailure(hr, "Failed to create log file."); + + hr = RegInitialize(); + ExitOnFailure(hr, "Failed to initialize the registry."); + + hr = WiuInitialize(); + ExitOnFailure(hr, "Failed to initialize Windows Installer."); + +LExit: + return hr; +} + +extern "C" HRESULT RemoveDependent(LPWSTR sczDependent, BOOL* pbRestartRequired) +{ + HRESULT hr = S_OK; + HKEY hkInstallerDependenciesKey = NULL; + HKEY hkProviderKey = NULL; + HKEY hkDependentsKey = NULL; + LPWSTR sczProviderKey = NULL; + LPWSTR sczDependentsKey = NULL; + LPWSTR sczProductId = NULL; + LPWSTR sczProductName = NULL; + DWORD cSubKeys = 0; + DWORD dwExitCode = 0; + WIU_RESTART restart = WIU_RESTART_NONE; + + // Optional workloads are always per-machine installs, so we don't need to check HKCU. + hr = RegOpen(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Classes\\Installer\\Dependencies", KEY_READ, &hkInstallerDependenciesKey); + ExitOnFailure(hr, "Failed to read installer dependencies key."); + + // This has to be an exhaustive search as we're not looking for a specific provider key, but for a specific dependent + // that could be registered against any provider key. + for (DWORD dwIndex = 0;; ++dwIndex) + { + // Get the next provider key name + hr = RegKeyEnum(hkInstallerDependenciesKey, dwIndex, &sczProviderKey); + + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + break; + } + + ExitOnFailure(hr, "Failed to enumerate installer dependency provider keys."); + LogStringLine(REPORT_STANDARD, "Processing provider key: %ls", sczProviderKey); + + hr = RegOpen(hkInstallerDependenciesKey, sczProviderKey, KEY_READ, &hkProviderKey); + ExitOnFailure(hr, "Unable to open provider key."); + + // Open the dependents key with write permissions so we can modify it if it matches + // the target dependent value. + hr = RegOpen(hkProviderKey, L"Dependents", KEY_READ | KEY_WRITE, &hkDependentsKey); + if (E_FILENOTFOUND == hr) + { + // Providers can sometimes become orphaned duirng uninstalls. If there's no Dependents subkey, we just + // release the handle and continue to the next provider key. + hr = S_OK; + ReleaseRegKey(hkProviderKey); + + continue; + } + + ExitOnFailure(hr, "Unable to open dependents key."); + + // Enumerate over all the dependent keys + for (DWORD dwDepdentsKeyIndex = 0;; ++dwDepdentsKeyIndex) + { + hr = RegKeyEnum(hkDependentsKey, dwDepdentsKeyIndex, &sczDependentsKey); + + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + break; + } + + ExitOnFailure(hr, "Failed to read provider's dependent key."); + + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczDependentsKey, -1, sczDependent, -1)) + { + LogStringLine(REPORT_STANDARD, " Dependent match found: %ls", sczDependentsKey); + + hr = RegDelete(hkDependentsKey, sczDependent, REG_KEY_DEFAULT, TRUE); + ExitOnFailure(hr, "Failed to delete dependent \"%ls\"", sczDependent); + LogStringLine(REPORT_STANDARD, " Dependent deleted"); + // Reset the index since we're deleting keys while enumerating + dwDepdentsKeyIndex = dwDepdentsKeyIndex > 1 ? dwDepdentsKeyIndex-- : 0; + + // Check if there are any subkeys remaining under the dependents key. If not, we + // can uninstall the MSI. We'll recheck the key again in case the MSI fails to clean up the + // provider key to make sure we don't have orphaned keys. + hr = RegQueryKey(hkDependentsKey, &cSubKeys, NULL); + ExitOnFailure(hr, "Failed to query dependents key."); + + LogStringLine(REPORT_STANDARD, " Remaining dependents: %i", cSubKeys); + + if (0 == cSubKeys) + { + // This was the final dependent, so now we can remove the installation if the provider wasn't corrupted and + // still contains the product ID. + hr = RegReadString(hkProviderKey, NULL, &sczProductId); + + if (E_FILENOTFOUND == hr) + { + LogStringLine(REPORT_STANDARD, " No product ID found, provider key: %ls", sczProviderKey); + hr = S_OK; + break; + } + else + { + ExitOnFailure(hr, "Failed to read product ID."); + } + + // Let's make sure the product is actually installed. The provider key for an MSI typically + // stores the ProductCode, DisplayName, and Version, but by calling into MsiGetProductInfo, + // we're doing an implicit detect and getting a property back. + hr = WiuGetProductInfo(sczProductId, L"ProductName", &sczProductName); + if (SUCCEEDED(hr)) + { + // The provider key *should* have the ProductName and ProductVersion properties, but since + // we know it's installed, we just query the installer service. + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + hr = WiuConfigureProductEx(sczProductId, INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT, L"MSIFASTINSTALL=7 IGNOREDEPENDENCIES=ALL REBOOT=ReallySuppress", &restart); + LogStringLine(REPORT_STANDARD, " Uninstall of \"%ls\" (%ls%) exited with 0x%.8x", sczProductName, sczProductId, hr); + + // Flag any reboot since we need to return that to the bundle. + if (WIU_RESTART_INITIATED == restart || WIU_RESTART_REQUIRED == restart) + { + LogStringLine(REPORT_STANDARD, " Reboot requested, deferring."); + *pbRestartRequired = TRUE; + } + + // Reset potential failures so we can continue to remove as many dependents as possible. + hr = S_OK; + } + else if (HRESULT_FROM_WIN32(ERROR_UNKNOWN_PRODUCT) == hr || HRESULT_FROM_WIN32(ERROR_UNKNOWN_PROPERTY) == hr) + { + // Possibly a corrupted provider key that wasn't cleaned up. We'll just ignore it. + LogStringLine(REPORT_STANDARD, " Product is not installed, ProductCode:%ls, result: 0x%.8x", sczProductId, hr); + hr = S_OK; + } + } + } + } + + ReleaseRegKey(hkDependentsKey); + ReleaseRegKey(hkProviderKey); + } + +LExit: + ReleaseStr(sczProductName); + ReleaseStr(sczProductId); + ReleaseStr(sczProviderKey); + ReleaseStr(sczDependentsKey); + ReleaseRegKey(hkDependentsKey); + ReleaseRegKey(hkProviderKey); + ReleaseRegKey(hkInstallerDependenciesKey); + return hr; +} + +int wmain(int argc, wchar_t* argv[]) +{ + HRESULT hr = S_OK; + DWORD dwExitCode = 0; + LPWSTR sczDependent = NULL; + BOOL bRestartRequired = FALSE; + + hr = ::Initialize(argc, argv); + ExitOnFailure(hr, "Failed to initialize."); + + sczDependent = argv[2]; + hr = ::RemoveDependent(sczDependent, &bRestartRequired); + ExitOnFailure(hr, "Failed to remove dependent \"%ls\".", sczDependent); + + if (bRestartRequired) + { + dwExitCode = ERROR_SUCCESS_REBOOT_REQUIRED; + } + +LExit: + LogUninitialize(TRUE); + RegUninitialize(); + WiuUninitialize(); + return FAILED(hr) ? (int)hr : (int)dwExitCode; +} diff --git a/src/finalizer/finalizer.proj b/src/finalizer/finalizer.proj new file mode 100644 index 000000000000..463a37a14abc --- /dev/null +++ b/src/finalizer/finalizer.proj @@ -0,0 +1,14 @@ + + + CMakeLists.txt + + + + + + + + diff --git a/src/finalizer/native.rc b/src/finalizer/native.rc new file mode 100644 index 0000000000000000000000000000000000000000..bea8f0b5201472b08eff2cd32328290138cdde8a GIT binary patch literal 3024 zcmc(hT~As;5QgWvN&mx!-l#FvT6@u?X(IAbBZ>ipcxA96B}E_tRr}-HKJPBeIR}(h z+oU1qupcw?&b%`_dw%|SWj!0%XY1S4F0EtEayDl4)z0l3^BZP88zS@CzOeVwUifEO z?}OcXTbD@Rq9yr{bNQy#vDmbt)fgRE)sC4T@GdcS3p;ULXeFd7=w)>sI^h@A&mWPK zg%dEVRp*X-`V{vu9=EIO4xKF~;t$CI!f5CMH%&tdNu1929YMUwl{gWyy5>Fv>=8~1i`%@DRZsvJ-PG{P(4LU-D`qAyG zzSifbJ5pKhvex$_?T(Qe!hW9|I7S0T_lz#Q?lmiy$X@Yuyo9XXcnd=^ri$s=_t{?d z_SSuzWN^c_GEBss;Ohaoci0oYZvQd!F)Krm9VqI2j`x(BlxOlF?6o)pHCW!{4hSRX zdu0!qvG0+JdP0;Ay*3ycshdh7dXfEK?W?|7Vn@8dN?^2&t-klPiZOgX4R4DRlH{7`rotFzLtFK%F-Qd>BiH| ztXodpssc54?8M&aV5aTA869uc;uHzhO^$o`ZgwMY+8e$_-tpwv5$~#K)vnkN*%QZ_ zYhUl*@tVz+5R2ZDPJ>R=axFMpOZl{pgs>fGA-gR1TK8ux l@|x}`G1u8!y+L*9G>v_&#_9|AYML=ON0805-K2ws(J$6shg$#u literal 0 HcmV?d00001 diff --git a/src/finalizer/precomp.h b/src/finalizer/precomp.h new file mode 100644 index 000000000000..92e713d52689 --- /dev/null +++ b/src/finalizer/precomp.h @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +// Configure some logging parameters for WiX +#define ExitTrace LogErrorString +#define ExitTrace1 LogErrorString +#define ExitTrace2 LogErrorString +#define ExitTrace3 LogErrorString + +// Includes from WiX SDK +#include "dutil.h" +#include "regutil.h" +#include "logutil.h" +#include "strutil.h" +#include "wiutil.h" diff --git a/src/finalizer_shim/finalizer_shim.csproj b/src/finalizer_shim/finalizer_shim.csproj new file mode 100644 index 000000000000..1f378f56b504 --- /dev/null +++ b/src/finalizer_shim/finalizer_shim.csproj @@ -0,0 +1,35 @@ + + + + $(Architecture) + $(CoreSdkTargetFramework) + true + false + false + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/redist/targets/GenerateMSIs.targets b/src/redist/targets/GenerateMSIs.targets index 0c69a4db799e..b3fbe8fab446 100644 --- a/src/redist/targets/GenerateMSIs.targets +++ b/src/redist/targets/GenerateMSIs.targets @@ -27,6 +27,8 @@ $(MSBuildThisFileDirectory)packaging/windows/clisdk/generatebundle.ps1 $(MSBuildThisFileDirectory)packaging/windows/clisdk/generatenupkg.ps1 + $(ArtifactsDir)bin/finalizer/$(Architecture)/$(Configuration)/bin/finalizer.exe + $(MSBuildThisFileDirectory)packaging/windows/clisdk/VS.Redist.Common.NetCore.Toolset.nuspec $(ArtifactsNonShippingPackagesDir)VS.Redist.Common.NetCore.Toolset.$(Architecture).$(FullNugetVersion).nupkg $(MSBuildThisFileDirectory)packaging/windows/clisdk/VS.Redist.Common.NetCore.SdkPlaceholder.nuspec @@ -345,6 +347,7 @@ '$(DownloadsFolder)$(DownloadedArm64NetCoreAppHostPackInstallerFileName)' ^ '$(DownloadsFolder)$(DownloadedAspNetTargetingPackInstallerFileName)' ^ '$(DownloadsFolder)$(DownloadedWindowsDesktopTargetingPackInstallerFileName)' ^ + '$(FinalizerExe)' ^ '$(LatestTemplateMsiInstallerFile)' ^ '$(ManifestsMsiInstallerFile)' ^ '$(CombinedFrameworkSdkHostMSIInstallerFile)' ^ diff --git a/src/redist/targets/packaging/windows/clisdk/bundle.wxs b/src/redist/targets/packaging/windows/clisdk/bundle.wxs index aac49d06b36c..67cae8841f40 100644 --- a/src/redist/targets/packaging/windows/clisdk/bundle.wxs +++ b/src/redist/targets/packaging/windows/clisdk/bundle.wxs @@ -175,10 +175,10 @@ - + - + @@ -194,6 +194,20 @@ + + + diff --git a/src/redist/targets/packaging/windows/clisdk/generatebundle.ps1 b/src/redist/targets/packaging/windows/clisdk/generatebundle.ps1 index 58bbdde7a4d4..d68bf8441b46 100644 --- a/src/redist/targets/packaging/windows/clisdk/generatebundle.ps1 +++ b/src/redist/targets/packaging/windows/clisdk/generatebundle.ps1 @@ -16,6 +16,7 @@ param( [Parameter(Mandatory=$true)][string]$Arm64NetCoreAppHostPackMSIFile, [Parameter(Mandatory=$true)][string]$AspNetTargetingPackMSIFile, [Parameter(Mandatory=$true)][string]$WindowsDesktopTargetingPackMSIFile, + [Parameter(Mandatory=$true)][string]$FinalizerExe, [Parameter(Mandatory=$true)][string]$TemplatesMSIFile, [Parameter(Mandatory=$true)][string]$ManifestsMSIFile, [Parameter(Mandatory=$true)][string]$DotnetBundleOutput, @@ -63,6 +64,7 @@ function RunCandleForBundle -dNetStandardTargetingPackMsiSourcePath="$NetStandardTargetingPackMSIFile" ` -dAspNetTargetingPackMsiSourcePath="$AspNetTargetingPackMSIFile" ` -dWindowsDesktopTargetingPackMsiSourcePath="$WindowsDesktopTargetingPackMSIFile" ` + -dFinalizerExeSourcePath="$FinalizerExe" ` -dTemplatesMsiSourcePath="$TemplatesMSIFile" ` -dManifestsMsiSourcePath="$ManifestsMSIFile" ` -dWinFormsAndWpfVersion="$WindowsDesktopVersion" ` diff --git a/src/redist/targets/packaging/windows/clisdk/variables.wxi b/src/redist/targets/packaging/windows/clisdk/variables.wxi index bad1ff7ef21a..4145851752af 100644 --- a/src/redist/targets/packaging/windows/clisdk/variables.wxi +++ b/src/redist/targets/packaging/windows/clisdk/variables.wxi @@ -45,4 +45,6 @@ + +