Skip to content

Commit

Permalink
[Setup] Always elevate bootstrapper to avoid multiple UAC prompts on …
Browse files Browse the repository at this point in the history
…upgrade
  • Loading branch information
yuyoyuppe committed Oct 22, 2021
1 parent 79aba4e commit cd2b303
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 55 deletions.
9 changes: 7 additions & 2 deletions .github/actions/spell-check/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ CANRENAME
Captureascreenshot
CAPTURECHANGED
CASESENSITIVE
cassert
CAtl
CCDDEE
ccf
Expand All @@ -222,6 +223,8 @@ cfg
cguid
changecursor
Changemove
changeset
Changset
charconv
charset
chdir
Expand Down Expand Up @@ -999,7 +1002,6 @@ IRepository
IResult
ISavable
isbi
iss
ISearch
IService
isetting
Expand All @@ -1008,6 +1010,7 @@ IShell
ISingle
ISmart
isocpp
iss
IStorage
IStream
istreambuf
Expand All @@ -1018,9 +1021,9 @@ ITab
ITask
ITemplate
ITEMSTATEICONCLICK
ITerminal
ITest
ith
ITerminal
IThrottled
IThumbnail
ITrigger
Expand Down Expand Up @@ -1327,6 +1330,7 @@ msedge
MSGFLT
mshtmdid
msi
msiexec
MSIFASTINSTALL
MSIHANDLE
MSIINSTALLER
Expand Down Expand Up @@ -2189,6 +2193,7 @@ ULLONG
ulong
ULONGLONG
umd
unapply
unchecks
uncomment
uncompilable
Expand Down
107 changes: 54 additions & 53 deletions installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,51 @@ std::optional<InstalledVersionInfo> get_installed_powertoys_version()
};
}

void ReLaunchElevatedAndExit()
{
std::wstring params;
int nCmdArgs = 0;
LPWSTR* argList = CommandLineToArgvW(GetCommandLineW(), &nCmdArgs);
for (int i = 1; i < nCmdArgs; ++i)
{
if (std::wstring_view{ argList[i] }.find(L' ') != std::wstring_view::npos)
{
params += L'"';
params += argList[i];
params += L'"';
}
else
{
params += argList[i];
}

if (i != nCmdArgs - 1)
{
params += L' ';
}
}

const auto processHandle = run_elevated(argList[0], params.c_str());
if (!processHandle)
{
spdlog::error("Couldn't restart elevated: ({})", GetLastError());
return;
}

if (WaitForSingleObject(processHandle, 3600000) == WAIT_OBJECT_0)
{
DWORD exitCode = 0;
GetExitCodeProcess(processHandle, &exitCode);
std::exit(exitCode);
}
else
{
spdlog::error("Elevated setup process timed out after 60m: ({})", GetLastError());
TerminateProcess(processHandle, 0);
std::exit(1);
}
}

int Bootstrapper(HINSTANCE hInstance)
{
winrt::init_apartment();
Expand Down Expand Up @@ -299,66 +344,22 @@ int Bootstrapper(HINSTANCE hInstance)
}
}

// Setup MSI UI visibility and restart as elevated if required
// Always elevate bootstrapper process since it invokes msiexec multiple times,
// so we can avoid multiple UAC confirmations
if (!is_process_elevated())
{
ReLaunchElevatedAndExit();
}

// Setup MSI UI visibility
if (!noFullUI)
{
MsiSetInternalUI(INSTALLUILEVEL_FULL, nullptr);
}

if (g_Silent)
{
if (is_process_elevated())
{
MsiSetInternalUI(INSTALLUILEVEL_NONE, nullptr);
}
else
{
spdlog::debug("MSI doesn't support silent mode without elevation => restarting elevated");
// MSI fails to run in silent mode due to a suppressed UAC w/o elevation,
// so we restart ourselves elevated with the same args
std::wstring params;
int nCmdArgs = 0;
LPWSTR* argList = CommandLineToArgvW(GetCommandLineW(), &nCmdArgs);
for (int i = 1; i < nCmdArgs; ++i)
{
if (std::wstring_view{ argList[i] }.find(L' ') != std::wstring_view::npos)
{
params += L'"';
params += argList[i];
params += L'"';
}
else
{
params += argList[i];
}

if (i != nCmdArgs - 1)
{
params += L' ';
}
}

const auto processHandle = run_elevated(argList[0], params.c_str());
if (!processHandle)
{
spdlog::error("Couldn't restart elevated to enable silent mode! ({})", GetLastError());
return 1;
}

if (WaitForSingleObject(processHandle, 3600000) == WAIT_OBJECT_0)
{
DWORD exitCode = 0;
GetExitCodeProcess(processHandle, &exitCode);
return exitCode;
}
else
{
spdlog::error("Elevated setup process timed out after 60m => using basic MSI UI ({})", GetLastError());
// Couldn't install using the completely silent mode in an hour, use basic UI.
TerminateProcess(processHandle, 0);
MsiSetInternalUI(INSTALLUILEVEL_BASIC, nullptr);
}
}
MsiSetInternalUI(INSTALLUILEVEL_NONE, nullptr);
}

// Try killing PowerToys and prevent future processes launch by acquiring app mutex
Expand Down

0 comments on commit cd2b303

Please sign in to comment.