diff --git a/.github/actions/spell-check/patterns.txt b/.github/actions/spell-check/patterns.txt index d48cec9abd..c56e5fbb14 100644 --- a/.github/actions/spell-check/patterns.txt +++ b/.github/actions/spell-check/patterns.txt @@ -40,6 +40,9 @@ # tabs in c# \$"\\t +# Hexadecimal character pattern in code +\\x[0-9a-fA-F][0-9a-fA-F] + # windows line breaks in strings \\r\\n diff --git a/installer/PowerToysSetup/Core.wxs b/installer/PowerToysSetup/Core.wxs index 6254bd99ed..81a655b3e1 100644 --- a/installer/PowerToysSetup/Core.wxs +++ b/installer/PowerToysSetup/Core.wxs @@ -8,7 +8,7 @@ - + @@ -46,34 +46,19 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - + + + + @@ -89,7 +74,7 @@ - + @@ -130,23 +115,27 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/installer/PowerToysSetup/Product.wxs b/installer/PowerToysSetup/Product.wxs index aab1ed1520..22940acbb5 100644 --- a/installer/PowerToysSetup/Product.wxs +++ b/installer/PowerToysSetup/Product.wxs @@ -136,6 +136,11 @@ + + + + + NOT Installed @@ -149,7 +154,10 @@ - + + + + NOT Installed @@ -177,8 +185,12 @@ + + + Installed AND (REMOVE="ALL") + + - NOT Installed @@ -211,6 +223,10 @@ Property="UnApplyModulesRegistryChangeSets" Value="[INSTALLFOLDER]" /> + + @@ -265,6 +281,21 @@ DllEntry="UninstallEmbeddedMSIXCA" /> + + + + + @@ -421,9 +453,6 @@ - - - diff --git a/installer/PowerToysSetupCustomActions/CustomAction.cpp b/installer/PowerToysSetupCustomActions/CustomAction.cpp index 62eebfd0c1..de366e5079 100644 --- a/installer/PowerToysSetupCustomActions/CustomAction.cpp +++ b/installer/PowerToysSetupCustomActions/CustomAction.cpp @@ -139,6 +139,23 @@ LExit: return SUCCEEDED(hr); } +static std::filesystem::path GetUserPowerShellModulesPath() +{ + PWSTR myDocumentsBlockPtr; + + if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &myDocumentsBlockPtr))) + { + const std::wstring myDocuments{ myDocumentsBlockPtr }; + CoTaskMemFree(myDocumentsBlockPtr); + return std::filesystem::path(myDocuments) / "PowerShell" / "Modules"; + } + else + { + CoTaskMemFree(myDocumentsBlockPtr); + return {}; + } +} + UINT __stdcall LaunchPowerToysCA(MSIHANDLE hInstall) { HRESULT hr = S_OK; @@ -162,7 +179,7 @@ UINT __stdcall LaunchPowerToysCA(MSIHANDLE hInstall) BOOL isSystemUser = IsLocalSystem(); if (isSystemUser) { - + auto action = [&commandLine](HANDLE userToken) { STARTUPINFO startupInfo{ .cb = sizeof(STARTUPINFO), .wShowWindow = SW_SHOWNORMAL }; PROCESS_INFORMATION processInformation; @@ -317,6 +334,125 @@ LExit: 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"; + +UINT __stdcall InstallDSCModuleCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + std::wstring installationFolder; + + hr = WcaInitialize(hInstall, "InstallDSCModuleCA"); + ExitOnFailure(hr, "Failed to initialize"); + + hr = getInstallFolder(hInstall, installationFolder); + ExitOnFailure(hr, "Failed to get installFolder."); + + { + const auto baseModulesPath = GetUserPowerShellModulesPath(); + if (baseModulesPath.empty()) + { + hr = E_FAIL; + ExitOnFailure(hr, "Unable to determine Powershell modules path"); + } + + const auto modulesPath = baseModulesPath / L"Microsoft.PowerToys.Configure" / get_product_version(); + + std::error_code errorCode; + fs::create_directories(modulesPath, errorCode); + if (errorCode) + { + hr = E_FAIL; + ExitOnFailure(hr, "Unable to create Powershell modules folder"); + } + + 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); + + if (errorCode) + { + hr = E_FAIL; + ExitOnFailure(hr, "Unable to copy Powershell modules file"); + } + } + } + +LExit: + if (SUCCEEDED(hr)) + { + er = ERROR_SUCCESS; + Logger::info(L"DSC module was installed!"); + } + else + { + er = ERROR_INSTALL_FAILURE; + Logger::error(L"Couldn't install DSC module!"); + } + + return WcaFinalize(er); +} + +UINT __stdcall UninstallDSCModuleCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "UninstallDSCModuleCA"); + ExitOnFailure(hr, "Failed to initialize"); + + { + const auto baseModulesPath = GetUserPowerShellModulesPath(); + if (baseModulesPath.empty()) + { + hr = E_FAIL; + ExitOnFailure(hr, "Unable to determine Powershell modules path"); + } + + const auto powerToysModulePath = baseModulesPath / L"Microsoft.PowerToys.Configure"; + const auto versionedModulePath = powerToysModulePath / get_product_version(); + + std::error_code errorCode; + + for (const auto* filename : { DSC_CONFIGURE_PSD1_NAME, DSC_CONFIGURE_PSM1_NAME }) + { + fs::remove(versionedModulePath / filename, errorCode); + + if (errorCode) + { + hr = E_FAIL; + ExitOnFailure(hr, "Unable to delete DSC file"); + } + } + + for (const auto* modulePath : { &versionedModulePath, &powerToysModulePath }) + { + fs::remove(*modulePath, errorCode); + + if (errorCode) + { + hr = E_FAIL; + ExitOnFailure(hr, "Unable to delete DSC folder"); + } + } + } + +LExit: + if (SUCCEEDED(hr)) + { + er = ERROR_SUCCESS; + Logger::info(L"DSC module was uninstalled!"); + } + else + { + er = ERROR_INSTALL_FAILURE; + Logger::error(L"Couldn't uninstall DSC module!"); + } + + return WcaFinalize(er); +} + UINT __stdcall InstallEmbeddedMSIXCA(MSIHANDLE hInstall) { HRESULT hr = S_OK; diff --git a/installer/PowerToysSetupCustomActions/CustomAction.def b/installer/PowerToysSetupCustomActions/CustomAction.def index a7d2f68f72..f685a0be1d 100644 --- a/installer/PowerToysSetupCustomActions/CustomAction.def +++ b/installer/PowerToysSetupCustomActions/CustomAction.def @@ -18,10 +18,12 @@ EXPORTS CertifyVirtualCameraDriverCA InstallVirtualCameraDriverCA InstallEmbeddedMSIXCA + InstallDSCModuleCA UnApplyModulesRegistryChangeSetsCA UninstallVirtualCameraDriverCA UnRegisterContextMenuPackagesCA UninstallEmbeddedMSIXCA + UninstallDSCModuleCA UninstallServicesCA UninstallCommandNotFoundModuleCA UpgradeCommandNotFoundModuleCA