I am trying to write a windows Logon trigger task using C++ on Windows 7.
I am following this microsoft tutorial.
But I am facing problem in saving the task to root folder. Here:
// ------------------------------------------------------
// Save the task in the root folder.
IRegisteredTask *pRegisteredTask = NULL;
hr = pRootFolder->RegisterTaskDefinition(
_bstr_t( wszTaskName ),
pTask,
TASK_CREATE_OR_UPDATE,
_variant_t(L"Builtin\\Administrators"),
_variant_t(),
TASK_LOGON_GROUP,
_variant_t(L""),
&pRegisteredTask);
Where the hr
is getting error : No Mapping between account names and security ids was done
I also tried replacing _variant_t(L"Builtin\\Administrators")
with _variant_t(L"S-1-5-32-544")
to NULL out language hard coding issue, still No luck.
How can I make it work?
(with Administor privileges, working for Windows 7, 8, etc. Note that this won't display an UAC popup on Windows startup "Are you sure to run this software with Admin rights?", that's why the TaskScheduler method is more interesting in this case than the good old HKEY_LOCAL_MACHINE\...\CurrentVersion\Run solution)
There are a few things to update in this tutorial to make it work:
_variant_t(L"S-1-5-32-544")
instead of _variant_t(L"Builtin\\Administrators")
hr = pLogonTrigger->put_UserId(_bstr_t(L"DOMAIN\\UserName"));
by either a hardcoded Domain\Username, or by some Domain\Username detection code (I couldn't make it work), or just comment this line, it worked for me!TASK_RUNLEVEL_HIGHEST
Then you'll get the famous:
Success! Task successfully registered.
Phew! After a few hours per day and some edits, now here is a working full main.cpp
:
#define SECURITY_WIN32
#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <comdef.h>
#include <Security.h>
#include <taskschd.h>
#pragma comment(lib, "taskschd.lib")
#pragma comment(lib, "comsupp.lib")
using namespace std;
#define TASKNAME L"Logon Trigger Test Task"
int __cdecl wmain()
{
// Get the windows directory and set the path to notepad.exe.
wstring wstrExecutablePath = _wgetenv(L"WINDIR");
wstrExecutablePath += L"\\SYSTEM32\\NOTEPAD.EXE";
// Initialize COM
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr)) return 1;
// Set general COM security levels.
hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL);
if (FAILED(hr)) goto cleanup0;
// Create an instance of the Task Service.
ITaskService *pService = NULL;
hr = CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (void**)&pService);
if (FAILED(hr)) goto cleanup0;
// Connect to the task service.
hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
if (FAILED(hr)) goto cleanup1;
// Get the pointer to the root task folder. This folder will hold the new task that is registered.
ITaskFolder *pRootFolder = NULL;
hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
if (FAILED(hr)) goto cleanup1;
// If the same task exists, remove it.
pRootFolder->DeleteTask(_bstr_t(TASKNAME), 0);
// Create the task builder object to create the task.
ITaskDefinition *pTask = NULL;
hr = pService->NewTask(0, &pTask);
// COM clean up. Pointer is no longer used.
pService->Release();
if (FAILED(hr)) { pRootFolder->Release(); CoUninitialize(); return 1; }
// Get the registration info for setting the identification.
IRegistrationInfo *pRegInfo = NULL;
hr = pTask->get_RegistrationInfo(&pRegInfo);
if (FAILED(hr)) goto cleanup2;
hr = pRegInfo->put_Author(L"Author Name");
pRegInfo->Release();
if (FAILED(hr)) goto cleanup2;
// Create the settings for the task
ITaskSettings *pSettings = NULL;
hr = pTask->get_Settings(&pSettings);
if (FAILED(hr)) goto cleanup2;
// Set setting values for the task.
pSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE);
pSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE);
pSettings->put_ExecutionTimeLimit(_bstr_t(L"PT0S"));
pSettings->Release();
if (FAILED(hr)) goto cleanup2;
// Get the trigger collection to insert the logon trigger.
ITriggerCollection *pTriggerCollection = NULL;
hr = pTask->get_Triggers(&pTriggerCollection);
if (FAILED(hr)) goto cleanup2;
// Add the logon trigger to the task.
ITrigger *pTrigger = NULL;
hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger);
pTriggerCollection->Release();
if (FAILED(hr)) goto cleanup2;
ILogonTrigger *pLogonTrigger = NULL;
hr = pTrigger->QueryInterface(IID_ILogonTrigger, (void**)&pLogonTrigger);
pTrigger->Release();
if (FAILED(hr)) goto cleanup2;
hr = pLogonTrigger->put_Id(_bstr_t(L"Trigger1"));
if (FAILED(hr)) goto cleanup2;
// 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(L"DOMAIN\\UserName"));
pLogonTrigger->Release();
if (FAILED(hr)) goto cleanup2;
IPrincipal *pPrincipal;
hr = pTask->get_Principal(&pPrincipal);
if (FAILED(hr)) goto cleanup2;
hr = pPrincipal->put_RunLevel(TASK_RUNLEVEL_HIGHEST);
if (FAILED(hr)) goto cleanup2;
// Add an Action to the task. This task will execute .exe
IActionCollection *pActionCollection = NULL;
// Get the task action collection pointer.
hr = pTask->get_Actions(&pActionCollection);
if (FAILED(hr)) goto cleanup2;
// Create the action, specifying that it is an executable action.
IAction *pAction = NULL;
hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction);
pActionCollection->Release();
if (FAILED(hr)) goto cleanup2;
// QI for the executable task pointer.
IExecAction *pExecAction = NULL;
hr = pAction->QueryInterface(IID_IExecAction, (void**)&pExecAction);
pAction->Release();
if (FAILED(hr)) goto cleanup2;
// Set the path of the executable.
hr = pExecAction->put_Path(_bstr_t(wstrExecutablePath.c_str()));
pExecAction->Release();
if (FAILED(hr)) goto cleanup2;
// Save the task in the root folder.
IRegisteredTask *pRegisteredTask = NULL;
hr = pRootFolder->RegisterTaskDefinition(_bstr_t(TASKNAME), pTask, TASK_CREATE_OR_UPDATE, _variant_t(L"S-1-5-32-544"), _variant_t(), TASK_LOGON_GROUP, _variant_t(L""), &pRegisteredTask); //_variant_t(L"Builtin\\Administrators"),
if (FAILED(hr)) goto cleanup2;
printf("Success! Task successfully registered.");
getchar();
pRootFolder->Release();
pTask->Release();
pRegisteredTask->Release();
CoUninitialize();
return 0;
cleanup0:
CoUninitialize();
return 1;
cleanup1:
pService->Release();
CoUninitialize();
return 1;
cleanup2:
pRootFolder->Release();
pTask->Release();
CoUninitialize();
return 1;
}
I suspect the demo code you have is XP-era, and hasn't been updated to match the Vista/Win7 rules.
I updated the sample to set the LUA settings after setting the logon trigger, and it seems to work:
hr = pLogonTrigger->put_UserId(_bstr_t(L"DOMAIN\username"));
if (FAILED(hr))
{
printf("\nCannot add user ID to logon trigger: %x", hr);
CoUninitialize();
return 1;
}
//*** NEW**** Set the LUA settings
CComPtr<IPrincipal> pPrincipal;
hr = pTask->get_Principal(&pPrincipal);
if (SUCCEEDED(hr))
{
hr = pPrincipal->put_RunLevel(TASK_RUNLEVEL_LUA);
}
if (SUCCEEDED(hr))
{
hr = pPrincipal->put_GroupId(_bstr_t(L"Builtin\\Administrators"));
}
if (FAILED(hr))
{
printf("\nCannot set runlevel/groupid: %x", hr);
CoUninitialize();
return 1;
}
If you need it to run on XP, then it's likely that the get_Principal
call will fail, so let that failure through.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With