Búsqueda de sitios web

Trabajos de recordatorio de PowerShell


En el pasado escribí en un blog sobre mi sistema de cosquillas que se ejecuta cuando inicio PowerShell. Pero a menudo tengo necesidades de recordatorios o cosquillas a corto plazo. Por ejemplo, como trabajo en casa, es posible que deba acordarme de cambiar la ropa o de que tengo una llamada telefónica a las 2:00 p.m. Claro, podría configurar alertas de calendario en un cliente de correo electrónico, pero prefiero tener algo tan rápido y fácil como un comando de PowerShell. Entonces escribí este script, New-Reminderjob.ps1.

#requires -version 3.0

<#
.Synopsis
Create a reminder background job.
.Description
This command uses the MSG.EXE command line tool to send a reminder message to currently logged on user. You can specify how many minutes to wait before displaying the message or you can set the alert to run at a specific date and time.

This command creates a background job in the current PowerShell session. If you close the session, the job will also be removed. This command is intended to set ad-hoc reminders for the current user. The message will automatically dismiss after 1 minute unless you use -Wait.

Even though Start-Job doesn't support -WhatIf, this command does. This script will also add some custom properties to the job object so that you can track that status of your reminders. See the examples.

NOTE: Be aware that each running reminder will start a new PowerShell process.
.Parameter Message
The text to display in the popup.
.Parameter Time
The date and time to display the popup. If you enter just a time, it will default to the current day. See examples. 
This parameter has aliases of date and dt. 
.Parameter Minutes
The number of minutes to wait before displaying the popup message.
.Parameter Wait
Force the user to acknowledge the popup message.
.Example
PS C:\> c:\scripts\new-reminderjob.ps1 "Switch over laundry" -minutes 40 -wait

This command creates a new job that will display a message in 40 minutes and wait for the user to acknowledge.
.Example
PS C:\> c:\scripts\new-reminderjob.ps1 "Go home" -time "5:00PM" -passthru

Id   Name         PSJobTypeName   State      HasMoreData     Location     Command         
--   ----         -------------   -----      -----------     --------     -------         
49   Reminder7    BackgroundJob   Running    True            localhost    ...      

Create a reminder to be displayed at 5:00PM today. The job object is written to the pipeline because of -Passthru
.Example
PS C:\> get-job remind* | Sort Time | Select ID,Name,State,Message,Time,Wait | format-table -auto

Id Name      State   Message             Time                 Wait
-- ----      -----   -------             ----                 ----
67 Reminder1 Running switch over laundry 5/27/2014 2:34:33 PM True
69 Reminder2 Running Budget meeting      5/27/2014 3:00:00 PM False
71 Reminder3 Running reboot WSUS         5/27/2014 3:21:33 PM False

In this example, PowerShell is getting all reminder jobs sorted by the time they will "kick off" and displays the necessary properties.
.Notes
Last Updated: 5/27/2014
Version     : 0.9
Author      : Jeff Hicks (@JeffHicks)
              https://jdhitsolutions.com/blog

Learn more:
 PowerShell in Depth: An Administrator's Guide (http://www.manning.com/jones2/)
 PowerShell Deep Dives (http://manning.com/hicks/)
 Learn PowerShell 3 in a Month of Lunches (http://manning.com/jones3/)
 Learn PowerShell Toolmaking in a Month of Lunches (http://manning.com/jones4/)
   
  ****************************************************************
  * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED *
  * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK.  IF   *
  * YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, *
  * DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING.             *
  ****************************************************************

.Link
https://jdhitsolutions.com/blog/2014/05/powershell-reminder-jobs
.Link
msg.exe
Start-Sleep
Start-Job
.Inputs
None
.Outputs
custom System.Management.Automation.PSRemotingJob
#>

[cmdletbinding(DefaultParameterSetName="Minutes",SupportsShouldProcess)]
Param(
[Parameter(Position=0,Mandatory,HelpMessage="Enter the alert message text")]
[string]$Message,
[Parameter(ParameterSetName="Time")]
[ValidateNotNullorEmpty()]
[Alias("date","dt")]
[datetime]$Time,
[Parameter(ParameterSetName="Minutes")]
[ValidateNotNullorEmpty()]
[int]$Minutes=1,
[switch]$Wait,
[switch]$Passthru
)

Begin {
    Write-Verbose -Message "Starting $($MyInvocation.Mycommand)"  
    Write-Verbose -Message "Using parameter set $($PSCmdlet.ParameterSetName)"
    Switch ($PSCmdlet.ParameterSetName) {
    "Time" { [int]$sleep = ($Time - (Get-Date)).TotalSeconds  }
    "Minutes" { [int]$sleep = $minutes*60}
    }

    #get last job ID
    $lastjob = Get-Job -Name "Reminder*" | sort ID | select -last 1
    
    if ($lastjob) {
        #define a regular expression
        [regex]$rx ="\d+$"
        [string]$counter = ([int]$rx.Match($lastJob.name).Value +1)
    }
    else {
        [string]$counter = 1
    }
} #begin

Process {
    Write-Verbose -message "Sleeping for $sleep seconds"
    $sb = {
    Param($sleep,$cmd)
    Start-Sleep -seconds $sleep ; Invoke-Expression $cmd
    }
    
    [string]$cmd = "msg.exe $env:username"
    if ($Wait) {
        Write-Verbose "Reminder will wait for user"
        $cmd+=" /W"
    }

    $cmd+=" $message"
    
    $jobName = "Reminder$Counter"
    Write-Verbose -Message "Creating job $jobname"

    #WhatIf
    $whatif = "'{0}' in {1} seconds" -f $message,$sleep
    if ($PSCmdlet.ShouldProcess( $whatif )) {
     $job = Start-Job -ScriptBlock $sb -ArgumentList $sleep,$cmd -Name $jobName 
     #add some custom properties to the job object
     $job | Add-Member -MemberType NoteProperty -Name Message -Value $message
     $job | Add-Member -MemberType NoteProperty -Name Time -Value (Get-Date).AddSeconds($sleep)
     $job | Add-Member -MemberType NoteProperty -Name Wait -Value $Wait
     if ($passthru) {
      #if -Passthru write the job object to the pipeline
      $job
     }
    }
} #process

End {
    Write-Verbose -Message "Do not close this PowerShell session or you will lose the reminder job"
    Write-Verbose -Message "Ending $($MyInvocation.Mycommand)"
} #end

En resumen, el script crea un trabajo en segundo plano que utilizará la herramienta de línea de comandos MSG.EXE para mostrarme un mensaje. La acción del trabajo duerme la cantidad de segundos especificada y luego ejecuta mi comando MSG.EXE. Podría haber usado varias formas de mostrar el mensaje, pero MSG.EXE está integrado y no vi ninguna razón para reinventar la rueda.

El script, que puede convertir en una función si lo desea, requiere el texto del recordatorio y luego cuándo "entregar" el recordatorio. Puede especificar una cantidad de minutos, el valor predeterminado es 1, o una fecha y/u hora. Si especifica una hora como “9:00 a. m.”, el script asumirá que se refiere a las 9 a. m. de hoy. El script convierte su hora de inicio en una cantidad de segundos que tiene que esperar y lo integra en el bloque de script del trabajo.

PS C:\scripts> .\New-ReminderJob.ps1 "Budget meeting" -date "5/27/2014 3:00PM" -wait

Cuando llega el momento, aparece un mensaje emergente como este.

Como es posible que tenga varios recordatorios diarios, quería una manera fácil de identificarlos. Una cosa que hice con mi script fue darle a todos mis trabajos de recordatorio un nombre personalizado que comience con "Recordatorio". Utilizo una expresión regular para encontrar el número del trabajo de recordatorio más reciente y lo incremento en uno. El otro paso útil es que agregué algunas propiedades personalizadas al objeto de trabajo. Estas propiedades incorporan valores del script en el objeto del trabajo. Ahora puedo hacer comandos interesantes como este:

Las propiedades personalizadas no tienen ningún efecto sobre ningún otro objeto de trabajo. Si uso mucho estas propiedades, podría crear algunas funciones adicionales para ahorrar algo de escritura.

Este sistema está diseñado para recordatorios diarios ad hoc para mí, razón por la cual no utilicé trabajos programados. No quería tener que lidiar con la limpieza de un montón de trabajos únicos. Estos trabajos de recordatorio solo duran mientras mi sesión de PowerShell esté abierta. Pero tenga en cuenta que cada recordatorio en ejecución iniciará un nuevo proceso de PowerShell, por lo que no recomendaría configurar esto con docenas de recordatorios. En realidad, si necesita tantos recordatorios, ¡necesita conseguir un nuevo trabajo o un asistente!

Espero que lo pruebes y me cuentes qué piensas o dónde crees que se puede mejorar. ¡Disfrutar!

Artículos relacionados