Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Full fix for installation issue when My Documents on network drive #32799

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/actions/spell-check/patterns.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
81 changes: 35 additions & 46 deletions installer/PowerToysSetup/Core.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<DirectoryRef Id="INSTALLFOLDER" FileSource="$(var.BinDir)">
<Component Id="powertoys_per_machine_comp" Win64="yes">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys">
<RegistryValue Type="string" Name="InstallScope" Value="$(var.InstallScope)" />
<RegistryValue Type="string" Name="InstallScope" Value="$(var.InstallScope)" />
</RegistryKey>
</Component>
<Component Id="powertoys_toast_clsid" Win64="yes">
Expand Down Expand Up @@ -46,34 +46,19 @@
</Component>
</DirectoryRef>

<?if $(var.PerUser) = "true" ?>
<DirectoryRef Id="PersonalFolder">
<Directory Id="WindowsPowerShellFolder" Name="PowerShell">
<Directory Id="PowerShellModulesFolder" Name="Modules">
<Directory Id="PowerToysDscFolder" Name="Microsoft.PowerToys.Configure">
<Directory Id="PowerToysDscVerFolder" Name="$(var.Version)">
<Component Id="PowerToysDSC" Win64="yes" Guid="4A033E3B-6590-43FD-8FBD-27F9DF557F7F">
<RegistryValue Root="HKCU"
Key="Software\[Manufacturer]\[ProductName]"
Name="DSCInstalled"
Type="integer"
Value="1"
KeyPath="yes"/>
<!-- Don't fail installation because of DSC. Files are marked as not vital. -->
<File Vital="no" Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version)\Microsoft.PowerToys.Configure.psd1" Id="PTConf.psd1" />
<File Vital="no" Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version)\Microsoft.PowerToys.Configure.psm1" Id="PTConf.psm1" />
<RemoveFolder Id="RemoveThisFolder" On="uninstall" />
<RemoveFolder Id="RemovePowerToysDscVerFolder" Directory="PowerToysDscVerFolder" On="uninstall" />
<RemoveFolder Id="RemovePowerToysDscFolder" Directory="PowerToysDscFolder" On="uninstall" />
<RemoveFolder Id="RemovePowerShellModulesFolder" Directory="PowerShellModulesFolder" On="uninstall" />
<RemoveFolder Id="RemoveWindowsPowerShellFolder" Directory="WindowsPowerShellFolder" On="uninstall" />
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="DSCModulesReferenceFolder">
<Component Id="PowerToysDSCReference" Win64="yes" Guid="40869ACB-0BEB-4911-AE41-5E73BC1586A9">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="DSCModulesReference" Value="" KeyPath="yes"/>
</RegistryKey>
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version)\Microsoft.PowerToys.Configure.psd1" Id="PTConfReference.psd1" />
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version)\Microsoft.PowerToys.Configure.psm1" Id="PTConfReference.psm1" />
</Component>
</DirectoryRef>
<?else?>

<?if $(var.PerUser) = "true" ?>
<!-- DSC module files for PerUser handled in InstallDSCModule custom action. -->
<?else?>
<DirectoryRef Id="ProgramFiles64Folder">
<Directory Id="WindowsPowerShellFolder" Name="WindowsPowerShell">
<Directory Id="PowerShellModulesFolder" Name="Modules">
Expand All @@ -89,7 +74,7 @@
</Directory>
</Directory>
</DirectoryRef>
<?endif?>
<?endif?>

<DirectoryRef Id="ApplicationProgramsFolder">
<Component Id="PowerToysStartMenuShortcut" >
Expand Down Expand Up @@ -130,23 +115,27 @@
</Fragment>
<Fragment>
<ComponentGroup Id="CoreComponents">
<Component Id="RemoveCoreFolder" Guid="9330BD69-2D12-4D98-B0C7-66C99564D619" Directory="INSTALLFOLDER" >
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="RemoveCoreFolder" Value="" KeyPath="yes"/>
</RegistryKey>
<RemoveFolder Id="RemoveBaseApplicationsAssetsFolder" Directory="BaseApplicationsAssetsFolder" On="uninstall"/>
<RemoveFolder Id="RemoveWinUI3AppsInstallFolder" Directory="WinUI3AppsInstallFolder" On="uninstall"/>
<RemoveFolder Id="RemoveWinUI3AppsAssetsFolder" Directory="WinUI3AppsAssetsFolder" On="uninstall"/>
<RemoveFolder Id="RemoveINSTALLFOLDER" Directory="INSTALLFOLDER" On="uninstall"/>
</Component>
<ComponentRef Id="powertoys_exe" />
<ComponentRef Id="PowerToysStartMenuShortcut"/>
<ComponentRef Id="powertoys_per_machine_comp" />
<ComponentRef Id="powertoys_toast_clsid" />
<ComponentRef Id="License_rtf" />
<ComponentRef Id="Notice_md" />
<ComponentRef Id="DesktopShortcut" />
<ComponentRef Id="PowerToysDSC" />
<Component Id="RemoveCoreFolder" Guid="9330BD69-2D12-4D98-B0C7-66C99564D619" Directory="INSTALLFOLDER" >
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="RemoveCoreFolder" Value="" KeyPath="yes"/>
</RegistryKey>
<RemoveFolder Id="RemoveBaseApplicationsAssetsFolder" Directory="BaseApplicationsAssetsFolder" On="uninstall"/>
<RemoveFolder Id="RemoveDSCModulesReferenceFolder" Directory="DSCModulesReferenceFolder" On="uninstall"/>
<RemoveFolder Id="RemoveWinUI3AppsInstallFolder" Directory="WinUI3AppsInstallFolder" On="uninstall"/>
<RemoveFolder Id="RemoveWinUI3AppsAssetsFolder" Directory="WinUI3AppsAssetsFolder" On="uninstall"/>
<RemoveFolder Id="RemoveINSTALLFOLDER" Directory="INSTALLFOLDER" On="uninstall"/>
</Component>
<ComponentRef Id="powertoys_exe" />
<ComponentRef Id="PowerToysStartMenuShortcut"/>
<ComponentRef Id="powertoys_per_machine_comp" />
<ComponentRef Id="powertoys_toast_clsid" />
<ComponentRef Id="License_rtf" />
<ComponentRef Id="Notice_md" />
<ComponentRef Id="DesktopShortcut" />
<ComponentRef Id="PowerToysDSCReference" />
<?if $(var.PerUser) = "false" ?>
<ComponentRef Id="PowerToysDSC" />
<?endif?>
</ComponentGroup>
</Fragment>
</Wix>
39 changes: 34 additions & 5 deletions installer/PowerToysSetup/Product.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@
<Custom Action="SetLaunchPowerToysParam" Before="LaunchPowerToys" />
<Custom Action="SetUninstallCommandNotFoundParam" Before="UninstallCommandNotFound" />
<Custom Action="SetApplyModulesRegistryChangeSetsParam" Before="ApplyModulesRegistryChangeSets" />

<?if $(var.PerUser) = "true" ?>
<Custom Action="SetInstallDSCModuleParam" Before="InstallDSCModule" />
<?endif?>

<Custom Action="SetUnApplyModulesRegistryChangeSetsParam" Before="UnApplyModulesRegistryChangeSets" />
<Custom Action="CheckGPO" After="InstallInitialize">
NOT Installed
Expand All @@ -149,7 +154,10 @@
<!--<Custom Action="InstallEmbeddedMSIXTask" After="InstallFinalize">
NOT Installed
</Custom>-->
<Custom Action="TelemetryLogInstallSuccess" After="InstallFinalize">
<?if $(var.PerUser) = "true" ?>
<Custom Action="InstallDSCModule" After="InstallFiles"/>
<?endif?>
<Custom Action="TelemetryLogInstallSuccess" After="InstallFinalize">
NOT Installed
</Custom>
<Custom Action="TelemetryLogUninstallSuccess" After="InstallFinalize">
Expand All @@ -171,8 +179,12 @@
<!--<Custom Action="UninstallEmbeddedMSIXTask" After="InstallFinalize">
Installed AND (REMOVE="ALL")
</Custom>-->
<?if $(var.PerUser) = "true" ?>
<Custom Action="UninstallDSCModule" After="InstallFinalize">
Installed AND (REMOVE="ALL")
</Custom>
<?endif?>
<Custom Action="TerminateProcesses" Before="InstallValidate" />

<Custom Action="LaunchPowerToys" Before="InstallFinalize">NOT Installed</Custom>

</InstallExecuteSequence>
Expand Down Expand Up @@ -205,6 +217,10 @@
Property="UnApplyModulesRegistryChangeSets"
Value="[INSTALLFOLDER]" />

<CustomAction Id="SetInstallDSCModuleParam"
Property="InstallDSCModule"
Value="[INSTALLFOLDER]" />

<CustomAction Id="SetUninstallCommandNotFoundParam"
Property="UninstallCommandNotFound"
Value="[INSTALLFOLDER]" />
Expand Down Expand Up @@ -255,6 +271,21 @@
DllEntry="UninstallEmbeddedMSIXCA"
/>

<CustomAction Id="InstallDSCModule"
Return="ignore"
Impersonate="yes"
Execute="deferred"
BinaryKey="PTCustomActions"
DllEntry="InstallDSCModuleCA"
/>

<CustomAction Id="UninstallDSCModule"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question, if Execute is deferred for one of them, why isn't it also for the other one?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InstallDSCModuleCA needs to know the location of the install folder to be able to copy the DSC files. For this, I use the getInstallFolder helper function. This requires a deferred custom action with a separate custom action to set the parameter.

UninstallDSCModuleCA doesn't need this, so I left it as it is (default=Immediate I believe). I suppose it would still work as a deferred custom action, but I would have to retest it :)

Return="ignore"
Impersonate="yes"
BinaryKey="PTCustomActions"
DllEntry="UninstallDSCModuleCA"
/>

<CustomAction Id="UninstallServicesTask"
Return="ignore"
Impersonate="yes"
Expand Down Expand Up @@ -381,6 +412,7 @@
<Directory Id="INSTALLFOLDER" Name="PowerToys">
<Directory Id="BaseApplicationsAssetsFolder" Name="Assets">
</Directory>
<Directory Id="DSCModulesReferenceFolder" Name="DSCModules" />
<Directory Id="WinUI3AppsInstallFolder" Name="WinUI3Apps">
<Directory Id="WinUI3AppsMicrosoftUIXamlInstallFolder" Name="Microsoft.UI.Xaml">
<Directory Id="WinUI3AppsMicrosoftUIXamlAssetsInstallFolder" Name="Assets" />
Expand All @@ -395,9 +427,6 @@
<Directory Id="ApplicationProgramsFolder" Name="PowerToys (Preview)"/>
</Directory>
<Directory Id="DesktopFolder" Name="Desktop" />
<?if $(var.PerUser) = "true" ?>
<Directory Id="PersonalFolder" Name="UserHomeDocuments" />
<?endif?>
</Directory>
</Fragment>
</Wix>
138 changes: 137 additions & 1 deletion installer/PowerToysSetupCustomActions/CustomAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,23 @@ BOOL ImpersonateLoggedInUserAndDoSomething(std::function<bool(HANDLE userToken)>
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;
Expand All @@ -161,7 +178,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;
Expand Down Expand Up @@ -316,6 +333,125 @@ UINT __stdcall UnApplyModulesRegistryChangeSetsCA(MSIHANDLE hInstall)
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;
Expand Down
2 changes: 2 additions & 0 deletions installer/PowerToysSetupCustomActions/CustomAction.def
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ EXPORTS
CertifyVirtualCameraDriverCA
InstallVirtualCameraDriverCA
InstallEmbeddedMSIXCA
InstallDSCModuleCA
UnApplyModulesRegistryChangeSetsCA
UninstallVirtualCameraDriverCA
UnRegisterContextMenuPackagesCA
UninstallEmbeddedMSIXCA
UninstallDSCModuleCA
UninstallServicesCA
UninstallCommandNotFoundModuleCA
Loading