终端安全系列-计划任务详解

2023/08/03 20:54
阅读数 163

任务计划程序服务(Task Scheduler service)是Windows操作系统中的一个核心服务,它负责管理和执行计划任务。任务计划程序服务(Task Scheduler service)在后台运行,并由 svchost.exe 进程来托管。任务计划程序服务允许用户创建、编辑和删除计划任务。用户可以通过图形用户界面(Task Scheduler GUI)、命令行工具(如schtasks)或编程接口来管理计划任务,用于在预定的时间或特定事件发生时自动执行一系列任务。

通过Windows计划任务,用户可以:

    1. 定时运行程序:在指定的日期和时间,自动运行特定的应用程序、脚本或命令行工具。

    2. 自动化系统维护:例如,定期清理临时文件、备份数据,或者运行磁盘碎片整理等系统维护任务。

    3. 周期性任务:创建周期性任务,比如每天、每周或每月重复执行的操作。

    4. 响应触发事件:根据特定的系统事件(例如用户登录、系统启动等)来触发执行任务。

    5. 管理远程计算机:通过计划任务可以在网络上管理和运行远程计算机上的任务。

Windows计划任务提供了一个用户友好的界面,使用户能够轻松创建、编辑和管理这些计划任务。用户可以设置任务的触发条件、执行操作、设置任务的运行时期、安全选项等,可以通过Win + R键,打开运行对话框,输入"taskschd.msc",然后点击"确定",即可打开"任务计划程序",在该应用程序中,可以创建、编辑和管理计划任务。

1. 计划任务的结构

在Windows计划任务中,任务是通过一种层级结构进行组织和管理的。这个层级结构允许你将任务分组,使任务管理更加有条理和灵活。计划任务的层级结构包含以下几个层级:

  1. 根目录(Root Folder):

    • 根目录是整个计划任务层级结构的最上层,是所有其他文件夹和计划任务的父级。

    • 在任务计划程序的左侧任务树中,你会看到一个名为“Task Scheduler Library”(任务计划程序库)的根目录。

  1. 自定义文件夹(Custom Folders):

    • 在根目录下,你可以创建自定义文件夹,用于组织和分类计划任务。这些文件夹可以根据你的需要创建,并可以任意命名。

    • 自定义文件夹可以帮助你将相关的任务组合在一起,使管理更加方便。

  1. 计划任务(Scheduled Tasks):

    • 在自定义文件夹中,你可以创建计划任务,即具体的任务执行实例。每个计划任务包含了触发器、操作、条件、设置和安全性选项等任务的详细配置信息。

    • 一个自定义文件夹可以包含一个或多个计划任务。

任务的结构在Windows计划任务中通常包含以下主要部分:

  1. 任务定义(Task Definition):

    • 任务名称:每个计划任务都有一个唯一的名称,用于标识任务。

    • 描述:对任务的简短描述,说明任务的目的和功能。

    • 作者:任务的创建者或拥有者。

    • 安全选项:指定任务的安全设置,包括哪些用户可以运行任务以及任务需要哪些特定权限。

  1. 触发器(Triggers):

    • 触发器类型:Windows支持多种触发器类型,包括时间触发器、日程触发器、登录触发器、系统启动触发器、特定事件触发器等。

    • 触发器设置:根据不同类型的触发器,你可以设置触发任务的具体条件。例如,时间触发器可以指定在某个日期和时间执行任务,日程触发器可以指定每天、每周的哪些日期执行任务,特定事件触发器可以指定在某个特定事件发生时执行任务等。

  1. 操作(Actions):

    • 操作类型:你可以指定任务执行时要运行的操作类型,可以是一个程序、脚本或命令行工具。

    • 操作设置:根据操作类型,你可以指定要运行的可执行文件或脚本文件的路径,以及传递给该程序的参数。

  1. 条件(Conditions):

    • 开始条件:你可以设置任务只有在满足一定条件时才开始执行。例如,任务可能需要在计算机空闲时执行,或者仅当计算机处于特定电源状态(如电源插入或电池供电)时才执行。

    • 停止条件:你可以指定任务在满足一定条件时停止执行。例如,任务可能会在任务开始后的一段时间内停止,或者在某个特定的事件发生后停止。

  1. 设置(Settings):

    • 允许任务在不登录用户的情况下运行:如果选中此选项,任务可以在没有用户登录的情况下运行。

    • 运行任务时是否停止所有实例:如果任务已经在运行,你可以选择启动一个新的实例时是否停止已有的任务。

    • 如果任务运行时间超过,停止任务:你可以设置任务的最大运行时间,并在超过该时间时停止任务的执行。

可以通过任务计划程序(如图所示)查看Windows计划任务的结构,在左侧面板,你会看到任务树,其中列出了计划任务的层级结构,在右侧面板,你会看到任务列表,其中显示了所选文件夹或计划任务的详细信息。这包括任务的名称、描述、状态以及下一次触发的时间等信息,同时在右边可以新建计划任务等等操作,这里不作讨论。

2. 与计划任务相关的DLL

        “taskschd.dll”和“taskcomp.dll”都是Windows 任务计划程序服务使用的动态链接库(DLL)。

2.1. taskschd.dll

taskschd.dll 是任务计划程序的主要 DLL,它提供了在 Windows 中管理计划任务的核心功能和接口。它包含各种函数和接口,应用程序可以使用这些函数和接口来编程与任务计划程序服务进行交互。以下是一些 taskschd.dll 支持的主要 API:

  1. ITaskScheduler 接口:用于创建和管理计划任务。主要包括以下方法:

    • NewWorkItem: 创建一个新的计划任务。

    • AddWorkItem: 将计划任务添加到计划任务文件夹中。

    • Delete: 删除指定的计划任务。

    • SetTargetComputer: 设置计划任务所属的目标计算机。

    • IsOfType: 检查计划任务的类型。

  1. ITask 接口:用于操作计划任务的属性和状态。主要包括以下方法:

    • Activate: 激活计划任务。

    • GetApplicationName: 获取计划任务的应用程序名称。

    • SetApplicationName: 设置计划任务的应用程序名称。

    • GetParameters: 获取计划任务的参数。

    • SetParameters: 设置计划任务的参数。

  1. IRegisteredTask 接口:用于操作已注册的计划任务。主要包括以下方法:

    • GetName: 获取计划任务的名称。

    • GetPath: 获取计划任务的完整路径。

    • GetState: 获取计划任务的状态。

    • GetRunTimes: 获取计划任务的运行时间。

  1. ITaskFolder 接口:用于操作计划任务文件夹。主要包括以下方法:

    • GetTask: 获取文件夹中指定名称的计划任务。

    • CreateFolder: 在当前文件夹中创建一个新的子文件夹。

    • DeleteFolder: 删除文件夹。

    • MoveTaskHere: 将计划任务从另一个文件夹移动到当前文件夹。

2.2. taskcomp.dll

    • 文件名:taskcomp.dll

    • 描述:taskcomp.dll 是任务计划程序 COM API DLL。

    • 作用:它提供了用于与任务计划程序服务进行交互的 COM (Component Object Model) 接口。它允许应用程序使用基于 COM 的编程来安排、修改或管理任务。

taskcomp.dll 是计划任务组件的 DLL 文件,它是 taskschd.dll 的辅助 DLL,用于支持任务计划程序的某些功能。taskcomp.dll 主要包含以下 API:

  1. ITaskHandler 接口:用于定义计划任务的处理程序。任务计划程序可以通过注册处理程序来执行自定义操作。主要包括以下方法:

    • Start: 启动计划任务的执行。

    • Stop: 停止计划任务的执行。

    • Pause: 暂停计划任务的执行。

    • Resume: 恢复计划任务的执行。

  1. ITaskHandlerStatus 接口:用于获取计划任务处理程序的状态信息。主要包括以下方法:

    • UpdateStatus: 更新计划任务处理程序的状态信息。

  1. ITaskHandlerConsole 接口:用于与计划任务处理程序交互的控制台界面。主要包括以下方法:

    • TaskHandlerCallback: 处理计划任务处理程序发送的回调消息。

  1. ITaskScheduler 接口:与 taskschd.dll 中的 ITaskScheduler 接口相同,用于创建和管理计划任务。主要包括以下方法:

    • NewWorkItem: 创建一个新的计划任务。

    • AddWorkItem: 将计划任务添加到计划任务文件夹中。

    • Delete: 删除指定的计划任务。

    • SetTargetComputer: 设置计划任务所属的目标计算机。

    • IsOfType: 检查计划任务的类型。

taskcomp.dll 主要用于支持计划任务处理程序的执行和交互,使开发者能够为计划任务定义自定义的执行逻辑,并与处理程序进行交互。

总结一下,taskschd.dll 负责提供任务计划程序的核心功能,而 taskcomp.dll 则通过 COM 接口暴露任务计划程序服务,使应用程序可以通过基于 COM 的编程与任务计划程序进行交互。

3. 任务计划程序服务分析

在进程中我们可以很明显定位到任务计划程序服务(Task Scheduler service)的主进程;

获取对应的PID使用Process Moniter进行监视运行,可以看到新建的计划任务会读取注册表,计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache 是Windows操作系统中存储计划任务信息的一部分注册表路径。在这个路径下,Windows保存了计划任务的一些配置信息,但并非所有计划任务的完整设置,而是一些缓存和元数据信息。

该注册表路径下的主要子项如下:

  1. Tasks:包含计划任务的配置信息。每个计划任务都有一个唯一的GUID(全局唯一标识符)作为其子项,这些GUID是任务的唯一标识符。在每个GUID子项下,保存了任务的详细配置信息,包括任务的触发器、操作和设置。

  2. Boot:包含系统启动时执行的计划任务的缓存信息。

  3. Logon:包含用户登录时执行的计划任务的缓存信息。

  4. Maintenance:包含系统维护任务的缓存信息。

  5. Cache:包含计划任务的缓存信息。

  6. Maintenance Config Cache:包含系统维护任务的配置缓存信息。

  7. Plain Cache:包含计划任务的缓存信息。

  8. RAC:包含计划任务相关的RAC(Run Once Registration)信息。

  9. Retries:包含计划任务的重试信息。

  10. Tasks{Task GUID}\Instances:每个计划任务的子项下有一个Instances子项,该子项包含任务的实例,即任务按照触发器条件多次执行的不同实例。

  11. Tasks{Task GUID}\LogonTriggerDelay:该子项包含计划任务的登录触发器延迟信息。

往下可以看到新建了一个文件夹,并新建了一个与我们同名的文件,打开为一个XML文件,可以知道计划任务的详细配置信息是保存在C:\Windows\System32\Tasks\[计划任务名]XML文件中的,而不是直接保存在注册表中。

在这个文件夹中,每个计划任务都有一个对应的XML文件,保存了包含计划任务的触发器、操作、条件、设置等信息。任务的完整配置。

可以使用下面Powershell脚本来解析计划任务的 XML 配置文件

# 指定XML文件路径$xmlFilePath = "C:\Path\to\your\Task.xml"
# 创建XmlDocument对象并加载XML文件$xmlDocument = New-Object System.Xml.XmlDocument$xmlDocument.Load($xmlFilePath)
# 创建XML命名空间管理器$nsManager = New-Object System.Xml.XmlNamespaceManager($xmlDocument.NameTable)$nsManager.AddNamespace("ns", $xmlDocument.DocumentElement.NamespaceURI)
# 获取根节点$rootNode = $xmlDocument.DocumentElement
# 获取子节点的值$taskVersion = $rootNode.GetAttribute("version")$namespace = $rootNode.NamespaceURI
# 获取RegistrationInfo节点的子节点值$registrationInfoNode = $rootNode.SelectSingleNode("//ns:RegistrationInfo", $nsManager)if ($registrationInfoNode -ne $null) { $date = $registrationInfoNode.SelectSingleNode("ns:Date", $nsManager).InnerText $author = $registrationInfoNode.SelectSingleNode("ns:Author", $nsManager).InnerText}
# 获取Triggers节点下的TimeTrigger子节点值$triggersNode = $rootNode.SelectSingleNode("//ns:Triggers", $nsManager)if ($triggersNode -ne $null) { $timeTriggerNode = $triggersNode.SelectSingleNode("//ns:TimeTrigger", $nsManager) if ($timeTriggerNode -ne $null) { $startBoundary = $timeTriggerNode.SelectSingleNode("ns:StartBoundary", $nsManager).InnerText $isEnabled = $timeTriggerNode.SelectSingleNode("ns:Enabled", $nsManager).InnerText }}
# 获取Actions节点下的Exec子节点值$actionsNode = $rootNode.SelectSingleNode("//ns:Actions", $nsManager)if ($actionsNode -ne $null) { $execNode = $actionsNode.SelectSingleNode("//ns:Exec", $nsManager) if ($execNode -ne $null) { $command = $execNode.SelectSingleNode("ns:Command", $nsManager).InnerText }}
# 输出解析的结果Write-Host "任务版本:$taskVersion"Write-Host "XML命名空间:$namespace"Write-Host "注册日期:$date"Write-Host "作者:$author"Write-Host "启动边界:$startBoundary"Write-Host "触发器是否启用:$isEnabled"Write-Host "执行命令:$command"

在CMD中可以使用schtasks /query 命令获取计划任务的信息,schtasks /query /xml 指定 /xml 参数可以以XML格式列出计划任务的配置信息,包括任务的详细设置和触发器。

        在Powershell中可以通过Get-ScheduledTask cmdlet 来获取计划任务详细信息,

4. 新建计划任务

新建计划任务的方法有多种,包括使用图形用户界面 (GUI) 工具、使用 PowerShell 命令以及使用系统自带的命令行工具。但是我们想要做的的是怎么样绕过终端安全进行写计划任务进行权限维持。

4.1. 使用 schtasks.exe 命令

方法一:使用 schtasks.exe 命令来创建计划任务。例如:

schtasks /Create /TN "MyTask" /TR "C:\MyScript.bat" /SC DAILY /ST 09:00

但是如果是在存在签名的Chrome进行写计划任务360是没有拦截的,基本可以判断360对使用schtasks 添加计划任务的拦截是判断添加计划任务的主体是否可信任。

4.2. 使用Powershell的cmdlet

在管理员权限下使用Powershell Register-ScheduledTask cmdlet来创建计划任务。例如

Register-ScheduledTask -TaskName "MyTask" -Trigger (New-ScheduledTaskTrigger -AtLogon) -Action (New-ScheduledTaskAction -Execute "C:\MyScript.ps1") 

360是没有任何反应的。

使用 New-ScheduledTask cmdlet 来创建计划任务。在高权限下同样没有拦截,例如:

# 创建计划任务的触发器$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 3) -RepetitionDuration (New-TimeSpan -Days 1)# 重复持续时间设置为 1 天# 创建计划任务的操作$action = New-ScheduledTaskAction -Execute "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -Argument "-file C:\Users\shi001admin\Desktop\test.ps1"# 创建计划任务对象$task = New-ScheduledTask -Action $action -Trigger $trigger# 注册计划任务并指定任务名称Register-ScheduledTask -TaskName "MyTask" -InputObject $task

4.3. 使用COM接口

但是Register-ScheduledTask和New-ScheduledTask创建计划任务都需要Administrator权限,通用性不太好,那么我们可以通过WMI和COM进行创建计划任务,在 Windows 系统中,用于创建计划任务的 COM 接口主要有两个:

  1. Task Scheduler Scripting Object Model (TaskScheduler):

    • 命名空间:Schedule.Service

    • 接口:IRegisteredTask、ITaskFolder

    • 用途:用于创建、修改和删除计划任务。

  1. Task Scheduler 1.0 Object Library (TaskScheduler):

    • 命名空间:Schedule.TaskScheduler

    • 接口:ITask, ITaskTrigger, ITaskAction, ITaskSettings

    • 用途:用于创建、修改和删除计划任务。注意:Task Scheduler 1.0 Object Library 是较旧的 COM 接口,它在 Windows 7 及更早的系统版本中使用较多,较新的系统版本可能更推荐使用 Task Scheduler Scripting Object Model。

例如使用 "Task Scheduler Scripting Object Model" 接口:

# 创建计划任务的操作$action = New-Object -ComObject "Schedule.Service" -Property @{    "ActionType" = 0     # 0 表示运行程序,其他类型可参考相关文档    "Id" = 1             # 操作的 ID,可以设置为 1    "Path" = "C:\MyScript.ps1"   # 要执行的脚本路径}# 创建计划任务的触发器$trigger = New-Object -ComObject "Schedule.Service" -Property @{    "TriggerType" = 1     # 1 表示登录时触发,其他类型可参考相关文档}# 获取计划任务服务$service = New-Object -ComObject "Schedule.Service"$service.Connect()# 创建计划任务对象$rootFolder = $service.GetFolder("\")$taskDefinition = $service.NewTask(0)$taskDefinition.RegistrationInfo.Description = "My Task Description"$taskDefinition.Settings.Enabled = $true$taskDefinition.Settings.Hidden = $false$trigger = $taskDefinition.Triggers.Create(1)  # 1 表示登录时触发,其他类型可参考相关文档$trigger.Id = "Trigger1"$trigger.StartBoundary = (Get-Date).AddMinutes(1).ToString("yyyy-MM-ddTHH:mm:ss")$trigger.Enabled = $true$action = $taskDefinition.Actions.Create(0)  # 0 表示运行程序,其他类型可参考相关文档$action.Id = "Action1"$action.Path = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"$action.Arguments = "-ExecutionPolicy Bypass -File C:\MyScript.ps1"$rootFolder.RegisterTaskDefinition("MyTask", $taskDefinition, 6, $null, $null, 3)  # 6 表示 "TaskScheduler" 设置# 运行计划任务$task = $rootFolder.GetTask("MyTask")$task.Run("")

其他可以用来创建计划任务的接口还有:

  1. Task Scheduler Scripting Object Model (TaskScheduler): 这是用于创建计划任务的主要 COM 接口,支持创建、修改和删除计划任务。

  2. Task Scheduler 1.0 Type Library (TaskScheduler 1.0): 旧版本的任务计划程序接口,提供创建计划任务的功能。

  3. Task Scheduler 2.0 Interfaces (TaskScheduler 2.0): 新版本的任务计划程序接口,是 Task Scheduler Scripting Object Model 的改进版本,提供更多功能和灵活性。

  4. ITaskScheduler (ITaskScheduler): 这是旧版任务计划程序的接口,用于创建和管理计划任务。

  5. ITaskService (ITaskService): 这是新版任务计划程序的接口,允许创建、修改和删除计划任务。

  6. ITaskFolder (ITaskFolder): 用于创建和管理任务计划程序文件夹的接口。

  7. ITaskSettings (ITaskSettings): 用于设置计划任务属性的接口,例如执行条件、重复间隔等。

  8. IAction (IAction): 用于创建和管理计划任务操作的接口,例如运行程序、发送电子邮件等。

  9. IActionCollection (IActionCollection): 用于管理计划任务操作集合的接口,支持添加、删除和修改操作。

  10. ITaskTrigger (ITaskTrigger): 用于创建和管理计划任务触发器的接口,例如启动计划任务的时间、事件等。

  11. IPrincipal (IPrincipal): 用于设置计划任务的安全主体的接口,例如运行计划任务的用户和权限。

  12. ITaskHandler (ITaskHandler): 用于实现自定义计划任务处理程序的接口,允许使用自定义程序来处理计划任务。

  13. ITaskNamedValueCollection (ITaskNamedValueCollection): 用于管理计划任务的自定义属性的接口。

  14. ITaskService (ITaskService): 用于管理计划任务的服务接口,可以创建、删除、运行和停止计划任务。

  15. IRegisteredTask (IRegisteredTask): 用于表示已注册的计划任务的接口,可以获取和设置计划任务的属性。

  16. ITaskFolder (ITaskFolder): 用于管理计划任务文件夹的接口,可以创建和删除文件夹,以及获取文件夹中的计划任务列表。

  17. ITaskSettings (ITaskSettings): 用于管理计划任务的设置的接口,例如是否允许在电池供电时运行、是否允许在计算机空闲时运行等。

  18. IIdleSettings (IIdleSettings): 用于管理计划任务在计算机空闲时运行的设置的接口,例如计划任务的空闲超时时间等。

4.4. 使用.NET Framework 中的相关类

Microsoft.Win32.TaskScheduler 命名空间是 .NET Framework 中提供的用于操作计划任务的命名空间。它位于 TaskScheduler.dll 程序集中,可以用于创建、修改、删除以及管理计划任务。

以下是一些常用的类和接口在 Microsoft.Win32.TaskScheduler 命名空间中:

  1. TaskService: 代表计划任务服务,用于连接到计划任务服务,创建和管理计划任务。

  2. TaskDefinition: 代表计划任务定义,用于设置计划任务的各种属性,如触发器、动作、安全选项等。

  3. Trigger: 代表计划任务的触发器,用于设置计划任务的触发条件,例如时间触发器、日程触发器等。

  4. Action: 代表计划任务的动作,用于设置计划任务要执行的操作,如运行程序、调用 PowerShell 脚本等。

  5. ExecAction: 是 Action 类的一个特定实现,用于设置运行程序的动作。

  6. TimeTrigger: 是 Trigger 类的一个特定实现,用于设置时间触发器的属性。 


例如可以使用使用 TaskScheduler 类库来创建和管理计划任务:

    1.引用 Microsoft.Win32.TaskScheduler 程序集,在 Visual Studio 中通过 NuGet 包管理器安装此程序集,或者手动将它添加到项目的引用中。

2.使用Microsoft.Win32.TaskScheduler程序集中的TaskService类和TaskDefinition类来创建计划任务。

using System;using Microsoft.Win32.TaskScheduler;
class Program{ static void Main() { string taskName = "MyTask"; string command = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"; string arguments = "-ExecutionPolicy Bypass -File C:\\MyScript.ps1"; DateTime startTime = DateTime.Now.AddMinutes(1); bool runRepeatedly = true;
using (TaskService taskService = new TaskService()) { TaskDefinition taskDefinition = taskService.NewTask();
// 设置计划任务的基本属性 taskDefinition.RegistrationInfo.Description = "My Task Description"; taskDefinition.Settings.AllowDemandStart = true; taskDefinition.Settings.DisallowStartIfOnBatteries = false; taskDefinition.Settings.StopIfGoingOnBatteries = false;
// 设置触发器,这里使用时间触发器,表示在 startTime 后重复执行 TimeTrigger trigger = new TimeTrigger(startTime); trigger.Repetition.Interval = TimeSpan.FromMinutes(3); // 每3分钟重复执行
// 设置重复执行的持续时间,例如设置为2天 trigger.Repetition.Duration = TimeSpan.FromDays(2);
taskDefinition.Triggers.Add(trigger);
// 设置执行操作,这里是调用 PowerShell 脚本 ExecAction action = new ExecAction(command, arguments); taskDefinition.Actions.Add(action);
// 注册计划任务 taskService.RootFolder.RegisterTaskDefinition(taskName, taskDefinition);
Console.WriteLine("Task created successfully."); } }}

4.5. 使用WMI

使用 WMI (Windows Management Instrumentation) 来创建计划任务需要调用 Win32_ScheduledJob 类。但是,请注意在 Windows 10 和较新的 Windows 版本中,Win32_ScheduledJob 类已被弃用,并且不再推荐使用,这里不再讨论。

using System;using System.Management;
class Program{ static void Main() { string taskName = "MyTask"; string command = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"; string arguments = "-ExecutionPolicy Bypass -File C:\\MyScript.ps1"; DateTime startTime = DateTime.Now.AddMinutes(1); bool runRepeatedly = true;
string xml = $@" <Task xmlns='http://schemas.microsoft.com/windows/2004/02/mit/task'> <RegistrationInfo> <Description>My Task Description</Description> </RegistrationInfo> <Triggers> <TimeTrigger> <StartBoundary>{startTime:s}</StartBoundary> <Repetition> <Interval>PT3M</Interval> <Duration>PT1H</Duration> </Repetition> </TimeTrigger> </Triggers> <Settings> <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy> <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries> <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries> </Settings> <Actions> <Exec> <Command>{command}</Command> <Arguments>{arguments}</Arguments> </Exec> </Actions> </Task> ";
using (ManagementClass taskClass = new ManagementClass(@"root\cimv2", "Win32_ScheduledJob", null)) { ManagementBaseObject inParams = taskClass.GetMethodParameters("Create"); inParams["JobData"] = xml;
ManagementBaseObject outParams = taskClass.InvokeMethod("Create", inParams, null); int returnValue = Convert.ToInt32(outParams["ReturnValue"]);
if (returnValue == 0) { Console.WriteLine("Task created successfully."); } else { Console.WriteLine("Failed to create task. Error code: " + returnValue); } } }}


4.6. 使用Windows API

直接使用Windows API来创建计划任务,而无需依赖外部库或COM接口,这里的方法是调用TaskCreate“taskschd.dll”库中的方法来创建一个新任务。

using System;using System.Runtime.InteropServices;
class Program{ private const int ERROR_SUCCESS = 0; private const string TaskFolder = "\\MyTasks\\"; // The folder in which the task will be created
[DllImport("taskschd.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern int TaskCreate( string pwszTaskName, ref Guid rclsid, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out ITask pUnk);
[ComImport] [Guid("148BD520-A2AB-11CE-B11F-00AA00530503")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] private interface ITask { void SetApplicationName([MarshalAs(UnmanagedType.LPWStr)] string pwszApplicationName); void SetParameters([MarshalAs(UnmanagedType.LPWStr)] string pwszParameters); void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pwszWorkingDirectory); void SetFlags(uint dwFlags); void SetAccountInformation([MarshalAs(UnmanagedType.LPWStr)] string pwszAccountName, IntPtr pwszPassword); void SetCreator([MarshalAs(UnmanagedType.LPWStr)] string pwszCreatorName); void SetComment([MarshalAs(UnmanagedType.LPWStr)] string pwszComment); void SetTrigger(IntPtr pTrigger); void SetErrorRetryInterval(uint dwErrorRetryInterval); void SetErrorRetryCount(uint dwErrorRetryCount); }
static void Main() { string taskName = "MyTask"; string command = "C:\\Windows\\System32\\calc.exe"; string arguments = "";
Guid clsidTaskScheduler = new Guid("{148BD524-A2AB-11CE-B11F-00AA00530503}"); Guid iidITaskScheduler = new Guid("{148BD520-A2AB-11CE-B11F-00AA00530503}");
ITask task; int result = TaskCreate(taskName, ref clsidTaskScheduler, ref iidITaskScheduler, out task);
if (result == ERROR_SUCCESS) { // Set the task properties task.SetApplicationName(command); task.SetParameters(arguments); task.SetWorkingDirectory("C:\\Windows\\System32"); task.SetFlags(0); // 0 means run with default settings task.SetAccountInformation(null, IntPtr.Zero); // Run with the user's credentials task.SetCreator("MyTaskCreator"); task.SetComment("My Task Description");
// Set the trigger (e.g., run every day at a specific time) // ...
// Save the task // ...
Console.WriteLine("Task created successfully."); } else { Console.WriteLine("Failed to create task. Error code: " + result); } }}

5. 后记

通过任何方法添加计划任务时,实际上是将任务的配置信息添加到操作系统的计划任务服务中。这些配置信息包括任务的名称、触发器(例如时间触发器或事件触发器)、执行操作(例如运行程序或执行脚本)、重复规则等。

本文分享自微信公众号 - 黑白天实验室(li0981jing)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部