Merge branch 'dev/vanzue/fork-dsc' into user/amelbawa/dsc

This commit is contained in:
vanzue
2025-09-03 23:51:57 +08:00
9 changed files with 226 additions and 9 deletions

View File

@@ -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++;
}

View File

@@ -1522,6 +1522,7 @@ SOFTWARE.
- ModernWpfUI
- Moq
- MSTest
- NJsonSchema
- NLog
- NLog.Extensions.Logging
- NLog.Schema

View File

@@ -191,6 +191,11 @@
<Custom Action="UnRegisterCmdPalPackage" Before="RemoveFiles">
Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
</Custom>
<!-- Delete *.dsc.json files during uninstall (best-effort) -->
<Custom Action="SetDeleteDscJsonFilesParam" Before="DeleteDscJsonFiles" />
<Custom Action="DeleteDscJsonFiles" Before="RemoveFiles">
Installed AND (REMOVE="ALL")
</Custom>
<Custom Action="UnsetAdvancedPasteAPIKey" Before="RemoveFiles">
Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
</Custom>
@@ -252,6 +257,11 @@
Property="UnApplyModulesRegistryChangeSets"
Value="[INSTALLFOLDER]" />
<!-- Pass install folder to deferred delete action -->
<CustomAction Id="SetDeleteDscJsonFilesParam"
Property="DeleteDscJsonFiles"
Value="[INSTALLFOLDER]" />
<CustomAction Id="SetInstallDSCModuleParam"
Property="InstallDSCModule"
Value="[INSTALLFOLDER]" />
@@ -325,6 +335,15 @@
DllEntry="UninstallDSCModuleCA"
/>
<!-- Best-effort delete of *.dsc.json during uninstall -->
<CustomAction Id="DeleteDscJsonFiles"
Return="ignore"
Impersonate="yes"
Execute="deferred"
BinaryKey="PTCustomActions"
DllEntry="DeleteDscJsonFilesCA"
/>
<CustomAction Id="UninstallServicesTask"
Return="ignore"
Impersonate="yes"

View File

@@ -398,6 +398,54 @@ LExit:
return WcaFinalize(er);
}
// Delete any *.dsc.json files under the install folder on uninstall (legacy installer)
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 {}", 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";

View File

@@ -20,6 +20,7 @@ EXPORTS
InstallDSCModuleCA
InstallCmdPalPackageCA
UnApplyModulesRegistryChangeSetsCA
DeleteDscJsonFilesCA
UnRegisterCmdPalPackageCA
UnRegisterContextMenuPackagesCA
UninstallEmbeddedMSIXCA

View File

@@ -3,6 +3,7 @@
#include "RcResource.h"
#include <ProjectTelemetry.h>
#include <spdlog/sinks/base_sink.h>
#include <filesystem>
#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;
@@ -398,6 +403,130 @@ 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;
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");
hr = getInstallFolder(hInstall, installationFolder);
ExitOnFailure(hr, "Failed to get installFolder.");
// Build executable path: <INSTALLFOLDER>\PowerToys.DSC.exe
exePath = installationFolder + L"\\PowerToys.DSC.exe";
// Build args: manifest --resource settings --outputDir "<INSTALLFOLDER>"
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.cb = sizeof(STARTUPINFO);
startupInfo.wShowWindow = SW_HIDE;
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);
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";
@@ -424,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;
@@ -433,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)
{
@@ -481,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)
{
@@ -492,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)
{

View File

@@ -32,4 +32,5 @@ EXPORTS
CleanFileLocksmithRuntimeRegistryCA
CleanPowerRenameRuntimeRegistryCA
CleanNewPlusRuntimeRegistryCA
GenerateDscManifestCA
DeleteDscJsonFilesCA

View File

@@ -119,6 +119,8 @@
<Custom Action="CheckGPO" After="InstallInitialize" Condition="NOT Installed" />
<Custom Action="ApplyModulesRegistryChangeSets" After="InstallFiles" Condition="NOT Installed" />
<Custom Action="InstallCmdPalPackage" After="InstallFiles" Condition="NOT Installed" />
<Custom Action="SetGenerateDscManifestParam" Before="GenerateDscManifest" />
<Custom Action="GenerateDscManifest" After="InstallFiles" Condition="NOT Installed AND NOT WIX_UPGRADE_DETECTED" />
<Custom Action="override Wix4CloseApplications_$(sys.BUILDARCHSHORT)" Before="RemoveFiles" />
<Custom Action="RemovePowerToysSchTasks" After="RemoveFiles" />
<!-- TODO: Use to activate embedded MSIX -->
@@ -132,6 +134,8 @@
<Custom Action="TelemetryLogUninstallSuccess" After="InstallFinalize" Condition="Installed and (NOT UPGRADINGPRODUCTCODE) AND (REMOVE=&quot;ALL&quot;)" />
<Custom Action="UnApplyModulesRegistryChangeSets" Before="RemoveFiles" Condition="Installed AND (REMOVE=&quot;ALL&quot;)" />
<Custom Action="UnRegisterContextMenuPackages" Before="RemoveFiles" Condition="Installed AND (REMOVE=&quot;ALL&quot;)" />
<Custom Action="SetDeleteDscJsonFilesParam" Before="DeleteDscJsonFiles" Condition="Installed AND (REMOVE=&quot;ALL&quot;)" />
<Custom Action="DeleteDscJsonFiles" Before="RemoveFiles" Condition="Installed AND (REMOVE=&quot;ALL&quot;)" />
<Custom Action="CleanImageResizerRuntimeRegistry" Before="RemoveFiles" Condition="Installed AND (REMOVE=&quot;ALL&quot;)" />
<Custom Action="CleanFileLocksmithRuntimeRegistry" Before="RemoveFiles" Condition="Installed AND (REMOVE=&quot;ALL&quot;)" />
<Custom Action="CleanPowerRenameRuntimeRegistry" Before="RemoveFiles" Condition="Installed AND (REMOVE=&quot;ALL&quot;)" />
@@ -244,6 +248,14 @@
<CustomAction Id="InstallCmdPalPackage" Return="ignore" Impersonate="yes" Execute="deferred" DllEntry="InstallCmdPalPackageCA" BinaryRef="PTCustomActions" />
<!-- Generate DSC manifests by invoking PowerToys.DSC.exe during install -->
<CustomAction Id="SetGenerateDscManifestParam" Property="GenerateDscManifest" Value="[INSTALLFOLDER]" />
<CustomAction Id="GenerateDscManifest" Return="ignore" Impersonate="yes" Execute="deferred" DllEntry="GenerateDscManifestCA" BinaryRef="PTCustomActions" />
<!-- Delete *.dsc.json files on uninstall -->
<CustomAction Id="SetDeleteDscJsonFilesParam" Property="DeleteDscJsonFiles" Value="[INSTALLFOLDER]" />
<CustomAction Id="DeleteDscJsonFiles" Return="ignore" Impersonate="yes" Execute="deferred" DllEntry="DeleteDscJsonFilesCA" BinaryRef="PTCustomActions" />
<!-- Close 'PowerToys.exe' before uninstall-->
<Property Id="MSIRESTARTMANAGERCONTROL" Value="DisableShutdown" />
<Property Id="MSIFASTINSTALL" Value="DisableShutdown" />

View File

@@ -12,6 +12,8 @@
<AssemblyDescription>PowerToys DSC</AssemblyDescription>
<RootNamespace>PowerToys.DSC</RootNamespace>
<Nullable>enable</Nullable>
<!-- Ensure WindowsDesktop runtime pack is included for consistent WindowsBase.dll version -->
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
@@ -39,7 +41,7 @@
</ItemGroup>
<!-- In debug mode, generate the DSC resource JSON files -->
<Target Name="GenerateDscResourceJsonFiles" AfterTargets="Build">
<Target Name="GenerateDscResourceJsonFiles" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
<Message Text="Generating DSC resource JSON files inside ..." Importance="high" />
<Exec Command="dotnet &quot;$(TargetPath)&quot; manifest --resource settings --outputDir &quot;$(TargetDir)\&quot;" />
</Target>