3 unstable releases

0.1.1 Jul 21, 2023
0.1.0 May 23, 2022
0.0.1 May 20, 2022

#1074 in Concurrency

MPL-2.0 license

29KB
567 lines

一个windows计划任务库demo

后面想法是要做成类似sql的可以增删改查的语法。


extern crate taskschd;

use std::ffi::{OsStr, OsString};
use std::path::Path;

use taskschd::taskschd::{hr_is_not_found, TaskService};
use taskschd::try_to_bstring;

#[test]
fn register() -> Result<(), failure::Error>{
    
    let task_name = try_to_bstring!("name")?;
    let task_folder = try_to_bstring!("\\")?;
    let task_exe = Path::new("C:\\Windows\\System32\\cmd.exe");
    let task_args = vec![OsString::from("/c ping 127.0.0.1 -t")];

    let mut service = TaskService::connect_local()?;

    // Get or create the folder
    let mut folder = service.get_folder(&task_folder).or_else(|e| {
        if hr_is_not_found(&e) {
            service
                .get_root_folder()
                .and_then(|mut root| root.create_folder(&task_folder))
        } else {
            Err(e)
        }
    })?;


    let start_time = folder
            .get_task(&task_name)
            .ok()
            .and_then(|mut task| task.get_definition().ok())
            .and_then(|mut def| def.get_daily_triggers().ok())
            .and_then(|mut triggers| {
                // Currently we are only using 1 daily trigger.
                triggers
                    .get_mut(0)
                    .and_then(|trigger| trigger.get_StartBoundary().ok())
            });

    let _ = folder.delete_task(&task_name);

    let mut task_def = service.new_task_definition()?;

    {


        let mut action = task_def.add_exec_action()?;
        action.put_Path(task_exe)?;
        //action.put_Arguments(task_args.as_slice())?;
        // TODO working directory?
    }

    {
        let mut settings = task_def.get_settings()?;
        settings.put_DisallowStartIfOnBatteries(false)?;
        settings.put_StopIfGoingOnBatteries(false)?;
        settings.put_StartWhenAvailable(true)?;
        settings.put_ExecutionTimeLimit(chrono::Duration::minutes(5))?;
    }

    {
        let mut info = task_def.get_registration_info()?;
        info.put_Author(&try_to_bstring!("author")?)?;
        info.put_Description(&try_to_bstring!("task test")?)?;
    }

    // A daily trigger starting 5 minutes ago.
    {
        let mut daily_trigger = task_def.add_daily_trigger()?;
        if let Some(ref start_time) = start_time {
            daily_trigger.put_StartBoundary_BString(start_time)?;
        } else {
            daily_trigger.put_StartBoundary(chrono::Utc::now() - chrono::Duration::minutes(5))?;
        }
        daily_trigger.put_DaysInterval(1)?;
        // TODO: 12-hourly trigger? logon trigger?
    }

    let service_account = Some(try_to_bstring!("NT AUTHORITY\\LocalService")?);

    let mut registered_task = task_def.create(&mut folder, &task_name, service_account.as_ref())?;

    let sddl = try_to_bstring!(concat!(
            "D:(",   // DACL
            "A;",    // ace_type = Allow
            ";",     // ace_flags = none
            "GRGX;", // rights = Generic Read, Generic Execute
            ";;",    // object_guid, inherit_object_guid = none
            "BU)"    // account_sid = Built-in users
        ))?;

    registered_task.set_sd(&sddl)?;
    
    Ok(())
}

#[test]
fn unregister() -> Result<(), failure::Error> {
    let task_name = try_to_bstring!("name")?;
    let task_folder = try_to_bstring!("\\")?;

    let mut service = TaskService::connect_local()?;
    let maybe_folder = service.get_folder(&task_folder);
    let mut folder = match maybe_folder {
        Err(e) => {
            if hr_is_not_found(&e) {
                return Ok(());
            } else {
                return Err(e.into());
            }
        }
        Ok(folder) => folder,
    };

    folder.delete_task(&task_name).or_else(|e| {
        if hr_is_not_found(&e) {
            Ok(())
        } else {
            // Other errors are fatal.
            Err(e)
        }
    })?;

    let count = folder.get_task_count(true).unwrap_or_else(|e| {
        1
    });

    if count == 0 {
        let result = service
            .get_root_folder()
            .and_then(|mut root| root.delete_folder(&task_folder));
    }

    Ok(())
}

#[test]
fn run_on_demand() -> Result<(), failure::Error> {
    let task_name = try_to_bstring!("name")?;
    let task_folder = try_to_bstring!("\\")?;

    let mut service = TaskService::connect_local()?;
    let task = service.get_folder(&task_folder)?.get_task(&task_name)?;

    task.run()?;

    Ok(())
}


Dependencies

~1–1.5MB
~21K SLoC