Search code examples
wixuaccustom-action

WiX: make symbolic link with UAC enabled


I want to execute a custom action in a Windows Installer (with WiX script) that makes symbolic links at the end of installation. mklink requires administrator privilege, as the installer restricts. This is what I wrote:

<CustomAction Id="mklink_cmdline" Property="QtExecCmdLine" Value='"[SystemFolder]cmd.exe" /c mklink "[SystemFolder]my_app.dll" "[INSTALLDIR]my_app.dll"' />
<CustomAction Id="mklink_exec" BinaryKey="WixCA" DllEntry="CAQuietExec" Return="ignore" />

...

<InstallExecuteSequence>
    <Custom Action="mklink_cmdline" Before="InstallFinalize">
        ...
    </Custom>
    <Custom Action="mklink_exec" After="mklink_cmdline">
        ...
    </Custom>
    ...
</InstallExecuteSequence>

This works perfectly if UAC is completely disabled. However, when enabling UAC in any level, this custom action fails with

CAQuietExec:  You do not have sufficient privilege to perform this operation.

even if I allowed in the consent window. I tried to change Execute to deferred, Impersonate to no, or change package's InstallPrivileges to elevated, none of them works.

Any suggestion I can bypass? Thank you!

Edit: revised code with deferred custom action

<CustomAction Id="mklink_cmdline" Property="mklink_exec" Value='"[SystemFolder]cmd.exe" /c mklink "[SystemFolder]my_app.dll" "[INSTALLDIR]my_app.dll"' />
<CustomAction Id="mklink_exec" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="deferred" Impersonate="no" Return="ignore" />

...

<InstallExecuteSequence>
    <Custom Action="mklink_exec" Before="InstallFinalize">
        ...
    </Custom>
    <Custom Action="mklink_cmdline" Before="mklink_exec">
        ...
    </Custom>
    ...
</InstallExecuteSequence>

Solution

  • Does it work when ran from an administrator command prompt? I assume it does.

    From what I found the msi cannot raise the UAC level which is what you need here. I had to create a setup.exe that wrapped the msi as an embedded resource and executed it. The setup.exe includes the app.manifest requesting administrator execution level which raises the UAC level appropriately:

    <?xml version="1.0" encoding="utf-8"?>
    <asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <assemblyIdentity version="1.0.0.0" name="Setup.app"/>
        <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
            <security>
                <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
                    <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
                </requestedPrivileges>
            </security>
        </trustInfo>
    </asmv1:assembly>
    

    I may just not understand WIX, custom actions and UAC enough, but this is what I ended up doing.