void enumerateTasksForFolder(std::string path, QueryData& results) { void* vpService = nullptr; auto ret = CoCreateInstance(CLSID_TaskScheduler, nullptr, CLSCTX_INPROC_SERVER, IID_ITaskService, &vpService); if (FAILED(ret)) { VLOG(1) << "Failed to create COM instance " << ret; return; } auto pService = static_cast<ITaskService*>(vpService); ret = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()); if (FAILED(ret)) { VLOG(1) << "Failed to connect to TaskService " << ret; pService->Release(); return; } ITaskFolder* pRootFolder = nullptr; auto widePath = stringToWstring(path); ret = pService->GetFolder(BSTR(widePath.c_str()), &pRootFolder); pService->Release(); if (FAILED(ret)) { VLOG(1) << "Failed to get root task folder " << ret; return; } IRegisteredTaskCollection* pTaskCollection = nullptr; ret = pRootFolder->GetTasks(TASK_ENUM_HIDDEN, &pTaskCollection); pRootFolder->Release(); if (FAILED(ret)) { VLOG(1) << "Failed to get task collection for root folder " << ret; return; } long numTasks = 0; pTaskCollection->get_Count(&numTasks); for (size_t i = 0; i < numTasks; i++) { IRegisteredTask* pRegisteredTask = nullptr; // Collections are 1-based lists ret = pTaskCollection->get_Item(_variant_t(i + 1), &pRegisteredTask); if (FAILED(ret)) { VLOG(1) << "Failed to process task"; continue; } Row r; BSTR taskName; ret = pRegisteredTask->get_Name(&taskName); std::wstring wTaskName(taskName, SysStringLen(taskName)); r["name"] = ret == S_OK ? SQL_TEXT(wstringToString(wTaskName.c_str())) : ""; VARIANT_BOOL enabled = false; pRegisteredTask->get_Enabled(&enabled); r["enabled"] = enabled ? INTEGER(1) : INTEGER(0); TASK_STATE taskState; pRegisteredTask->get_State(&taskState); r["state"] = kStateMap.count(taskState) > 0 ? kStateMap.at(taskState) : kStateMap.at(TASK_STATE_UNKNOWN); BSTR taskPath; ret = pRegisteredTask->get_Path(&taskPath); std::wstring wTaskPath(taskPath, SysStringLen(taskPath)); r["path"] = ret == S_OK ? wstringToString(wTaskPath.c_str()) : ""; VARIANT_BOOL hidden = false; pRegisteredTask->get_Enabled(&hidden); r["hidden"] = hidden ? INTEGER(1) : INTEGER(0); HRESULT lastTaskRun = E_FAIL; pRegisteredTask->get_LastTaskResult(&lastTaskRun); _com_error err(lastTaskRun); r["last_run_message"] = err.ErrorMessage(); r["last_run_code"] = INTEGER(lastTaskRun); // We conver the COM Date type to a unix epoch timestamp DATE dRunTime; SYSTEMTIME st; FILETIME ft; FILETIME locFt; pRegisteredTask->get_LastRunTime(&dRunTime); VariantTimeToSystemTime(dRunTime, &st); SystemTimeToFileTime(&st, &ft); LocalFileTimeToFileTime(&ft, &locFt); r["last_run_time"] = INTEGER(filetimeToUnixtime(locFt)); pRegisteredTask->get_NextRunTime(&dRunTime); VariantTimeToSystemTime(dRunTime, &st); SystemTimeToFileTime(&st, &ft); LocalFileTimeToFileTime(&ft, &locFt); r["next_run_time"] = INTEGER(filetimeToUnixtime(locFt)); ITaskDefinition* taskDef = nullptr; IActionCollection* tActionCollection = nullptr; pRegisteredTask->get_Definition(&taskDef); if (taskDef != nullptr) { taskDef->get_Actions(&tActionCollection); } long actionCount = 0; if (tActionCollection != nullptr) { tActionCollection->get_Count(&actionCount); } std::vector<std::string> actions; // Task collections are 1-indexed for (auto j = 1; j <= actionCount; j++) { IAction* act = nullptr; IExecAction* execAction = nullptr; tActionCollection->get_Item(j, &act); if (act == nullptr) { continue; } act->QueryInterface(IID_IExecAction, reinterpret_cast<void**>(&execAction)); if (execAction == nullptr) { continue; } BSTR taskExecPath; execAction->get_Path(&taskExecPath); std::wstring wTaskExecPath(taskExecPath, SysStringLen(taskExecPath)); BSTR taskExecArgs; execAction->get_Arguments(&taskExecArgs); std::wstring wTaskExecArgs(taskExecArgs, SysStringLen(taskExecArgs)); BSTR taskExecRoot; execAction->get_WorkingDirectory(&taskExecRoot); std::wstring wTaskExecRoot(taskExecRoot, SysStringLen(taskExecRoot)); auto full = wTaskExecRoot + L" " + wTaskExecPath + L" " + wTaskExecArgs; actions.push_back(wstringToString(full.c_str())); act->Release(); } if (tActionCollection != nullptr) { tActionCollection->Release(); } if (taskDef != nullptr) { taskDef->Release(); } r["action"] = !actions.empty() ? osquery::join(actions, ",") : ""; results.push_back(r); pRegisteredTask->Release(); } pTaskCollection->Release(); }
int __cdecl wmain() { // ------------------------------------------------------ // Initialize COM. HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if( FAILED(hr) ) { printf("\nCoInitializeEx failed: %x", 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) ) { printf("\nCoInitializeSecurity failed: %x", hr ); CoUninitialize(); return 1; } // ------------------------------------------------------ // Create a name for the task. LPCWSTR wszTaskName = L"Event Trigger Test Task"; // ------------------------------------------------------ // 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)) { printf("\nFailed to CoCreate an instance of the TaskService class: %x", hr); CoUninitialize(); return 1; } // Connect to the task service. hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()); if( FAILED(hr) ) { printf("\nITaskService::Connect failed: %x", hr ); pService->Release(); CoUninitialize(); return 1; } // ------------------------------------------------------ // 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) ) { printf("\nCannot get Root Folder pointer: %x", hr ); pService->Release(); CoUninitialize(); return 1; } // If the same task exists, remove it. pRootFolder->DeleteTask( _bstr_t( wszTaskName), 0 ); // Create the task builder object to create the task. ITaskDefinition *pTask = NULL; hr = pService->NewTask( 0, &pTask ); pService->Release(); // COM clean up. Pointer is no longer used. if (FAILED(hr)) { printf("\nFailed to create an instance of the task: %x", 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) ) { printf("\nCannot get identification pointer: %x", hr ); pRootFolder->Release(); pTask->Release(); CoUninitialize(); return 1; } hr = pRegInfo->put_Author( L"Author Name" ); pRegInfo->Release(); // COM clean up. Pointer is no longer used. if( FAILED(hr) ) { printf("\nCannot put identification info: %x", hr ); pRootFolder->Release(); pTask->Release(); CoUninitialize(); return 1; } // ------------------------------------------------------ // Create the settings for the task ITaskSettings *pSettings = NULL; hr = pTask->get_Settings( &pSettings ); if( FAILED(hr) ) { printf("\nCannot get settings pointer: %x", hr ); pRootFolder->Release(); pTask->Release(); CoUninitialize(); return 1; } // Set setting values for the task. hr = pSettings->put_StartWhenAvailable(VARIANT_BOOL(true)); pSettings->Release(); // COM clean up. Pointer is no longer used. if( FAILED(hr) ) { printf("\nCannot put setting info: %x", hr ); pRootFolder->Release(); pTask->Release(); CoUninitialize(); return 1; } // ------------------------------------------------------ // Get the trigger collection to insert the event trigger. ITriggerCollection *pTriggerCollection = NULL; hr = pTask->get_Triggers( &pTriggerCollection ); if( FAILED(hr) ) { printf("\nCannot get trigger collection: %x", hr ); pRootFolder->Release(); pTask->Release(); CoUninitialize(); return 1; } // Create the event trigger for the task. ITrigger *pTrigger = NULL; hr = pTriggerCollection->Create( TASK_TRIGGER_EVENT, &pTrigger ); pTriggerCollection->Release(); if( FAILED(hr) ) { printf("\nCannot create the trigger: %x", hr ); pRootFolder->Release(); pTask->Release(); CoUninitialize(); return 1; } IEventTrigger *pEventTrigger = NULL; hr = pTrigger->QueryInterface( IID_IEventTrigger, (void**) &pEventTrigger ); pTrigger->Release(); if( FAILED(hr) ) { printf("\nQueryInterface call on IEventTrigger failed: %x", hr ); pRootFolder->Release(); pTask->Release(); CoUninitialize(); return 1; } hr = pEventTrigger->put_Id( _bstr_t( L"Trigger1" ) ); if( FAILED(hr) ) printf("\nCannot put the trigger ID: %x", hr); // Set the task to start at a certain time. The time // format should be YYYY-MM-DDTHH:MM:SS(+-)(timezone). // For example, the start boundary below // is January 1st 2005 at 12:05 hr = pEventTrigger->put_StartBoundary( _bstr_t(L"2005-01-01T12:05:00") ); if( FAILED(hr) ) printf("\nCannot put the trigger start boundary: %x", hr); hr = pEventTrigger->put_EndBoundary( _bstr_t(L"2015-05-02T08:00:00") ); if( FAILED(hr) ) printf("\nCannot put the trigger end boundary: %x", hr); // Define the delay for the event trigger (30 seconds). hr = pEventTrigger->put_Delay( L"PT30S" ); if( FAILED(hr) ) printf("\nCannot put the trigger delay: %x", hr); // Define the event query for the event trigger. // The following query string defines a subscription to all // level 2 events in the System channel. hr = pEventTrigger->put_Subscription( L"<QueryList> <Query Id='1'> <Select Path='System'>*[System/Level=2]</Select></Query></QueryList>" ); pEventTrigger->Release(); if( FAILED(hr) ) { printf("\nCannot put the event query: %x", hr); pRootFolder->Release(); pTask->Release(); CoUninitialize(); return 1; } // ------------------------------------------------------ // Add an action to the task. This task will send an e-mail. IActionCollection *pActionCollection = NULL; // Get the task action collection pointer. hr = pTask->get_Actions( &pActionCollection ); if( FAILED(hr) ) { printf("\nCannot get action collection pointer: %x", hr ); pRootFolder->Release(); pTask->Release(); CoUninitialize(); return 1; } // Create the action, specifying that it will send an e-mail. IAction *pAction = NULL; hr = pActionCollection->Create( TASK_ACTION_SEND_EMAIL, &pAction ); pActionCollection->Release(); if( FAILED(hr) ) { printf("\nCannot create an e-mail action: %x", hr ); pRootFolder->Release(); pTask->Release(); CoUninitialize(); return 1; } IEmailAction *pEmailAction = NULL; // QI for the e-mail task pointer. hr = pAction->QueryInterface(IID_IEmailAction, (void**) &pEmailAction ); pAction->Release(); if( FAILED(hr) ) { printf("\nQueryInterface call failed for IEmailAction: %x", hr ); pRootFolder->Release(); pTask->Release(); CoUninitialize(); return 1; } // Set the properties of the e-mail action. hr = pEmailAction->put_From(L"*****@*****.**"); if( FAILED(hr) ) { printf("\nCannot put From information: %x", hr ); pRootFolder->Release(); pEmailAction->Release(); pTask->Release(); CoUninitialize(); return 1; } hr = pEmailAction->put_To(L"*****@*****.**"); if( FAILED(hr) ) { printf("\nCannot put To information: %x", hr ); pRootFolder->Release(); pEmailAction->Release(); pTask->Release(); CoUninitialize(); return 1; } hr = pEmailAction->put_Server(L"smtp.tschd.microsoft.com"); if( FAILED(hr) ) { printf("\nCannot put SMTP server information: %x", hr ); pRootFolder->Release(); pEmailAction->Release(); pTask->Release(); CoUninitialize(); return 1; } hr = pEmailAction->put_Subject(L"An event has occurred"); if( FAILED(hr) ) printf("\nCannot put the subject information: %x", hr); hr = pEmailAction->put_Body(L"A level 2 event occurred in the system channel."); if( FAILED(hr) ) printf("\nCannot put the e-mail body information: %x", hr); pEmailAction->Release(); // ------------------------------------------------------ // Securely get the user name and password. The task will // be created to run with the credentials from the supplied // user name and password. CREDUI_INFO cui; TCHAR pszName[CREDUI_MAX_USERNAME_LENGTH] = TEXT(""); TCHAR pszPwd[CREDUI_MAX_PASSWORD_LENGTH] = TEXT(""); BOOL fSave; DWORD dwErr; cui.cbSize = sizeof(CREDUI_INFO); cui.hwndParent = NULL; // Ensure that MessageText and CaptionText identify // what credentials to use and which application requires them. cui.pszMessageText = TEXT("Account information for task registration:"); cui.pszCaptionText = TEXT("Enter Account Information for Task Registration"); cui.hbmBanner = NULL; fSave = FALSE; // Create the UI asking for the credentials. dwErr = CredUIPromptForCredentials( &cui, // CREDUI_INFO structure TEXT(""), // Target for credentials NULL, // Reserved 0, // Reason pszName, // User name CREDUI_MAX_USERNAME_LENGTH, // Max number for user name pszPwd, // Password CREDUI_MAX_PASSWORD_LENGTH, // Max number for password &fSave, // State of save check box CREDUI_FLAGS_GENERIC_CREDENTIALS | // Flags CREDUI_FLAGS_ALWAYS_SHOW_UI | CREDUI_FLAGS_DO_NOT_PERSIST); if(dwErr) { printf("\nDid not get credentials."); pRootFolder->Release(); pTask->Release(); CoUninitialize(); return 1; } // ------------------------------------------------------ // Save the task in the root folder. IRegisteredTask *pRegisteredTask = NULL; hr = pRootFolder->RegisterTaskDefinition( _bstr_t( wszTaskName ), pTask, TASK_CREATE_OR_UPDATE, _variant_t(_bstr_t(pszName)), _variant_t(_bstr_t(pszPwd)), TASK_LOGON_PASSWORD, _variant_t(L""), &pRegisteredTask); if( FAILED(hr) ) { printf("\nError saving the Task : %x", hr ); pRootFolder->Release(); pTask->Release(); CoUninitialize(); SecureZeroMemory(pszName, sizeof(pszName)); SecureZeroMemory(pszPwd, sizeof(pszPwd)); return 1; } printf("\n Success! Task successfully registered. " ); // Clean up. pRootFolder->Release(); pTask->Release(); pRegisteredTask->Release(); CoUninitialize(); // When you have finished using the credentials, // erase them from memory. SecureZeroMemory(pszName, sizeof(pszName)); SecureZeroMemory(pszPwd, sizeof(pszPwd)); return 0; }