mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-15 03:07:56 +01:00
Remove CreateScheduledTask CA and handle task creation from runner code (#27819)
* Refactor to avoid code duplication * Remove CreateScheduledTask CA * Update installer/PowerToysSetupCustomActions/CustomAction.cpp Co-authored-by: Andrey Nekrasov <yuyoyuppe@users.noreply.github.com> * Update installer/PowerToysSetupCustomActions/CustomAction.cpp Co-authored-by: Andrey Nekrasov <yuyoyuppe@users.noreply.github.com> --------- Co-authored-by: Andrey Nekrasov <yuyoyuppe@users.noreply.github.com>
This commit is contained in:
@@ -112,7 +112,6 @@
|
|||||||
<WixVariable Id="WixUIDialogBmp" Value="$(var.ProjectDir)\Images\dialog.png" />
|
<WixVariable Id="WixUIDialogBmp" Value="$(var.ProjectDir)\Images\dialog.png" />
|
||||||
<WixVariable Id="WixUILicenseRtf" Value="$(var.RepoDir)\installer\License.rtf" />
|
<WixVariable Id="WixUILicenseRtf" Value="$(var.RepoDir)\installer\License.rtf" />
|
||||||
<Property Id="INSTALLSTARTMENUSHORTCUT" Value="1"/>
|
<Property Id="INSTALLSTARTMENUSHORTCUT" Value="1"/>
|
||||||
<Property Id="CREATESCHEDULEDTASK" Value="1"/>
|
|
||||||
<Property Id="WixShellExecTarget" Value="[#PowerToys_ActionRunner.exe]" />
|
<Property Id="WixShellExecTarget" Value="[#PowerToys_ActionRunner.exe]" />
|
||||||
|
|
||||||
<SetProperty Action="SetDEFAULTBOOTSTRAPPERINSTALLFOLDER" Id="DEFAULTBOOTSTRAPPERINSTALLFOLDER" Value="[$(var.DefaultInstallDir)]PowerToys" Before="SetBOOTSTRAPPERINSTALLFOLDER" Sequence="execute"></SetProperty>
|
<SetProperty Action="SetDEFAULTBOOTSTRAPPERINSTALLFOLDER" Id="DEFAULTBOOTSTRAPPERINSTALLFOLDER" Value="[$(var.DefaultInstallDir)]PowerToys" Before="SetBOOTSTRAPPERINSTALLFOLDER" Sequence="execute"></SetProperty>
|
||||||
@@ -132,13 +131,9 @@
|
|||||||
<SetProperty Id="InstallScope" Value="$(var.InstallScope)" Before="DetectPrevInstallPath" Sequence="execute"></SetProperty>
|
<SetProperty Id="InstallScope" Value="$(var.InstallScope)" Before="DetectPrevInstallPath" Sequence="execute"></SetProperty>
|
||||||
<InstallExecuteSequence>
|
<InstallExecuteSequence>
|
||||||
<Custom Action="DetectPrevInstallPath" After="AppSearch" />
|
<Custom Action="DetectPrevInstallPath" After="AppSearch" />
|
||||||
<Custom Action="SetRegisterPowerToysSchTaskParam" Before="RegisterPowerToysSchTask" />
|
|
||||||
<Custom Action="SetLaunchPowerToysParam" Before="LaunchPowerToys" />
|
<Custom Action="SetLaunchPowerToysParam" Before="LaunchPowerToys" />
|
||||||
<Custom Action="SetApplyModulesRegistryChangeSetsParam" Before="ApplyModulesRegistryChangeSets" />
|
<Custom Action="SetApplyModulesRegistryChangeSetsParam" Before="ApplyModulesRegistryChangeSets" />
|
||||||
<Custom Action="SetUnApplyModulesRegistryChangeSetsParam" Before="UnApplyModulesRegistryChangeSets" />
|
<Custom Action="SetUnApplyModulesRegistryChangeSetsParam" Before="UnApplyModulesRegistryChangeSets" />
|
||||||
<Custom Action="RegisterPowerToysSchTask" After="InstallFiles">
|
|
||||||
NOT Installed and CREATESCHEDULEDTASK = 1
|
|
||||||
</Custom>
|
|
||||||
<Custom Action="CheckGPO" After="InstallInitialize">
|
<Custom Action="CheckGPO" After="InstallInitialize">
|
||||||
NOT Installed
|
NOT Installed
|
||||||
</Custom>
|
</Custom>
|
||||||
@@ -196,10 +191,6 @@
|
|||||||
BinaryKey="PTCustomActions"
|
BinaryKey="PTCustomActions"
|
||||||
DllEntry="TerminateProcessesCA" />
|
DllEntry="TerminateProcessesCA" />
|
||||||
|
|
||||||
<CustomAction Id="SetRegisterPowerToysSchTaskParam"
|
|
||||||
Property="RegisterPowerToysSchTask"
|
|
||||||
Value="[INSTALLFOLDER]PowerToys.exe" />
|
|
||||||
|
|
||||||
<CustomAction Id="SetApplyModulesRegistryChangeSetsParam"
|
<CustomAction Id="SetApplyModulesRegistryChangeSetsParam"
|
||||||
Property="ApplyModulesRegistryChangeSets"
|
Property="ApplyModulesRegistryChangeSets"
|
||||||
Value="[INSTALLFOLDER]" />
|
Value="[INSTALLFOLDER]" />
|
||||||
@@ -232,15 +223,6 @@
|
|||||||
Property="DeleteDotnetRuntimeHardlinks"
|
Property="DeleteDotnetRuntimeHardlinks"
|
||||||
Value="[INSTALLFOLDER]" />
|
Value="[INSTALLFOLDER]" />
|
||||||
|
|
||||||
<!-- Needs to Impersonate="no" and Execute="deferred" in order to run elevated. -->
|
|
||||||
<CustomAction Id="RegisterPowerToysSchTask"
|
|
||||||
Return="ignore"
|
|
||||||
Impersonate="no"
|
|
||||||
Execute="deferred"
|
|
||||||
BinaryKey="PTCustomActions"
|
|
||||||
DllEntry="CreateScheduledTaskCA"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<CustomAction Id="RemovePowerToysSchTasks"
|
<CustomAction Id="RemovePowerToysSchTasks"
|
||||||
Return="ignore"
|
Return="ignore"
|
||||||
Impersonate="no"
|
Impersonate="no"
|
||||||
|
|||||||
@@ -93,6 +93,51 @@ BOOL IsLocalSystem()
|
|||||||
return bSystem;
|
return bSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL ImpersonateLoggedInUserAndDoSomething(std::function<bool(HANDLE userToken)> action)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
HANDLE hUserToken = NULL;
|
||||||
|
DWORD dwSessionId;
|
||||||
|
ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId);
|
||||||
|
auto rv = WTSQueryUserToken(dwSessionId, &hUserToken);
|
||||||
|
|
||||||
|
if (rv == 0)
|
||||||
|
{
|
||||||
|
hr = E_ABORT;
|
||||||
|
ExitOnFailure(hr, "Failed to query user token");
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE hUserTokenDup;
|
||||||
|
if (DuplicateTokenEx(hUserToken, TOKEN_ALL_ACCESS, NULL, SECURITY_IMPERSONATION_LEVEL::SecurityImpersonation, TOKEN_TYPE::TokenPrimary, &hUserTokenDup) == 0)
|
||||||
|
{
|
||||||
|
CloseHandle(hUserToken);
|
||||||
|
CloseHandle(hUserTokenDup);
|
||||||
|
hr = E_ABORT;
|
||||||
|
ExitOnFailure(hr, "Failed to duplicate user token");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImpersonateLoggedOnUser(hUserTokenDup))
|
||||||
|
{
|
||||||
|
if (!action(hUserTokenDup))
|
||||||
|
{
|
||||||
|
hr = E_ABORT;
|
||||||
|
ExitOnFailure(hr, "Failed to execute action");
|
||||||
|
}
|
||||||
|
|
||||||
|
RevertToSelf();
|
||||||
|
CloseHandle(hUserToken);
|
||||||
|
CloseHandle(hUserTokenDup);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hr = E_ABORT;
|
||||||
|
ExitOnFailure(hr, "Failed to duplicate user token");
|
||||||
|
}
|
||||||
|
|
||||||
|
LExit:
|
||||||
|
return SUCCEEDED(hr);
|
||||||
|
}
|
||||||
|
|
||||||
UINT __stdcall LaunchPowerToysCA(MSIHANDLE hInstall)
|
UINT __stdcall LaunchPowerToysCA(MSIHANDLE hInstall)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
@@ -117,34 +162,15 @@ UINT __stdcall LaunchPowerToysCA(MSIHANDLE hInstall)
|
|||||||
|
|
||||||
if (isSystemUser) {
|
if (isSystemUser) {
|
||||||
|
|
||||||
HANDLE hUserToken = NULL;
|
auto action = [&commandLine](HANDLE userToken) {
|
||||||
DWORD dwSessionId;
|
|
||||||
ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId);
|
|
||||||
auto rv = WTSQueryUserToken(dwSessionId, &hUserToken);
|
|
||||||
|
|
||||||
if (rv == 0)
|
|
||||||
{
|
|
||||||
ExitOnFailure(hr, "Failed to query user token");
|
|
||||||
}
|
|
||||||
|
|
||||||
HANDLE hUserTokenDup;
|
|
||||||
if (DuplicateTokenEx(hUserToken, TOKEN_ALL_ACCESS, NULL, SECURITY_IMPERSONATION_LEVEL::SecurityImpersonation, TOKEN_TYPE::TokenPrimary, &hUserTokenDup) == 0)
|
|
||||||
{
|
|
||||||
CloseHandle(hUserToken);
|
|
||||||
CloseHandle(hUserTokenDup);
|
|
||||||
ExitOnFailure(hr, "Failed to duplicate user token");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImpersonateLoggedOnUser(hUserTokenDup))
|
|
||||||
{
|
|
||||||
STARTUPINFO startupInfo{ .cb = sizeof(STARTUPINFO), .wShowWindow = SW_SHOWNORMAL };
|
STARTUPINFO startupInfo{ .cb = sizeof(STARTUPINFO), .wShowWindow = SW_SHOWNORMAL };
|
||||||
PROCESS_INFORMATION processInformation;
|
PROCESS_INFORMATION processInformation;
|
||||||
|
|
||||||
PVOID lpEnvironment = NULL;
|
PVOID lpEnvironment = NULL;
|
||||||
CreateEnvironmentBlock(&lpEnvironment, hUserTokenDup, FALSE);
|
CreateEnvironmentBlock(&lpEnvironment, userToken, FALSE);
|
||||||
|
|
||||||
CreateProcessAsUser(
|
CreateProcessAsUser(
|
||||||
hUserTokenDup,
|
userToken,
|
||||||
NULL,
|
NULL,
|
||||||
commandLine.data(),
|
commandLine.data(),
|
||||||
NULL,
|
NULL,
|
||||||
@@ -158,20 +184,20 @@ UINT __stdcall LaunchPowerToysCA(MSIHANDLE hInstall)
|
|||||||
|
|
||||||
if (!CloseHandle(processInformation.hProcess))
|
if (!CloseHandle(processInformation.hProcess))
|
||||||
{
|
{
|
||||||
er = ERROR_INSTALL_FAILURE;
|
return false;
|
||||||
}
|
}
|
||||||
if (!CloseHandle(processInformation.hThread))
|
if (!CloseHandle(processInformation.hThread))
|
||||||
{
|
{
|
||||||
er = ERROR_INSTALL_FAILURE;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RevertToSelf();
|
return true;
|
||||||
CloseHandle(hUserToken);
|
};
|
||||||
CloseHandle(hUserTokenDup);
|
|
||||||
}
|
if (!ImpersonateLoggedInUserAndDoSomething(action))
|
||||||
else
|
|
||||||
{
|
{
|
||||||
ExitOnFailure(hr, "Failed to duplicate user token");
|
hr = E_ABORT;
|
||||||
|
ExitOnFailure(hr, "ImpersonateLoggedInUserAndDoSomething failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -195,10 +221,12 @@ UINT __stdcall LaunchPowerToysCA(MSIHANDLE hInstall)
|
|||||||
|
|
||||||
if (!CloseHandle(processInformation.hProcess))
|
if (!CloseHandle(processInformation.hProcess))
|
||||||
{
|
{
|
||||||
|
hr = E_ABORT;
|
||||||
ExitOnFailure(hr, "Failed to close process handle");
|
ExitOnFailure(hr, "Failed to close process handle");
|
||||||
}
|
}
|
||||||
if (!CloseHandle(processInformation.hThread))
|
if (!CloseHandle(processInformation.hThread))
|
||||||
{
|
{
|
||||||
|
hr = E_ABORT;
|
||||||
ExitOnFailure(hr, "Failed to close thread handle");
|
ExitOnFailure(hr, "Failed to close thread handle");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -411,7 +439,7 @@ UINT __stdcall UninstallServicesCA(MSIHANDLE hInstall)
|
|||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
UINT er = ERROR_SUCCESS;
|
UINT er = ERROR_SUCCESS;
|
||||||
hr = WcaInitialize(hInstall, "CreateScheduledTaskCA");
|
hr = WcaInitialize(hInstall, "UninstallServicesCA");
|
||||||
|
|
||||||
ExitOnFailure(hr, "Failed to initialize");
|
ExitOnFailure(hr, "Failed to initialize");
|
||||||
|
|
||||||
@@ -422,278 +450,6 @@ LExit:
|
|||||||
return WcaFinalize(er);
|
return WcaFinalize(er);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Creates a Scheduled Task to run at logon for the current user.
|
|
||||||
// The path of the executable to run should be passed as the CustomActionData (Value).
|
|
||||||
// Based on the Task Scheduler Logon Trigger Example:
|
|
||||||
// https://learn.microsoft.com/windows/win32/taskschd/logon-trigger-example--c---/
|
|
||||||
UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
UINT er = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
TCHAR username_domain[USERNAME_DOMAIN_LEN];
|
|
||||||
TCHAR username[USERNAME_LEN];
|
|
||||||
|
|
||||||
std::wstring wstrTaskName;
|
|
||||||
|
|
||||||
ITaskService* pService = nullptr;
|
|
||||||
ITaskFolder* pTaskFolder = nullptr;
|
|
||||||
ITaskDefinition* pTask = nullptr;
|
|
||||||
IRegistrationInfo* pRegInfo = nullptr;
|
|
||||||
ITaskSettings* pSettings = nullptr;
|
|
||||||
ITriggerCollection* pTriggerCollection = nullptr;
|
|
||||||
IRegisteredTask* pRegisteredTask = nullptr;
|
|
||||||
IPrincipal* pPrincipal = nullptr;
|
|
||||||
ITrigger* pTrigger = nullptr;
|
|
||||||
ILogonTrigger* pLogonTrigger = nullptr;
|
|
||||||
IAction* pAction = nullptr;
|
|
||||||
IActionCollection* pActionCollection = nullptr;
|
|
||||||
IExecAction* pExecAction = nullptr;
|
|
||||||
|
|
||||||
LPWSTR wszExecutablePath = nullptr;
|
|
||||||
|
|
||||||
hr = WcaInitialize(hInstall, "CreateScheduledTaskCA");
|
|
||||||
ExitOnFailure(hr, "Failed to initialize");
|
|
||||||
|
|
||||||
Logger::info(L"CreateScheduledTaskCA Initialized.");
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
|
||||||
// Get the Domain/Username for the trigger.
|
|
||||||
//
|
|
||||||
// This action needs to run as the system to get elevated privileges from the installation,
|
|
||||||
// so GetUserNameEx can't be used to get the current user details.
|
|
||||||
// The USERNAME and USERDOMAIN environment variables are used instead.
|
|
||||||
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN))
|
|
||||||
{
|
|
||||||
ExitWithLastError(hr, "Getting username failed: %x", hr);
|
|
||||||
}
|
|
||||||
if (!GetEnvironmentVariable(L"USERDOMAIN", username_domain, USERNAME_DOMAIN_LEN))
|
|
||||||
{
|
|
||||||
ExitWithLastError(hr, "Getting the user's domain failed: %x", hr);
|
|
||||||
}
|
|
||||||
wcscat_s(username_domain, L"\\");
|
|
||||||
wcscat_s(username_domain, username);
|
|
||||||
|
|
||||||
Logger::info(L"Current user detected: {}", username_domain);
|
|
||||||
|
|
||||||
// Task Name.
|
|
||||||
wstrTaskName = L"Autorun for ";
|
|
||||||
wstrTaskName += username;
|
|
||||||
|
|
||||||
// Get the executable path passed to the custom action.
|
|
||||||
hr = WcaGetProperty(L"CustomActionData", &wszExecutablePath);
|
|
||||||
ExitOnFailure(hr, "Failed to get the executable path from CustomActionData.");
|
|
||||||
|
|
||||||
// COM and Security Initialization is expected to have been done by the MSI.
|
|
||||||
// It couldn't be done in the DLL, anyway.
|
|
||||||
// ------------------------------------------------------
|
|
||||||
// Create an instance of the Task Service.
|
|
||||||
hr = CoCreateInstance(CLSID_TaskScheduler,
|
|
||||||
nullptr,
|
|
||||||
CLSCTX_INPROC_SERVER,
|
|
||||||
IID_ITaskService,
|
|
||||||
reinterpret_cast<void**>(&pService));
|
|
||||||
ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr);
|
|
||||||
|
|
||||||
// Connect to the task service.
|
|
||||||
hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
|
|
||||||
ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
|
||||||
// Get the PowerToys task folder. Creates it if it doesn't exist.
|
|
||||||
hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
// Folder doesn't exist. Get the Root folder and create the PowerToys subfolder.
|
|
||||||
ITaskFolder* pRootFolder = nullptr;
|
|
||||||
hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
|
|
||||||
ExitOnFailure(hr, "Cannot get Root Folder pointer: %x", hr);
|
|
||||||
hr = pRootFolder->CreateFolder(_bstr_t(L"\\PowerToys"), _variant_t(L""), &pTaskFolder);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
pRootFolder->Release();
|
|
||||||
ExitOnFailure(hr, "Cannot create PowerToys task folder: %x", hr);
|
|
||||||
}
|
|
||||||
Logger::info(L"PowerToys task folder created.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the same task exists, remove it.
|
|
||||||
pTaskFolder->DeleteTask(_bstr_t(wstrTaskName.c_str()), 0);
|
|
||||||
|
|
||||||
// Create the task builder object to create the task.
|
|
||||||
hr = pService->NewTask(0, &pTask);
|
|
||||||
ExitOnFailure(hr, "Failed to create a task definition: %x", hr);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
|
||||||
// Get the registration info for setting the identification.
|
|
||||||
hr = pTask->get_RegistrationInfo(&pRegInfo);
|
|
||||||
ExitOnFailure(hr, "Cannot get identification pointer: %x", hr);
|
|
||||||
hr = pRegInfo->put_Author(_bstr_t(username_domain));
|
|
||||||
ExitOnFailure(hr, "Cannot put identification info: %x", hr);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
|
||||||
// Create the settings for the task
|
|
||||||
hr = pTask->get_Settings(&pSettings);
|
|
||||||
ExitOnFailure(hr, "Cannot get settings pointer: %x", hr);
|
|
||||||
|
|
||||||
hr = pSettings->put_StartWhenAvailable(VARIANT_FALSE);
|
|
||||||
ExitOnFailure(hr, "Cannot put_StartWhenAvailable setting info: %x", hr);
|
|
||||||
hr = pSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE);
|
|
||||||
ExitOnFailure(hr, "Cannot put_StopIfGoingOnBatteries setting info: %x", hr);
|
|
||||||
hr = pSettings->put_ExecutionTimeLimit(_bstr_t(L"PT0S")); //Unlimited
|
|
||||||
ExitOnFailure(hr, "Cannot put_ExecutionTimeLimit setting info: %x", hr);
|
|
||||||
hr = pSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE);
|
|
||||||
ExitOnFailure(hr, "Cannot put_DisallowStartIfOnBatteries setting info: %x", hr);
|
|
||||||
hr = pSettings->put_Priority(4);
|
|
||||||
ExitOnFailure(hr, "Cannot put_Priority setting info : %x", hr);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
|
||||||
// Get the trigger collection to insert the logon trigger.
|
|
||||||
hr = pTask->get_Triggers(&pTriggerCollection);
|
|
||||||
ExitOnFailure(hr, "Cannot get trigger collection: %x", hr);
|
|
||||||
|
|
||||||
// Add the logon trigger to the task.
|
|
||||||
hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger);
|
|
||||||
ExitOnFailure(hr, "Cannot create the trigger: %x", hr);
|
|
||||||
|
|
||||||
hr = pTrigger->QueryInterface(
|
|
||||||
IID_ILogonTrigger, (void**)&pLogonTrigger);
|
|
||||||
pTrigger->Release();
|
|
||||||
ExitOnFailure(hr, "QueryInterface call failed for ILogonTrigger: %x", hr);
|
|
||||||
|
|
||||||
hr = pLogonTrigger->put_Id(_bstr_t(L"Trigger1"));
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
Logger::error(L"Cannot put the trigger ID: {}", hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timing issues may make explorer not be started when the task runs.
|
|
||||||
// Add a little delay to mitigate this.
|
|
||||||
hr = pLogonTrigger->put_Delay(_bstr_t(L"PT03S"));
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
Logger::error(L"Cannot put the trigger delay: {}", hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define the user. The task will execute when the user logs on.
|
|
||||||
// The specified user must be a user on this computer.
|
|
||||||
hr = pLogonTrigger->put_UserId(_bstr_t(username_domain));
|
|
||||||
pLogonTrigger->Release();
|
|
||||||
ExitOnFailure(hr, "Cannot add user ID to logon trigger: %x", hr);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
|
||||||
// Add an Action to the task. This task will execute the path passed to this custom action.
|
|
||||||
|
|
||||||
// Get the task action collection pointer.
|
|
||||||
hr = pTask->get_Actions(&pActionCollection);
|
|
||||||
ExitOnFailure(hr, "Cannot get Task collection pointer: %x", hr);
|
|
||||||
|
|
||||||
// Create the action, specifying that it is an executable action.
|
|
||||||
hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction);
|
|
||||||
pActionCollection->Release();
|
|
||||||
ExitOnFailure(hr, "Cannot create the action: %x", hr);
|
|
||||||
|
|
||||||
// QI for the executable task pointer.
|
|
||||||
hr = pAction->QueryInterface(
|
|
||||||
IID_IExecAction, (void**)&pExecAction);
|
|
||||||
pAction->Release();
|
|
||||||
ExitOnFailure(hr, "QueryInterface call failed for IExecAction: %x", hr);
|
|
||||||
|
|
||||||
// Set the path of the executable to PowerToys (passed as CustomActionData).
|
|
||||||
hr = pExecAction->put_Path(_bstr_t(wszExecutablePath));
|
|
||||||
pExecAction->Release();
|
|
||||||
ExitOnFailure(hr, "Cannot set path of executable: %x", hr);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
|
||||||
// Create the principal for the task
|
|
||||||
hr = pTask->get_Principal(&pPrincipal);
|
|
||||||
ExitOnFailure(hr, "Cannot get principal pointer: %x", hr);
|
|
||||||
|
|
||||||
// Set up principal information:
|
|
||||||
hr = pPrincipal->put_Id(_bstr_t(L"Principal1"));
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
Logger::error(L"Cannot put the principal ID: {}", hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = pPrincipal->put_UserId(_bstr_t(username_domain));
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
Logger::error(L"Cannot put principal user Id: {}", hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = pPrincipal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
Logger::error(L"Cannot put principal logon type: {}", hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the task with the highest available privileges.
|
|
||||||
hr = pPrincipal->put_RunLevel(TASK_RUNLEVEL_LUA);
|
|
||||||
pPrincipal->Release();
|
|
||||||
ExitOnFailure(hr, "Cannot put principal run level: %x", hr);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
|
||||||
// Save the task in the PowerToys folder.
|
|
||||||
{
|
|
||||||
_variant_t SDDL_FULL_ACCESS_FOR_EVERYONE = L"D:(A;;FA;;;WD)";
|
|
||||||
hr = pTaskFolder->RegisterTaskDefinition(
|
|
||||||
_bstr_t(wstrTaskName.c_str()),
|
|
||||||
pTask,
|
|
||||||
TASK_CREATE_OR_UPDATE,
|
|
||||||
_variant_t(username_domain),
|
|
||||||
_variant_t(),
|
|
||||||
TASK_LOGON_INTERACTIVE_TOKEN,
|
|
||||||
SDDL_FULL_ACCESS_FOR_EVERYONE,
|
|
||||||
&pRegisteredTask);
|
|
||||||
ExitOnFailure(hr, "Error saving the Task : %x", hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger::info(L"Scheduled task created for the current user.");
|
|
||||||
|
|
||||||
LExit:
|
|
||||||
ReleaseStr(wszExecutablePath);
|
|
||||||
if (pService)
|
|
||||||
{
|
|
||||||
pService->Release();
|
|
||||||
}
|
|
||||||
if (pTaskFolder)
|
|
||||||
{
|
|
||||||
pTaskFolder->Release();
|
|
||||||
}
|
|
||||||
if (pTask)
|
|
||||||
{
|
|
||||||
pTask->Release();
|
|
||||||
}
|
|
||||||
if (pRegInfo)
|
|
||||||
{
|
|
||||||
pRegInfo->Release();
|
|
||||||
}
|
|
||||||
if (pSettings)
|
|
||||||
{
|
|
||||||
pSettings->Release();
|
|
||||||
}
|
|
||||||
if (pTriggerCollection)
|
|
||||||
{
|
|
||||||
pTriggerCollection->Release();
|
|
||||||
}
|
|
||||||
if (pRegisteredTask)
|
|
||||||
{
|
|
||||||
pRegisteredTask->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
PMSIHANDLE hRecord = MsiCreateRecord(0);
|
|
||||||
MsiRecordSetString(hRecord, 0, TEXT("Failed to create a scheduled task to start PowerToys at user login. You can re-try to create the scheduled task using the PowerToys settings."));
|
|
||||||
MsiProcessMessage(hInstall, static_cast<INSTALLMESSAGE>(INSTALLMESSAGE_WARNING + MB_OK), hRecord);
|
|
||||||
}
|
|
||||||
|
|
||||||
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
|
||||||
return WcaFinalize(er);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removes all Scheduled Tasks in the PowerToys folder and deletes the folder afterwards.
|
// Removes all Scheduled Tasks in the PowerToys folder and deletes the folder afterwards.
|
||||||
// Based on the Task Scheduler Displaying Task Names and State example:
|
// Based on the Task Scheduler Displaying Task Names and State example:
|
||||||
// https://learn.microsoft.com/windows/desktop/TaskSchd/displaying-task-names-and-state--c---/
|
// https://learn.microsoft.com/windows/desktop/TaskSchd/displaying-task-names-and-state--c---/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ EXPORTS
|
|||||||
LaunchPowerToysCA
|
LaunchPowerToysCA
|
||||||
CheckGPOCA
|
CheckGPOCA
|
||||||
ApplyModulesRegistryChangeSetsCA
|
ApplyModulesRegistryChangeSetsCA
|
||||||
CreateScheduledTaskCA
|
|
||||||
DetectPrevInstallPathCA
|
DetectPrevInstallPathCA
|
||||||
RemoveScheduledTasksCA
|
RemoveScheduledTasksCA
|
||||||
TelemetryLogInstallSuccessCA
|
TelemetryLogInstallSuccessCA
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ void apply_general_settings(const json::JsonObject& general_configs, bool save)
|
|||||||
if (is_process_elevated())
|
if (is_process_elevated())
|
||||||
{
|
{
|
||||||
delete_auto_start_task_for_this_user();
|
delete_auto_start_task_for_this_user();
|
||||||
create_auto_start_task_for_this_user(general_configs.GetNamedBoolean(L"run_elevated", false));
|
create_auto_start_task_for_this_user(run_as_elevated);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -127,6 +127,12 @@ void apply_general_settings(const json::JsonObject& general_configs, bool save)
|
|||||||
delete_auto_start_task_for_this_user();
|
delete_auto_start_task_for_this_user();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete_auto_start_task_for_this_user();
|
||||||
|
create_auto_start_task_for_this_user(run_as_elevated);
|
||||||
|
}
|
||||||
|
|
||||||
if (json::has(general_configs, L"enabled"))
|
if (json::has(general_configs, L"enabled"))
|
||||||
{
|
{
|
||||||
for (const auto& enabled_element : general_configs.GetNamedObject(L"enabled"))
|
for (const auto& enabled_element : general_configs.GetNamedObject(L"enabled"))
|
||||||
|
|||||||
Reference in New Issue
Block a user