Jump to content

Creating a "brushed up" Task Scheduler UDF?


water
 Share

Would you like to see a brushed up Task Scheduler UDF (inlcuding help files, examples ...)?  

39 members have voted

  1. 1. Would you like to see such a brushed up UDF?

    • Yes
    • Don't mind
    • Maybe later
      0
    • No
      0


Recommended Posts

Hi @water

I'm currently testing the UDF, and have found an issue with _TS_TaskImportXML.  I have some XML files for task that I have exported manually, and I'm trying to import them.  Most of my tasks files have LogonType set to Password.  When I try to import them, I get @error=1707, @extended=-2147352567.  This is caused by the $oFolder.RegisterTaskDefinition call having empty strings for username and password.  According to the documentation for $TASK_LOGON_PASSWORD, "Use a password for logging on the user. The password must be supplied at registration time."  When I fill in the user name and password for the RegisterTaskDefinition call in the function, the task imports correctly.  I think it would be a good Idea to add optional parameters for user name and password to the function.  

Thanks,

 

Adam

 

Link to comment
Share on other sites

@AdamUL If it needs the username and password to register the task, it can't be optional... unless you don't plan on registering it? Or do your XML files have the username and password in them already?

Edited by seadoggie01

All my code provided is Public Domain... but it may not work. ;) Use it, change it, break it, whatever you want.

Spoiler

My Humble Contributions:
Personal Function Documentation - A personal HelpFile for your functions
Acro.au3 UDF - Automating Acrobat Pro
ToDo Finder - Find #ToDo: lines in your scripts
UI-SimpleWrappers UDF - Use UI Automation more Simply-er
KeePass UDF - Automate KeePass, a password manager
InputBoxes - Simple Input boxes for various variable types

Link to comment
Share on other sites

@seadoggie01  If you look in the code for _TS_TaskImportXML you will see that the task is registered with empty strings for the user name and password.  

Local $oTask = $oFolder.RegisterTaskDefinition($sTaskName, $oTaskDefinition, $TASK_CREATE, "", "", 0)
If @error Then Return SetError(1707, @error, 0)

This could easily be changed to 

Func _TS_TaskImportXML($oService, $sTaskPath, $iInputType, $vXMLInput, $sUserId = Default, $sPassword = Default)
    If $sUserId = Default Then $sUserId = ""
    If $sPassword = Default Then $sPassword = ""
.
.
.
    Local $oTask = $oFolder.RegisterTaskDefinition($sTaskName, $oTaskDefinition, $TASK_CREATE, $sUserId, $sPassword, 0)
    If @error Then Return SetError(1707, @error, 0)
.
.
.

No, the password is not stored, when you export a task with the "password" LoginType.  Also, the password is not stored in the XML file.  

 

Adam

Link to comment
Share on other sites

I think it makes sense to remove the Task Registration from the XML import function.
We already have a registration function that allows to pass userid and password.
So the XML import function would not create and return a Task but create a Task Definition object from the imported XML and return this object to the caller.
He could then do further modifications before calling _TS_TaskRegister (and provide usrid and password).

What do you think?
 

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Hi water, that sounds like a good idea.   _TS_TaskCopy would need to be updated as well, as it uses _TS_TaskImportXML.  _TS_TaskCopy also fails to copy a task with Principal LogonType set to Password, as is to be expected.  

 

Adam

 

Link to comment
Share on other sites

Version 1.3.0.0 released

Changelog can be found on the download page and the history in the ZIP file.

For download please see my signature below.

Please play with this version and tell me what doesn't work or is missing!

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

23 hours ago, AdamUL said:

Hi water, that sounds like a good idea.   _TS_TaskCopy would need to be updated as well, as it uses _TS_TaskImportXML.  _TS_TaskCopy also fails to copy a task with Principal LogonType set to Password, as is to be expected.  

Done 🙂

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Nice work water. 

I noticed something when registering an imported task.  If you want to keep the same Principal LogoType, as in the XML file, you need to call the _TS_TaskRegister function with $TASK_LOGON_NONE as the $iLogonType.  If you do not, it gets changed to the default, $TASK_LOGON_INTERACTIVE_TOKEN.

With Principal LogonType $TASK_LOGON_PASSWORD in the file.

Global $oTask = _TS_TaskRegister($oService, $sFolderName, $sTargetTaskName, $oTaskDefinition, "Domain\Username", "Password", $TASK_LOGON_NONE)

With other Principal LogonTypes in the file.  I would also use this in the example file for _TS_TaskImportXML.  

Global $oTask = _TS_TaskRegister($oService, $sFolderName, $sTargetTaskName, $oTaskDefinition, Default, Default, $TASK_LOGON_NONE)

 

This is also the case when you create a task, if you set the Principal LogonType with _TS_TaskPropertiesSet or _TS_Wrapper_PrincipalSet, and then register with _TS_TaskRegister or _TS_Wrapper_TaskRegister without additional parameters.  Using the following keeps the Principal LogonType set.  

_TS_Wrapper_TaskRegister($oService, "Test", "Test-DateTime-Daily", $oTaskDefinition, Default, Default, $TASK_LOGON_NONE)

Sorry, if I'm not describing it well enough.  As nothing really needs to change in the UDF itself, maybe an entry in the Wiki pointing this out.  

 

Adam

 

Link to comment
Share on other sites

48 minutes ago, AdamUL said:

As nothing really needs to change in the UDF itself, maybe an entry in the Wiki pointing this out.

That's exactly what I intend to do ;)
When working with the UDF we will better understand how the Task Scheduler is meant by MS to be used.
I - or everyone else - can update the wiki and save this hands-on experience so it might be helpful for others.

Thanks for testing and reporting your findings!

N.B.: Do you think it is sensible to change _TS_TaskRegister and set the default $iLogonType from $TASK_LOGON_INTERACTIVE_TOKEN to $TASK_LOGON_NONE?

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

22 hours ago, water said:

N.B.: Do you think it is sensible to change _TS_TaskRegister and set the default $iLogonType from $TASK_LOGON_INTERACTIVE_TOKEN to $TASK_LOGON_NONE?

That's a good question.  It would be a script breaking change.  If we do have $TASK_LOGON_NONE as the default for _TS_TaskRegister, then when you register a task you will need to explicitly state the LogonType you want when registering a created task.  If you set it in the principal or import a task with it set, then it wouldn't be an issue.  Is that what we want?  _TS_Wrapper_TaskRegister would need to be changed as well.  If we keep it the same, and you used _TS_Wrapper_PrincipalSet and then use _TS_Wrapper_TaskRegister with default settings, what you set could be changed.   

We could add some code in the the TaskRegister functions to check if there is a current LogonType, and use $TASK_LOGON_NONE instead of the default.  This would require an update to the UDF.  It wouldn't be script breaking.  I updated the functions below to show you what I mean.  Let me know what you think.  

Func _TS_TaskRegister($oService, $sFolder, $sName, $oTaskDefinition, $sUserId = Default, $sPassword = Default, $iLogonType = Default)
    If $sUserId = Default Then $sUserId = ""
    If $sPassword = Default Then $sPassword = ""
    If Not IsObj($oService) Then Return SetError(2101, 0, 0)
    If Not _TS_FolderExists($oService, $sFolder) Then Return SetError(2102, @error, 0)
    If _TS_TaskExists($oService, $sFolder & "\" & $sName) Then Return SetError(2103, @error, 0)
    If Not IsObj($oTaskDefinition) Then Return SetError(2104, 0, 0)
    Local $aTaskProperties = _TS_TaskPropertiesGet($oService, $oTaskDefinition, 1, True, "PRINCIPAL", "LogonType") ;<=== Added.
    If UBound($aTaskProperties, $UBOUND_ROWS) = 1 Then                                                             ;<=== Added.
        If $iLogonType = Default Then $iLogonType = $TASK_LOGON_NONE                                               ;<=== Added.
    Else                                                                                                           ;<=== Added.
        If $iLogonType = Default Then $iLogonType = $TASK_LOGON_INTERACTIVE_TOKEN                                  ;<=== Moved.
    EndIf                                                                                                          ;<=== Added.
    ; Register (create) the Task
    Local $oFolder = _TS_FolderGet($oService, $sFolder)
    If @error Then Return SetError(2105, @error, 0)
    Local $oTask = $oFolder.RegisterTaskDefinition($sName, $oTaskDefinition, $TASK_CREATE, $sUserId, $sPassword, $iLogonType)
    If @error Then Return SetError(2106, @error, 0)
    Return $oTask
EndFunc   ;==>_TS_TaskRegister
Func _TS_Wrapper_TaskRegister($oService, $sFolder, $sName, $oTaskDefinition, $sUserId = Default, $sPassword = Default, $iLogonType = Default)
    If Not IsObj($oService) Or ObjName($oService) <> "ITaskService" Then Return SetError(3001, 0, 0)
    If Not IsObj($oTaskDefinition) Or ObjName($oTaskDefinition) <> "ITaskDefinition" Then Return SetError(3004, 0, 0)
    If $sUserId = Default Then $sUserId = ""
    If $sPassword = Default Then $sPassword = ""
    If $iLogonType = Default Then $iLogonType = $TASK_LOGON_INTERACTIVE_TOKEN
    If Not _TS_FolderExists($oService, $sFolder) Then Return SetError(3002, @error, 0)
    If _TS_TaskExists($oService, $sFolder & "\" & $sName) Then Return SetError(3003, @error, 0)
    $oTaskDefinition.RegistrationInfo.Uri = $sFolder & "\" & $sName
    If @error Then Return SetError(3007, @error, 0)
    Local $aTaskProperties = _TS_TaskPropertiesGet($oService, $oTaskDefinition, 1, True, "PRINCIPAL", "LogonType") ;<=== Added.
    If UBound($aTaskProperties, $UBOUND_ROWS) = 1 Then                                                             ;<=== Added.
        If $iLogonType = Default Then $iLogonType = $TASK_LOGON_NONE                                               ;<=== Added.
    Else                                                                                                           ;<=== Added.
        If $iLogonType = Default Then $iLogonType = $TASK_LOGON_INTERACTIVE_TOKEN                                  ;<=== Moved.
    EndIf                                                                                                          ;<=== Added.
    ; Register (create) the Task
    Local $oFolder = _TS_FolderGet($oService, $sFolder)
    If @error Then Return SetError(3005, @error, 0)
    Local $oTask = $oFolder.RegisterTaskDefinition($sName, $oTaskDefinition, $TASK_CREATE, $sUserId, $sPassword, $iLogonType)
    If @error Then Return SetError(3006, @error, 0)
    Return $oTask
EndFunc   ;==>_TS_Wrapper_TaskRegister

Your welcome on the testing.  Thank you for writing this UDF.   

 

Adam

 

Edited by AdamUL
Link to comment
Share on other sites

Great idea :)
I have implemented the following changes:

  • Added the additional code as suggested to _TS_TaskRegister
  • _TS_Wrapper_TaskRegister is now an alias for _TS_TaskRegister as the wrapper has the same functionality and has only been added for completeness
  • _TS_TaskPropertiesGet has been modified so you get the property value as a string when you set $iFormat to 1 and $sQueryProperties to a single property. Else you get the full array.

Comments please ;)

Temp.au3

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Thanks Water.  Nice changes.  I like the non-array return for _TS_TaskPropertiesGet on a single property.  Just a heads up. In my testing of _TS_TaskPropertiesGet, numerical values, such as LogonType, return as a number type (Int32), not a string.  Values such as UserId return as String.  This is also the case for the returned array.  Maybe a comment in the documentation about the type as being returned by the COM object?  This most likely won't be an issues with the way AutoIt handles variants.  Testing snippet below.  

;~ Global $vTaskProperties = _TS_TaskPropertiesGet($oService, $sTask, 1, True)
;~ Global $vTaskProperties = _TS_TaskPropertiesGet($oService, $sTask, 1, True, "PRINCIPAL")
;~ Global $vTaskProperties = _TS_TaskPropertiesGet($oService, $sTask, 1, True, "PRINCIPAL", "LogonType")
Global $vTaskProperties = _TS_TaskPropertiesGet($oService, $sTask, 1, True, "PRINCIPAL", "UserId")
If @error Then
    MsgBox($MB_ICONERROR, "_TS_TaskPropertiesGet", "Returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))
Else
    If IsArray($vTaskProperties) Then 
        _ArrayColInsert($vTaskProperties, UBound($vTaskProperties, $UBOUND_COLUMNS))
        For $i = 0 To UBound($vTaskProperties, $UBOUND_ROWS) - 1
            $vTaskProperties[$i][UBound($vTaskProperties, $UBOUND_COLUMNS) - 1] = VarGetType($vTaskProperties[$i][2])
        Next
        _ArrayDisplay($vTaskProperties, "$vTaskProperties")
    Else
        MsgBox($MB_OK, "PRINCIPAL", $vTaskProperties & @CRLF & @CRLF &  "Type: " & VarGetType($vTaskProperties))
    EndIf 
EndIf

I was able to plug in the new _TS_TaskRegister, and it worked without issue in my testing scripts and the examples.  

Good work.  

 

Adam

Link to comment
Share on other sites

Thanks for the heads up :)

Have added a remark in the UDF.

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Hi water,

In my testing, I'm having an issue with editing an existing task.  I ran _TS_TaskCreate.au3 to create a test task.  I then tried to edit the action properties to add an action.  When I tried _TS_ActionCreate to create the action object, I get @error 402 and @extended 1.  The Temp.au3 is the file you posted above, and TaskScheduler.au3 has those function commanded out.  The test script is below.  

#RequireAdmin

#include <Array.au3>
#include <Debug.au3>
#include "TaskScheduler.au3"
#include "Temp.au3"

Global $sTaskName = "Test-Task"
Global $sTaskFolder = "\Test"
Global $sTask = $sTaskFolder & (($sTaskFolder = "\") ? ("") : ("\")) & $sTaskName
Global $oTask = Null

; Connect to the Task Scheduler Service
Global $oService = _TS_Open()

$oTask = _TS_TaskGet($oService, $sTask)
If Not @error Then
    MsgBox($MB_ICONINFORMATION, "_TS_TaskGet", "Task found:" & @CRLF & "  Name: " & $oTask.Name & @CRLF & "  Path: " & $oTask.Path)
Else
    MsgBox($MB_ICONERROR, "_TS_TaskGet", "Returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))
EndIf

Global $aProperties[] = ['ACTIONS|Path|calc']

; Create an Action
Global $oAction = _TS_ActionCreate($oService, $oTask, $TASK_ACTION_EXEC, "Test-Action")
If @error Then Exit MsgBox($MB_ICONERROR, "_TS_TaskCreate", "Creating the Action returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))
_TS_TaskPropertiesSet($oAction, $aProperties)
If @error Then Exit MsgBox($MB_ICONERROR, "_TS_TaskCreate", "_TS_TaskPropertiesSet for the TaskDefinition returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))

Global $vTaskProperties = _TS_TaskPropertiesGet($oService, $sTask, 1, True, "ACTIONS")
;~ Global $vTaskProperties = _TS_TaskPropertiesGet($oService, $sTask, 1, True, "ACTIONS", "Path")
If @error Then
    MsgBox($MB_ICONERROR, "_TS_TaskPropertiesGet", "Returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))
Else
    If IsArray($vTaskProperties) Then 
        _ArrayDisplay($vTaskProperties, "_TS_TaskPropertiesGet")
    Else
        MsgBox($MB_OK, "$vTaskProperties", $vTaskProperties)
    EndIf 
EndIf

_TS_Close()

Adam

Edited by AdamUL
Link to comment
Share on other sites

I had a quick look and I think it is a bug.
All those functions have to cope with a task that is about to be created (which means a Task Definition object is passed to the function) and an already registered Task (which means the function gets a Task object).
At the moment those functions do not handle a Task object correctly.

Will be fixed quite soon :)

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Hi water,

Thank you for working on this.  I have more to report.  I found how to get the task definition object for an existing task.  I am using it to test functions with existing tasks.  There is an issue with _TS_TaskRegister, when you try to re-register the updated task.  It failed with error 2103.  For testing, I commented out the _TS_TaskExist check and, it failed with 2106.  In the RegisterTaskDefinition line, I changed $TASK_CREATE to $TASK_CREATE_OR_UPDATE, and the task was updated without issue.  I have updated the function adding an additional parameter $bUpdateTask.  I also create a wrapper function, _TS_TaskUpdateRegister, that has $bUpdateTask set to true.  Below is the updated test script, and attached is the updated Temp.au3 with the updated functions.  As before, TaskScheduler.au3 has those function commanded out.  

#RequireAdmin

#include <Array.au3>
#include "TaskScheduler.au3"
#include "Temp.au3"

Global $sTaskName = "Test-Task"
Global $sTaskFolder = "\Test"
Global $sTask = $sTaskFolder & (($sTaskFolder = "\") ? ("") : ("\")) & $sTaskName
Global $oTask = Null
Global $oTaskDefinition = Null

; Connect to the Task Scheduler Service.
Global $oService = _TS_Open()

; Get Task Object.
$oTask = _TS_TaskGet($oService, $sTask)
If Not @error Then
    MsgBox($MB_ICONINFORMATION, "_TS_TaskGet", "Task found:" & @CRLF & "  Name: " & $oTask.Name & @CRLF & "  Path: " & $oTask.Path)
Else
    MsgBox($MB_ICONERROR, "_TS_TaskGet", "Returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))
EndIf

; Get Task Definition Object.
$oTaskDefinition = $oTask.Definition

Global $aProperties[] = ['ACTIONS|Path|calc']

; Create an Action.
Global $oAction = _TS_ActionCreate($oService, $oTaskDefinition, $TASK_ACTION_EXEC, "Test-Action2")
If @error Then Exit MsgBox($MB_ICONERROR, "_TS_ActionCreate", "Creating the Action returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))
_TS_TaskPropertiesSet($oAction, $aProperties)
If @error Then Exit MsgBox($MB_ICONERROR, "_TS_TaskPropertiesSet", "_TS_TaskPropertiesSet for the TaskDefinition returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))

; Re-register the Updated Task.
;~ $oTask = _TS_TaskRegister($oService, $sTaskFolder, $sTaskName, $oTaskDefinition, Default, Default, Default, True)
$oTask = _TS_TaskUpdateRegister($oService, $sTaskFolder, $sTaskName, $oTaskDefinition)
If @error Then Exit MsgBox($MB_ICONERROR, "__TS_TaskRegister", "_TS_TaskRegister returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))

; Check Task Properties.
Global $vTaskProperties = _TS_TaskPropertiesGet($oService, $sTask, 1, True, "ACTIONS")
;~ Global $vTaskProperties = _TS_TaskPropertiesGet($oService, $sTask, 1, True, "ACTIONS", "Path")
If @error Then
    MsgBox($MB_ICONERROR, "_TS_TaskPropertiesGet", "Returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))
Else
    If IsArray($vTaskProperties) Then 
        _ArrayDisplay($vTaskProperties, "_TS_TaskPropertiesGet")
    Else
        MsgBox($MB_OK, "$vTaskProperties", $vTaskProperties)
    EndIf 
EndIf

_TS_Close()

 

Adam

 

Temp.au3

Link to comment
Share on other sites

Thanks for the heads up.
When working on the ActionCreate function I noticed that the UDF currently is too focused on creating Tasks. Modifying existing tasks has some severe problems right now.

I have modified _TS_TaskRegister so you can now specify the TASK_CREATE flag to create, update ... a Task. The TaskExist checks are only done when needed.

; #FUNCTION# ====================================================================================================================
; Name...........: _TS_TaskRegister
; Description ...: Register or update a Task.
; Syntax.........: _TS_TaskRegister($oService, $sFolder, $sName, $oTaskDefinition, $sUserId = "", $sPassword = "", $iLogonType = Default, $iCreateFlag = $TASK_CREATE)
; Parameters ....: $oService        - Task Scheduler Service object as returned by _TS_Open
;                  $sFolder         - Folder where the Task should be created
;                  $sName           - Name of the Task
;                  $oTaskDefinition - Task Definition object as created by _TS_TaskCreate and filled by _TS_TaskPropertiesSet
;                  $sUserId         - Optional: The user credentials that are used to register the Task. If present, these credentials
;                                     take priority over the credentials specified in the Task Definition object pointed to by the definition parameter
;                  $sPassword       - Optional: The password for the UserId that is used to register the Task. When the TASK_LOGON_SERVICE_ACCOUNT logon type
;                                     is used, the password must be an empty value such as NULL or ""
;                  $iLogonType      - Optional: Can be any of the TASK_LOGON_TYPE constants enumeration. For the default please check Remarks
;                  $iCreateFlag     - Optional: Defines if to create or update the task. Can be any of the TASK_CREATE constants enumeration. Default is $TASK_CREATE
; Return values .: Success - Task object
;                  Failure - Returns 0 and sets @error:
;                  |2101 - Parameter $oService is not an object or not an ITaskService object
;                  |2102 - $sFolder does not exist or an error occurred in _TS_FolderExists. @extended is set to the COM error (if any)
;       modified   |2103 - Task exists which is incompatible with flags $TASK_CREATE, $TASK_DISABLE and $TASK_CREATE or
;                  |       Task does not exist which is incompatible with flags $TASK_UPDATE And $TASK_DONT_ADD_PRINCIPAL_ACE
;                  |2104 - Parameter $oTaskDefinition is not an object or not an ITaskDefinition object
;                  |2105 - Error accessing $sFolder using _TS_FolderGet. @extended is set to the COM error
;                  |2106 - Error creating the Task. @extended is set to the COM error
; Author ........: water
; Modified.......:
; Remarks .......: If the logon type has been set in the Principal sub-object then $TASK_LOGON_NONE is the default to not overwrite the existing setting.
;                  Else $TASK_LOGON_INTERACTIVE_TOKEN will be used as default.
; Related .......:
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _TS_TaskRegister($oService, $sFolder, $sName, $oTaskDefinition, $sUserId = Default, $sPassword = Default, $iLogonType = Default, $iCreateFlag = Default)
    If $sUserId = Default Then $sUserId = ""
    If $sPassword = Default Then $sPassword = ""
    If $iLogonType = Default Then
        If $oTaskDefinition.Principal.LogonType <> 0 Then
            $iLogonType = $TASK_LOGON_NONE
        Else
            $iLogonType = $TASK_LOGON_INTERACTIVE_TOKEN
        EndIf
    EndIf
    If $iCreateFlag = Default Then $iCreateFlag = $TASK_CREATE
    If Not IsObj($oService) Or ObjName($oService) <> "ITaskService" Then Return SetError(2101, 0, 0)
    If Not _TS_FolderExists($oService, $sFolder) Then Return SetError(2102, @error, 0)
    If ($iCreateFlag = $TASK_CREATE Or $iCreateFlag = $TASK_DISABLE Or $iCreateFlag = $TASK_IGNORE_REGISTRATION_TRIGGERS) AND _
        _TS_TaskExists($oService, $sFolder & "\" & $sName) Then
        Return SetError(2103, @error, 0)
    ElseIf ($iCreateFlag = $TASK_UPDATE Or $iCreateFlag = $TASK_DONT_ADD_PRINCIPAL_ACE) AND Not _TS_TaskExists($oService, $sFolder & "\" & $sName) Then
        Return SetError(2103, @error, 0)
    EndIf
    If Not IsObj($oTaskDefinition) Or ObjName($oTaskDefinition) <> "ITaskDefinition" Then Return SetError(2104, 0, 0)
    ; Register (create) the Task
    Local $oFolder = _TS_FolderGet($oService, $sFolder)
    If @error Then Return SetError(2105, @error, 0)
    Local $oTask = $oFolder.RegisterTaskDefinition($sName, $oTaskDefinition, $iCreateFlag, $sUserId, $sPassword, $iLogonType)
    If @error Then Return SetError(2106, @error, 0)
    Return $oTask
EndFunc   ;==>_TS_TaskRegister

 

In addition I have played with the ActionCreate function to add Actions to an existing Task but unfortunately handling of a Registered Task and a Task Definition for a new Task in the same function not work at the moment.

Will keep you informed :)

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Your welcome.  

In my testing, I haven't had issues adding an action with the current _TS_ActionCreate and _TS_Wrapper_ActionCreate to an existing task, after got it's task definition using the following.  

;Get Task Object.
$oTask = _TS_TaskGet($oService, $sTask)

; Get Task Definition Object.
$oTaskDefinition = $oTask.Definition

For the example scripts below, adding the max 32 actions to an existing task, was not an issue.  Temp.au3 with the updated _TS_TaskRegister function above.  As before, TaskScheduler.au3 has those function commanded out.  The first script uses _TS_ActionCreate and the second uses _TS_Wrapper_ActionCreate.

;Adding Actions to an existing task using _TS_ActionCreate
#RequireAdmin

#include <Array.au3>
#include "TaskScheduler.au3"
#include "Temp.au3"

Global $sTaskName = "Test-Task"
Global $sTaskFolder = "\Test"
Global $sTask = $sTaskFolder & (($sTaskFolder = "\") ? ("") : ("\")) & $sTaskName
Global $sTaskNew = $sTask & "-New"
Global $oTask = Null
Global $oTaskDefinition = Null

; Connect to the Task Scheduler Service.
Global $oService = _TS_Open()

; Get Task Object.
$oTask = _TS_TaskGet($oService, $sTask)
If Not @error Then
    MsgBox($MB_ICONINFORMATION, "_TS_TaskGet", "Task found:" & @CRLF & "  Name: " & $oTask.Name & @CRLF & "  Path: " & $oTask.Path)
Else
    MsgBox($MB_ICONERROR, "_TS_TaskGet", "Returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))
EndIf

; Get Task Definition Object.
$oTaskDefinition = $oTask.Definition

; Add 31 more Actions to get to the Max 32 Actions
For $i = 2 To 32
    
    Global $aProperties[] = ['ACTIONS|Path|"C:\Test\test' & $i & '.exe"', 'ACTIONS|Arguments|/r /t', 'ACTIONS|WorkingDirectory|"' & @ScriptDir & '\' & $i & '"']

    ; Create an Action
    Global $oAction = _TS_ActionCreate($oService, $oTaskDefinition, $TASK_ACTION_EXEC, "Test-Action" & $i)
    If @error Then Exit MsgBox($MB_ICONERROR, "_TS_ActionCreate", "Creating the Action returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))

    _TS_TaskPropertiesSet($oAction, $aProperties)
    If @error Then Exit MsgBox($MB_ICONERROR, "_TS_TaskPropertiesSet", "_TS_TaskPropertiesSet for the TaskDefinition returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))

Next

; Register to update the task.
$oTask = _TS_TaskRegister($oService, $sTaskFolder, $sTaskName, $oTaskDefinition, Default, Default, Default, $TASK_UPDATE)
If @error Then Exit MsgBox($MB_ICONERROR, "_TS_TaskRegister", "_TS_TaskRegister returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))

; Check that Actions were added.
Global $vTaskProperties = _TS_TaskPropertiesGet($oService, $sTask, 1, True, "ACTIONS")
;~ Global $vTaskProperties = _TS_TaskPropertiesGet($oService, $sTask, 1, True, "ACTIONS", "Path")
If @error Then
    MsgBox($MB_ICONERROR, "_TS_TaskPropertiesGet", "Returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))
Else
    If IsArray($vTaskProperties) Then 
        _ArrayDisplay($vTaskProperties, "_TS_TaskPropertiesGet")
    Else
        MsgBox($MB_OK, "$vTaskProperties", $vTaskProperties)
    EndIf 
EndIf

_TS_Close()
;Adding Actions to an existing task using _TS_Wrapper_ActionCreate
#RequireAdmin

#include <Array.au3>
#include "TaskScheduler.au3"
#include "Temp.au3"

Global $sTaskName = "Test-Task"
Global $sTaskFolder = "\Test"
Global $sTask = $sTaskFolder & (($sTaskFolder = "\") ? ("") : ("\")) & $sTaskName
Global $sTaskNew = $sTask & "-New"
Global $oTask = Null
Global $oTaskDefinition = Null

; Connect to the Task Scheduler Service.
Global $oService = _TS_Open()

; Get Task Object.
$oTask = _TS_TaskGet($oService, $sTask)
If Not @error Then
    MsgBox($MB_ICONINFORMATION, "_TS_TaskGet", "Task found:" & @CRLF & "  Name: " & $oTask.Name & @CRLF & "  Path: " & $oTask.Path)
Else
    MsgBox($MB_ICONERROR, "_TS_TaskGet", "Returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))
EndIf

; Get Task Definition Object.
$oTaskDefinition = $oTask.Definition

; Add 31 more Actions to get to the Max 32 Actions
For $i = 2 To 32

    ; Create an Action
    _TS_Wrapper_ActionCreate($oTaskDefinition, '"C:\Test\test' & $i & '.exe"', '"' & @ScriptDir & '\' & $i & '"', "/r /t")
    If @error Then Exit MsgBox($MB_ICONERROR, "_TS_Wrapper_ActionCreate", "_TS_Wrapper_ActionCreate returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))

Next

; Register to update the task.
$oTask = _TS_TaskRegister($oService, $sTaskFolder, $sTaskName, $oTaskDefinition, Default, Default, Default, $TASK_UPDATE)
If @error Then Exit MsgBox($MB_ICONERROR, "_TS_TaskRegister", "_TS_TaskRegister returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))

; Check that Actions were added.
Global $vTaskProperties = _TS_TaskPropertiesGet($oService, $sTask, 1, True, "ACTIONS")
;~ Global $vTaskProperties = _TS_TaskPropertiesGet($oService, $sTask, 1, True, "ACTIONS", "Path")
If @error Then
    MsgBox($MB_ICONERROR, "_TS_TaskPropertiesGet", "Returned @error=" & @error & ", @extended=" & @extended & @CRLF & @CRLF & _TS_ErrorText(@error))
Else
    If IsArray($vTaskProperties) Then 
        _ArrayDisplay($vTaskProperties, "_TS_TaskPropertiesGet")
    Else
        MsgBox($MB_OK, "$vTaskProperties", $vTaskProperties)
    EndIf 
EndIf

_TS_Close()

We could have a function to get the task definition of an existing task using the code from the _TS_TaskGet function.  Maybe a _TS_TaskDefinitionGet function?  

; #FUNCTION# ====================================================================================================================
; Name...........: _TS_TaskDefinitionGet
; Description ...: Returns the Task Definition object of a single Task.
; Syntax.........: _TS_TaskDefinitionGet($oService, $sTaskPath)
; Parameters ....: $oService  - Task Scheduler Service object as returned by _TS_Open
;                  $sTaskPath - Task path (Folder plus Task name) to process
; Return values .: Success - Task Definition Object of the Task
;                  Failure - Returns 0 and sets @error:
;                  |1601 - Error accessing the specified Taskfolder. @extended is set to the COM error code
;                  |1602 - Error retrieving the Tasks collection. @extended is set to the COM error code
;                  |1603 - Task with the specified name could not be found in the Task Folder
; Author ........: water
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _TS_TaskDefinitionGet($oService, $sTaskPath)
    Local $sFolder, $oFolder, $sTaskName, $oTask, $oTasks, $iPos, $bHidden = 1
    $iPos = StringInStr($sTaskPath, "\", 0, -1)
    $sTaskName = StringMid($sTaskPath, $iPos + 1)
    $sFolder = ($iPos = 1) ? "\" : (StringLeft($sTaskPath, $iPos - 1))
    $oFolder = $oService.GetFolder($sFolder)
    If @error Then Return SetError(1601, @error, 0)
    $oTasks = $oFolder.GetTasks($bHidden)
    If @error Then Return SetError(1602, @error, 0)
    For $oTask In $oTasks
        If $oTask.Name = $sTaskName Then Return $oTask.Definition
    Next
    Return SetError(1603, 0, 0)
EndFunc   ;==>_TS_TaskGet

 

Adam

 

Link to comment
Share on other sites

I see. The problem was caused by a lack of sleep and coffee ;)
Function _TS_ActionCreate needs the TaskDefinition object passed as parameter. When passing the path of an Registered Task the Task object is created locally in the function by TaskGet.
When the function ends the Task object is lost and so is the created Action.

For the user to retrieve the Task Definition object we could add a parameter to TaskGet to return the Task Definition object and not the Task object. What do you think?

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

That sounds like a very good idea to me.  I see what you mean by the internal _TS_TaskGet for _TS_ActionCreate, when given a Task path.  I missed that because I was working with objects.  

 

Adam

 

Edited by AdamUL
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...