From 759c4dd3de121cae4e307d560e006c19dd9a10af Mon Sep 17 00:00:00 2001 From: vanzue Date: Tue, 2 Sep 2025 15:20:43 +0800 Subject: [PATCH 1/7] fix sln file --- PowerToys.sln | 1 + 1 file changed, 1 insertion(+) diff --git a/PowerToys.sln b/PowerToys.sln index 33075919c2..06e286840d 100644 --- a/PowerToys.sln +++ b/PowerToys.sln @@ -798,6 +798,7 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerToys.DSC", "src\dsc\v3\PowerToys.DSC\PowerToys.DSC.csproj", "{94CDC147-6137-45E9-AEDE-17FF809607C0}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerToys.DSC.UnitTests", "src\dsc\v3\PowerToys.DSC.UnitTests\PowerToys.DSC.UnitTests.csproj", "{A24BF1AF-79AA-4896-BAE3-CCBBE0380A78}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Apps.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.Apps.UnitTests\Microsoft.CmdPal.Ext.Apps.UnitTests.csproj", "{E816D7B1-4688-4ECB-97CC-3D8E798F3830}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Bookmarks.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.Bookmarks.UnitTests\Microsoft.CmdPal.Ext.Bookmarks.UnitTests.csproj", "{E816D7B3-4688-4ECB-97CC-3D8E798F3832}" From b221fda0606e53e7209e99c3a94db40396256110 Mon Sep 17 00:00:00 2001 From: vanzue Date: Wed, 3 Sep 2025 09:42:52 +0800 Subject: [PATCH 2/7] custom actions to support dsc resource deployment --- installer/PowerToysSetup/Product.wxs | 19 +++ .../CustomAction.cpp | 48 +++++++ .../CustomAction.def | 1 + .../CustomAction.cpp | 119 ++++++++++++++++++ .../CustomAction.def | 3 +- installer/PowerToysSetupVNext/Product.wxs | 12 ++ src/dsc/v3/PowerToys.DSC/PowerToys.DSC.csproj | 2 +- 7 files changed, 202 insertions(+), 2 deletions(-) diff --git a/installer/PowerToysSetup/Product.wxs b/installer/PowerToysSetup/Product.wxs index 77ffad8483..ffdb60ae54 100644 --- a/installer/PowerToysSetup/Product.wxs +++ b/installer/PowerToysSetup/Product.wxs @@ -191,6 +191,11 @@ Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL") + + + + Installed AND (REMOVE="ALL") + Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL") @@ -252,6 +257,11 @@ Property="UnApplyModulesRegistryChangeSets" Value="[INSTALLFOLDER]" /> + + + @@ -325,6 +335,15 @@ DllEntry="UninstallDSCModuleCA" /> + + + = 9 && _wcsicmp(name.c_str() + (name.size() - 9), L".dsc.json") == 0) + { + std::error_code ec; + std::filesystem::remove(p, ec); + if (ec) + { + Logger::warn(L"DeleteDscJsonFilesCA: failed to delete {}", p.c_str()); + } + } + } + } + } + } + catch (...) + { + Logger::warn(L"DeleteDscJsonFilesCA: exception while deleting files"); + } + +LExit: + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + const wchar_t *DSC_CONFIGURE_PSD1_NAME = L"Microsoft.PowerToys.Configure.psd1"; const wchar_t *DSC_CONFIGURE_PSM1_NAME = L"Microsoft.PowerToys.Configure.psm1"; diff --git a/installer/PowerToysSetupCustomActions/CustomAction.def b/installer/PowerToysSetupCustomActions/CustomAction.def index 9467ca2204..3fb518c28a 100644 --- a/installer/PowerToysSetupCustomActions/CustomAction.def +++ b/installer/PowerToysSetupCustomActions/CustomAction.def @@ -20,6 +20,7 @@ EXPORTS InstallDSCModuleCA InstallCmdPalPackageCA UnApplyModulesRegistryChangeSetsCA + DeleteDscJsonFilesCA UnRegisterCmdPalPackageCA UnRegisterContextMenuPackagesCA UninstallEmbeddedMSIXCA diff --git a/installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp b/installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp index 8c3ad76448..18a6c79c7a 100644 --- a/installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp +++ b/installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp @@ -398,6 +398,125 @@ LExit: return WcaFinalize(er); } +// Generate DSC manifests during install by invoking PowerToys.DSC.exe +UINT __stdcall GenerateDscManifestCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + std::wstring installationFolder; + + hr = WcaInitialize(hInstall, "GenerateDscManifest"); + ExitOnFailure(hr, "Failed to initialize"); + + hr = getInstallFolder(hInstall, installationFolder); + ExitOnFailure(hr, "Failed to get installFolder."); + + // Build executable path: \PowerToys.DSC.exe + std::wstring exePath = installationFolder + L"\\PowerToys.DSC.exe"; + + // Build args: manifest --resource settings --outputDir "" + std::wstring args = L"manifest --resource settings --outputDir \"" + installationFolder + L"\""; + std::wstring commandLine = L"\"" + exePath + L"\" " + args; + + // Try to start the process and wait for it to finish; ignore failures (best-effort) + STARTUPINFO startupInfo{ .cb = sizeof(STARTUPINFO), .wShowWindow = SW_HIDE }; + PROCESS_INFORMATION processInformation{}; + + if (!CreateProcess( + nullptr, + commandLine.data(), + nullptr, + nullptr, + FALSE, + CREATE_DEFAULT_ERROR_MODE, + nullptr, + nullptr, + &startupInfo, + &processInformation)) + { + Logger::error(L"GenerateDscManifestCA: failed to launch DSC manifest generator"); + // Don't fail installation on error + goto LExit; + } + + // Wait for completion + WaitForSingleObject(processInformation.hProcess, INFINITE); + + DWORD exitCode = 0; + if (GetExitCodeProcess(processInformation.hProcess, &exitCode)) + { + if (exitCode != 0) + { + Logger::warn(L"GenerateDscManifestCA: manifest generator exited with non-zero code"); + } + else + { + Logger::info(L"GenerateDscManifestCA: manifests generated successfully"); + } + } + + if (!CloseHandle(processInformation.hProcess)) + { + Logger::warn(L"GenerateDscManifestCA: failed to close process handle"); + } + if (!CloseHandle(processInformation.hThread)) + { + Logger::warn(L"GenerateDscManifestCA: failed to close thread handle"); + } + +LExit: + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + +// Delete any *.dsc.json files under the install folder on uninstall +UINT __stdcall DeleteDscJsonFilesCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + std::wstring installationFolder; + + hr = WcaInitialize(hInstall, "DeleteDscJsonFiles"); + ExitOnFailure(hr, "Failed to initialize"); + + hr = getInstallFolder(hInstall, installationFolder); + ExitOnFailure(hr, "Failed to get installFolder."); + + try + { + std::filesystem::path root{ installationFolder }; + if (std::filesystem::exists(root) && std::filesystem::is_directory(root)) + { + for (auto const &entry : std::filesystem::recursive_directory_iterator(root, std::filesystem::directory_options::skip_permission_denied)) + { + if (!entry.is_regular_file()) continue; + const auto &p = entry.path(); + if (p.has_extension() && _wcsicmp(p.extension().c_str(), L".json") == 0) + { + auto name = p.filename().wstring(); + if (name.size() >= 9 && _wcsicmp(name.c_str() + (name.size() - 9), L".dsc.json") == 0) + { + std::error_code ec; + std::filesystem::remove(p, ec); + if (ec) + { + Logger::warn(L"DeleteDscJsonFilesCA: failed to delete %s", p.c_str()); + } + } + } + } + } + } + catch (...) + { + Logger::warn(L"DeleteDscJsonFilesCA: exception while deleting files"); + } + +LExit: + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + const wchar_t *DSC_CONFIGURE_PSD1_NAME = L"Microsoft.PowerToys.Configure.psd1"; const wchar_t *DSC_CONFIGURE_PSM1_NAME = L"Microsoft.PowerToys.Configure.psm1"; diff --git a/installer/PowerToysSetupCustomActionsVNext/CustomAction.def b/installer/PowerToysSetupCustomActionsVNext/CustomAction.def index 39efc9ff70..721298c6fd 100644 --- a/installer/PowerToysSetupCustomActionsVNext/CustomAction.def +++ b/installer/PowerToysSetupCustomActionsVNext/CustomAction.def @@ -32,4 +32,5 @@ EXPORTS CleanFileLocksmithRuntimeRegistryCA CleanPowerRenameRuntimeRegistryCA CleanNewPlusRuntimeRegistryCA - \ No newline at end of file + GenerateDscManifestCA + DeleteDscJsonFilesCA \ No newline at end of file diff --git a/installer/PowerToysSetupVNext/Product.wxs b/installer/PowerToysSetupVNext/Product.wxs index e343897d5d..ce652ce208 100644 --- a/installer/PowerToysSetupVNext/Product.wxs +++ b/installer/PowerToysSetupVNext/Product.wxs @@ -119,6 +119,8 @@ + + @@ -132,6 +134,8 @@ + + @@ -244,6 +248,14 @@ + + + + + + + + diff --git a/src/dsc/v3/PowerToys.DSC/PowerToys.DSC.csproj b/src/dsc/v3/PowerToys.DSC/PowerToys.DSC.csproj index abfcc23200..260773861f 100644 --- a/src/dsc/v3/PowerToys.DSC/PowerToys.DSC.csproj +++ b/src/dsc/v3/PowerToys.DSC/PowerToys.DSC.csproj @@ -39,7 +39,7 @@ - + From e17dd1a63f9478a147849bda6d535c1ed5b58a77 Mon Sep 17 00:00:00 2001 From: "Kai Tao (from Dev Box)" Date: Wed, 3 Sep 2025 10:55:47 +0800 Subject: [PATCH 3/7] fix build --- .../CustomAction.cpp | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp b/installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp index 18a6c79c7a..7e9e3ff358 100644 --- a/installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp +++ b/installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp @@ -3,6 +3,7 @@ #include "RcResource.h" #include #include +#include #include "../../src/common/logger/logger.h" #include "../../src/common/utils/gpo.h" @@ -232,7 +233,9 @@ UINT __stdcall LaunchPowerToysCA(MSIHANDLE hInstall) auto action = [&commandLine](HANDLE userToken) { - STARTUPINFO startupInfo{.cb = sizeof(STARTUPINFO), .wShowWindow = SW_SHOWNORMAL}; + STARTUPINFO startupInfo = { 0 }; + startupInfo.cb = sizeof(STARTUPINFO); + startupInfo.wShowWindow = SW_SHOWNORMAL; PROCESS_INFORMATION processInformation; PVOID lpEnvironment = NULL; @@ -271,7 +274,9 @@ UINT __stdcall LaunchPowerToysCA(MSIHANDLE hInstall) } else { - STARTUPINFO startupInfo{.cb = sizeof(STARTUPINFO), .wShowWindow = SW_SHOWNORMAL}; + STARTUPINFO startupInfo = { 0 }; + startupInfo.cb = sizeof(STARTUPINFO); + startupInfo.wShowWindow = SW_SHOWNORMAL; PROCESS_INFORMATION processInformation; @@ -404,6 +409,12 @@ UINT __stdcall GenerateDscManifestCA(MSIHANDLE hInstall) HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; std::wstring installationFolder; + std::wstring exePath; + std::wstring args; + std::wstring commandLine; + STARTUPINFO startupInfo = { 0 }; + PROCESS_INFORMATION processInformation = { 0 }; + DWORD exitCode = 0; hr = WcaInitialize(hInstall, "GenerateDscManifest"); ExitOnFailure(hr, "Failed to initialize"); @@ -412,15 +423,15 @@ UINT __stdcall GenerateDscManifestCA(MSIHANDLE hInstall) ExitOnFailure(hr, "Failed to get installFolder."); // Build executable path: \PowerToys.DSC.exe - std::wstring exePath = installationFolder + L"\\PowerToys.DSC.exe"; + exePath = installationFolder + L"\\PowerToys.DSC.exe"; // Build args: manifest --resource settings --outputDir "" - std::wstring args = L"manifest --resource settings --outputDir \"" + installationFolder + L"\""; - std::wstring commandLine = L"\"" + exePath + L"\" " + args; + args = L"manifest --resource settings --outputDir \"" + installationFolder + L"\""; + commandLine = L"\"" + exePath + L"\" " + args; // Try to start the process and wait for it to finish; ignore failures (best-effort) - STARTUPINFO startupInfo{ .cb = sizeof(STARTUPINFO), .wShowWindow = SW_HIDE }; - PROCESS_INFORMATION processInformation{}; + startupInfo.cb = sizeof(STARTUPINFO); + startupInfo.wShowWindow = SW_HIDE; if (!CreateProcess( nullptr, @@ -442,7 +453,6 @@ UINT __stdcall GenerateDscManifestCA(MSIHANDLE hInstall) // Wait for completion WaitForSingleObject(processInformation.hProcess, INFINITE); - DWORD exitCode = 0; if (GetExitCodeProcess(processInformation.hProcess, &exitCode)) { if (exitCode != 0) @@ -543,7 +553,7 @@ UINT __stdcall InstallDSCModuleCA(MSIHANDLE hInstall) const auto modulesPath = baseModulesPath / L"Microsoft.PowerToys.Configure" / (get_product_version(false) + L".0"); std::error_code errorCode; - fs::create_directories(modulesPath, errorCode); + std::filesystem::create_directories(modulesPath, errorCode); if (errorCode) { hr = E_FAIL; @@ -552,7 +562,7 @@ UINT __stdcall InstallDSCModuleCA(MSIHANDLE hInstall) for (const auto *filename : {DSC_CONFIGURE_PSD1_NAME, DSC_CONFIGURE_PSM1_NAME}) { - fs::copy_file(fs::path(installationFolder) / "DSCModules" / filename, modulesPath / filename, fs::copy_options::overwrite_existing, errorCode); + std::filesystem::copy_file(std::filesystem::path(installationFolder) / "DSCModules" / filename, modulesPath / filename, std::filesystem::copy_options::overwrite_existing, errorCode); if (errorCode) { @@ -600,7 +610,7 @@ UINT __stdcall UninstallDSCModuleCA(MSIHANDLE hInstall) for (const auto *filename : {DSC_CONFIGURE_PSD1_NAME, DSC_CONFIGURE_PSM1_NAME}) { - fs::remove(versionedModulePath / filename, errorCode); + std::filesystem::remove(versionedModulePath / filename, errorCode); if (errorCode) { @@ -611,7 +621,7 @@ UINT __stdcall UninstallDSCModuleCA(MSIHANDLE hInstall) for (const auto *modulePath : {&versionedModulePath, &powerToysModulePath}) { - fs::remove(*modulePath, errorCode); + std::filesystem::remove(*modulePath, errorCode); if (errorCode) { From ef2a88036ade6ee1d91771f85f64289ed42c6e66 Mon Sep 17 00:00:00 2001 From: "Kai Tao (from Dev Box)" Date: Wed, 3 Sep 2025 13:46:42 +0800 Subject: [PATCH 4/7] fix deps json WindowsBase.dll version --- src/dsc/v3/PowerToys.DSC/PowerToys.DSC.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dsc/v3/PowerToys.DSC/PowerToys.DSC.csproj b/src/dsc/v3/PowerToys.DSC/PowerToys.DSC.csproj index 260773861f..230cd4556b 100644 --- a/src/dsc/v3/PowerToys.DSC/PowerToys.DSC.csproj +++ b/src/dsc/v3/PowerToys.DSC/PowerToys.DSC.csproj @@ -12,6 +12,8 @@ PowerToys DSC PowerToys.DSC enable + + true From 1870fbb6e4fe437d480241b5fae1ccdbb5c4d533 Mon Sep 17 00:00:00 2001 From: "Kai Tao (from Dev Box)" Date: Wed, 3 Sep 2025 15:58:40 +0800 Subject: [PATCH 5/7] Add notice.md declaration --- NOTICE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NOTICE.md b/NOTICE.md index bedc11379d..7be74101de 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -1525,6 +1525,7 @@ SOFTWARE. - NLog - NLog.Extensions.Logging - NLog.Schema +- NJsonSchema - OpenAI - ReverseMarkdown - ScipBe.Common.Office.OneNote From 1e4e88eca0c0372282841e00d06fe6b3133b96bd Mon Sep 17 00:00:00 2001 From: "Kai Tao (from Dev Box)" Date: Wed, 3 Sep 2025 17:35:33 +0800 Subject: [PATCH 6/7] fix order --- NOTICE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NOTICE.md b/NOTICE.md index 7be74101de..03d8434c93 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -1522,10 +1522,10 @@ SOFTWARE. - ModernWpfUI - Moq - MSTest +- NJsonSchema - NLog - NLog.Extensions.Logging - NLog.Schema -- NJsonSchema - OpenAI - ReverseMarkdown - ScipBe.Common.Office.OneNote From f5f6f19bd5264223f8d50d1ea086ecf022e6938a Mon Sep 17 00:00:00 2001 From: vanzue Date: Wed, 3 Sep 2025 20:51:34 +0800 Subject: [PATCH 7/7] work around for not signed signature --- .pipelines/versionAndSignCheck.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.pipelines/versionAndSignCheck.ps1 b/.pipelines/versionAndSignCheck.ps1 index 1bb271300d..44295b84ff 100644 --- a/.pipelines/versionAndSignCheck.ps1 +++ b/.pipelines/versionAndSignCheck.ps1 @@ -53,6 +53,10 @@ $nullVersionExceptions = @( "Microsoft.Windows.Widgets.dll", "AdaptiveCards.ObjectModel.WinUI3.dll", "AdaptiveCards.Rendering.WinUI3.dll") -join '|'; +$signatureExceptions = @( + "Namotion.Reflection.dll", + "NJsonSchema.Annotations.dll", + "NJsonSchema.dll") -join '|'; $totalFailure = 0; Write-Host $DirPath; @@ -86,7 +90,7 @@ $items | ForEach-Object { } else { $auth = Get-AuthenticodeSignature $_.FullName - if ($auth.SignerCertificate -eq $null) { + if ($auth.SignerCertificate -eq $null -and $_.Name -notmatch $signatureExceptions) { Write-Host "Not Signed: " + $_.FullName $totalFailure++; }