I'm trying to run PowerShell in admin using ShellExecute within a Qt program, but the arguments don't seem to be transferring.
QString ruleName = QCoreApplication::applicationName();
QString exePath = QCoreApplication::applicationFilePath();
// Define the embedded PowerShell scripts as strings
const QString checkFirewallScript = QString(
"param([string]$ruleName,[string]$exePath)"
"a powershell script of 70 lines"
).arg(ruleName, exePath);
// Construct the PowerShell command with the script
QString command = QString("powershell.exe -Command \"%1\"").arg(checkFirewallScript);
// Convert the command to a wide string
LPCWSTR commandC = (const wchar_t*) command.utf16();
// Use ShellExecute to run the command as administrator
HINSTANCE exitCode = ShellExecute(NULL, L"runas", L"powershell.exe", commandC, NULL, SW_SHOWNORMAL);
My exit code is always 42 though I read where above 32, it is just the instance number. I get a warning within the Qt error box of "QString::arg: 2 argument(s) missing in" and it spits out the script. I have no percent signs and the script works in powershell by itself (when I add the 2 "missing" arguments directly to script). This also worked without issue when I was using Qt Process, but I want UAC to be invoked so I am using ShellExecute (which is ShellExecuteW according to headers).
// Get the application file path and name
QString ruleName = QCoreApplication::applicationName();
QString exePath = QCoreApplication::applicationFilePath();
// Define the embedded PowerShell scripts as strings
const QString checkFirewallScript = R"(param(
[Parameter(Mandatory=$true)][string]$ruleName,
[Parameter(Mandatory=$true)][string]$exePath
)
$rules = Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue |
...
)";
// Construct the command to run PowerShell with the script
QString command = QString("-ExecutionPolicy Bypass -F \"%1\" -ruleName \"%2\" -exePath \"%3\"")
.arg(tempScriptPath)
.arg(ruleName)
.arg(exePath);
// Convert the command to a wide string
std::wstring commandW = command.toStdWString();
// Initialize the SHELLEXECUTEINFO structure
SHELLEXECUTEINFOW sei = {0};
sei.cbSize = sizeof(SHELLEXECUTEINFOW);
sei.fMask = SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS;
sei.hwnd = NULL;
sei.lpVerb = L"runas";
sei.lpFile = L"powershell.exe";
sei.lpParameters = commandW.c_str();;
sei.lpDirectory = NULL;
sei.nShow = SW_SHOWNORMAL;
sei.hInstApp = NULL;
//run
if (!ShellExecuteExW(&sei)) { ...
WaitForSingleObject(sei.hProcess, 10000); // 10 seconds
DWORD exitCode;
GetExitCodeProcess(sei.hProcess, &exitCode);
CloseHandle(sei.hProcess);
if (exitCode == 18000) {
It took a bit of doing, had to forgo running the entire script as an argument because I kept encountering too many issues. This lets me run powershell in its own window while also requesting admin permissions to do some firewall maintenance. Thanks to
IInspectable for reccomending ShellExecuteExW, I can do custom error codes in the script. I didn't post the entire script + function, but this represents the good parts.