lunes, 1 de junio de 2015

El Demo del Día: Automatizar la Programación de Tareas de Windows en .NET

Automatizar la Programación de Tareas de Windows en .NET

Windows ofrece un servicio muy útil que permite ejecutar tareas programadas por fechas (Task Scheduler), este un gran complemento para ejecutar aplicaciones de consola como por ejemplo para actualización de aplicaciones y/o archivos, envío de notificaciones y/o mensajes de correos, backups, etc.

Requerimiento

Se desea crear una aplicación que permita automatizar la programación de tareas para no hacerla manualmente a través de la aplicación de consola taskschd.msc. Sino tener una aplicación personalizada que permita listar las tareas, crear una nueva tarea y eliminar una tarea existente.

Solución

Crearemos una aplicación Windows Forms .NET en C# que use la clase TaskService de la librería manejada Microsoft.Win32.TaskScheduler.dll que la podemos descargar libremente de la siguiente dirección: Task Scheduler Managed Wrapper

Crear una Aplicación Windows Forms en C#

Abrir Visual Studio y crear una aplicación Windows Forms en C# llamada "ProgramacionTareas", cambiarle de nombre al formulario por "frmListaTareas" y realizar el diseño similar a la figura mostrada:


Nota: En el diseño hay un ListView llamado "lvwTarea", un menú contextual llamado "mnuTarea" con 2 opciones: mnuNuevaTarea y mnuEliminarTarea.

Hacer una referencia a la librería: "Microsoft.Win32.TaskScheduler.dll" y escribir el siguiente código en el formulario "frmListaTareas":

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using net=System.Threading.Tasks;
using Microsoft.Win32.TaskScheduler; //TaskService

namespace ProgramacionTareas
{
    public partial class frmListaTareas : Form
    {
        public frmListaTareas()
        {
            InitializeComponent();
        }

        private void configurarListView()
        {
            lvwTarea.Columns.Add("Nombre de la Tarea", 400);
            lvwTarea.Columns.Add("Folder", 300);
            lvwTarea.Columns.Add("Status", 100);
            lvwTarea.View = View.Details;          
            lvwTarea.MultiSelect = false;
            lvwTarea.GridLines = true;
            lvwTarea.FullRowSelect = true;
            lvwTarea.HotTracking = true;
        }

        private void listarTareas(object sender, EventArgs e)
        {
            configurarListView();
            IEnumerable<Task> tareas = null;
            net.TaskScheduler ui =
                net.TaskScheduler.FromCurrentSynchronizationContext();
            System.Threading.Tasks.Task.Run(() =>
            {
                TaskService prog = new TaskService();
                tareas = prog.AllTasks;
            }).ContinueWith(x => mostrarTareas(tareas),ui);
        }

        private void seleccionarTareas(ListViewItem fila,Task tarea,string estado)
        {
            if (estado.Equals("Running"))
            {
                fila.ForeColor = Color.White;
                fila.BackColor = Color.Red;
            }
            if (tarea.Folder.Name.Equals("DSOFT"))
            {
                fila.ForeColor = Color.Yellow;
                fila.BackColor = Color.Green;
            }
        }

        private void mostrarTareas(IEnumerable<Task> tareas)
        {
            ListViewItem fila;
            string estado;
            foreach (Task tarea in tareas)
            {
                estado = tarea.State.ToString();
                fila = lvwTarea.Items.Add(tarea.Name);
                fila.SubItems.Add(tarea.Folder.Name);
                fila.SubItems.Add(estado);
                seleccionarTareas(fila, tarea, estado);
            }
        }

        private void crearNuevaTarea(object sender, EventArgs e)
        {
            frmNuevaTarea frm = new frmNuevaTarea();
            if (frm.ShowDialog().Equals(DialogResult.OK))
            {
                TaskService programador = new TaskService();
                Trigger evento = Trigger.CreateTrigger(TaskTriggerType.Daily);
                evento.StartBoundary = frm.dtpFechaInicio.Value.AddMinutes(1);
                evento.EndBoundary = frm.dtpFechaFin.Value;
                ExecAction accion = new ExecAction();
                accion.Path = frm.txtPrograma.Text;
                Task tarea = programador.AddTask
                    (@"\DSOFT\" + frm.txtNombre.Text, evento, accion);
                if (tarea != null)
                {
                    string estado = tarea.State.ToString();
                    ListViewItem fila = lvwTarea.Items.Add(tarea.Name);
                    fila.SubItems.Add(tarea.Folder.Name);
                    fila.SubItems.Add(estado);
                    seleccionarTareas(fila, tarea, estado);
                }
            }
        }

        private void eliminarTarea(object sender, EventArgs e)
        {
            if (lvwTarea.SelectedItems != null && lvwTarea.SelectedItems.Count > 0)
            {              
                ListViewItem fila =lvwTarea.SelectedItems[0];
                string nombreCarpeta = fila.SubItems[1].Text;
                TaskService programador = new TaskService();
                TaskFolder carpeta = programador.GetFolder(nombreCarpeta);
                if (carpeta != null)
                {
                    string nombreTarea = fila.SubItems[0].Text;
                    Task tarea = programador.GetTask
                        (String.Format(@"\{0}\{1}", nombreCarpeta, nombreTarea));
                    if (tarea != null)
                    {
                        if (tarea.State.Equals(TaskState.Running)) tarea.Stop();
                        try
                        {
                            carpeta.DeleteTask(nombreTarea, true);
                            fila.Remove();
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message, "No se pudo eliminar la tarea");
                        }
                    }
                }
            }
        }
    }
}

Nota: Para el ejemplo, se ha creado en el Task Scheduler de Windows una carpeta llamada "DSOFT"

Agregar otro formulario al proyecto y ponerle como nombre "frmNuevaTarea" y diseñarlo similar a como se ve en la siguiente figura:


Nota: En el diseño hay 2 TextBoxs llamados txtNombre y txtPrograma, además 2 DateTimePicker llamados: dtpFechaInicio y dtpFechaFin, finalmente 3 botones: "btnAbrirPrograma", "btnAceptar" y "btnCancelar". El botón "btnAceptar" tiene configurado la propiedad DialogResult en OK y el botón "btnCancelar" tiene configurado la propiedad DialogResult en Cancel.

Escribir el siguiente código en el formulario "frmNuevaTarea":

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ProgramacionTareas
{
    public partial class frmNuevaTarea : Form
    {
        public frmNuevaTarea()
        {
            InitializeComponent();
        }

        private void mostrarDialogoAbrirPrograma(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Title = "Selecciona el Programa a Abrir";
            ofd.Filter = "Archivos de programas|*.exe";
            if (ofd.ShowDialog().Equals(DialogResult.OK))
            {
                txtPrograma.Text = ofd.FileName;
            }
        }
    }
}

Ejecutar y Probar la Aplicación Windows Forms

Antes de ejecutar la aplicación, para poder comprobar el listado de tareas, la creación de una nueva tarea y la eliminación de una tarea existente hay que abrir el Task Scheduler, para esto pulsar Ctrl + R y escribir el siguiente comando: taskschd.msc

Se mostrará la consola del Task Scheduler similar al mostrado en la siguiente figura:


Nota: Crear una carpeta personalizada para guardar nuestras tareas programadas llamada "DSOFT" y crear un par de tareas básicas dentro de esta carpeta.

Grabar la aplicación y pulsar F5 para ejecutarla, inmediatamente se listaran las tareas programadas similar a la siguiente figura:


En la ventana las tareas de la carpeta personalizada creada "DSOFT" se mostrarán con fondo verde y color amarillo y las tareas que están ejecutándose se mostrarán con fondo rojo y color blanco.

Dar clic derecho sobre la lista (ListView) y aparecerá un menú contextual con 2 opciones, seleccionar la primera opción: "Nueva Tarea" y aparecerá el siguiente cuadro de diálogo:


Llenar los datos de la nueva tarea: nombre, fecha de inicio, fecha de fin y seleccionar el programa a ejecutar, clic al botón "Aceptar" y la tarea se agregará al final de la lista, similar a la siguiente figura:


Comprobar que la tarea aparece en la consola del Task Scheduler de Windows (clic derecho y refrescar), además se ha programado para que después de un minuto del "Aceptar" se ejecute.

Clic derecho a la tarea creada recientemente y seleccionar la opción: "Eliminar Tarea", e inmediatamente se eliminará la tarea, también comprobarlo en la consola del Task Scheduler de Windows (clic derecho y refrescar).

Comentario

En este post hemos aprendido como crear nuestro propio Administrador de Tareas Programadas usando la clase TaskService de la librería manejada: Microsoft.Win32.TaskScheduler.dll.

Esto es de mucha utilidad cuando a veces nos restringen el acceso a las Herramientas de Windows y necesitamos crear una Nueva Tarea para ejecutar una aplicación, sobre todo para programas en Batch.

Descarga del Código
DemoDia_ProgramacionTareas

3 comentarios:

  1. Profesor Dueñas, un demo muy oportuno en mi caso, Estuvimos hace unos días viendo el desarrollo de una aplicación de consola que en un determinado momento del día invoca un servicio realizando una acción en particular, con el demo y su asesoría se cierra el requerimiento bajo un 100% de calidad.

    Saludos.

    ResponderBorrar
  2. Hola Juan Carlos. Esta aplicación la iniciamos ayer en el Taller de los Domingos que estuvo muy interesante, de la cual también publicaré otros Demos esta semana.

    También esta pendiente tu requerimiento de las Fechas (DateSpan) que lo compartiré como Demo para todos.

    Saludos

    ResponderBorrar
    Respuestas
    1. Excelente y gracias por su ayuda quedo en deuda con usted. Haré un esfuerzo y estar con usted y los muchachos este Domingo.

      Un fuerte abrazo.

      Borrar