Reputation: 133
I am writing a script to check mail and I want it to check the unread mail every 20 or 30 minutes how can I schedule this task to run every 30 minutes using powershell.
Upvotes: 3
Views: 12271
Reputation: 71
I mixed powershell and schtasks.exe functionality to get exactly what I wanted. @KUTlime's answer is better if you also had a "DateTime Max" so it would run infinitely.
I added if already created skip, although the create will just fail if it's already created anyway.
$taskName = "StartAllZPPNecessaryServices"
$taskPath = "\" # Root folder of Task Scheduler
$taskDescription = "Run StartAll.ps1 every 20 minutes"
$taskExists = Get-ScheduledTask | Where-Object { $_.TaskName -eq $taskName -and $_.TaskPath -eq $taskPath }
if ($taskExists)
{
Write-Output "The task '$taskName' already exists."
} else {
$command = 'schtasks.exe /Create /TN "$taskName" /TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\ServiceInfo\StartAll.ps1" /SC MINUTE /MO 20 /RU "SYSTEM" /RL HIGHEST /F'
Invoke-Expression $command
Write-Output "The task '$taskName' has been created successfully."
}
There are also options to write out the XML and run the import commands.
Upvotes: 0
Reputation: 8117
You didn't specified a version of PowerShell or the operation system under which you want to check for your emails.
The Task Scheduler in Windows has so many problems that I don't know where to begin.
Unfortunately, you can schedule a task which re-occurs every 20-30 min easily. You have to schedule a daily task at 00:00, 00:30, 01:00 etc. in cycle, so you would end up with 48 or 72 scheduled tasks in your scheduler. 🤔
If we are talking about Windows on notebooks, laptops even desktop PCs with UPS backup, you can't rely on the task scheduler. The tasks are not executed according the schedule because battery management interfere.
Another problem is that every 20-30 min a window of PowerShell will popup on your screen for a brief moment. You can suppress this by register the task as system service => under system service account. Other approach is to run PowerShell in CMD and hand over the script which must be executed. This is not an option if you don't have an admin rights.
Another, very tricky problem is that use of one of the must include switch (technically, you don't have to use this switch but the task gets executed faster) for scheduled PowerShell tasks: the -NonInteractive
switch will actively stop you from using some of the interactive cmdlets like Pause
, Read-Host
or Get-Credential
in your script which you want to execute. You have to design your scheduled task according the instruction which you want to execute in PowerShell session.
Not ideal option is the schedule the trigger as -Once
and setup this trigger with repetition:
$frequencyOfCheckInMin = 20
$howManyYearYouWantToCheckForEmails = 5
$params = @{
Once = $true
At = (Get-Date)
RepetitionInterval = (New-TimeSpan -Minutes $frequencyOfCheckInMin)
RepetitionDuration = (New-TimeSpan -Days ($howManyYearYouWantToCheckForEmails * 365 * $frequencyOfCheckInMin))
}
$trigger = New-ScheduledTaskTrigger @params
A better approach would be to register one task with PowerShell script that gets executed in 30 min for the task registration time manually. Your PowerShell script would contain a logic for an email check and update of the scheduled task trigger to a new, 30 min later from the time of the execution of the scheduled task trigger. Code follows.
# A definition of a general task which takes a script as argument and execute task
$pathToScript = 'D:\Fortis Backup\Test.ps1'
$ScheduledTaskActionParams = @{
Execute = "PowerShell.exe"
Argument = "-NoLogo -NoProfile -NonInteractive -File `"$pathToScript`""
}
$registerTaskParameters = @{
Principal = New-ScheduledTaskPrincipal -UserId "$ENV:USERDOMAIN\$ENV:USERNAME"
Trigger = New-ScheduledTaskTrigger -Once -At ((Get-Date).AddMinutes(30))
TaskName = 'Check email'
Action = New-ScheduledTaskAction @ScheduledTaskActionParams
}
Register-ScheduledTask @registerTaskParameters -Force
Get-EmailStatus
$newTrigger = New-ScheduledTaskTrigger -Once -At ((Get-Date).AddMinutes(30))
Set-ScheduledTask -TaskName 'Check email' -Trigger $newTrigger
For details about the trigger, have a look over here.
It is a super simple.
To tackle problems with non-interactive cmdlets, I've designed these functions which I'm using in my private Swiss Army Knife Module for various PowerShell task.
function Confirm-PowerShellScriptForNonInteractiveMode
{
[CmdletBinding(PositionalBinding)]
Param (
# A path to PS1 file to test
[Parameter(
Mandatory,
ValueFromPipelineByPropertyName,
ValueFromPipeline,
Position = 0)]
[ValidateNotNullOrEmpty()]
[ValidateScript( { Test-Path $_ })]
[ValidateScript( { $_ -like '*.ps1' })]
[System.IO.FileInfo]
$Path
)
Begin
{
Write-Information 'Starting to validate script(s)...'
}
Process
{
$nonInteractiveCmdlets = @('Pause', 'Read-Host', 'Get-Credential')
$isValid = [System.Boolean]$true
$content = Get-Content -Path $Path
foreach ($cmdlet in $nonInteractiveCmdlets)
{
Write-Verbose "Script status: $isValid, testing $cmdlet"
$isValid = $isValid -AND !($content -match "$cmdlet")
}
return $isValid
}
End
{
Write-Information 'All scripts has been validated.'
}
}
function Register-PowerShellScheduledTask
{
[CmdletBinding(PositionalBinding)]
Param (
# A path to PS1 file to register
[Parameter(
Mandatory,
ValueFromPipelineByPropertyName,
ValueFromPipeline,
Position = 0)]
[ValidateNotNullOrEmpty()]
[ValidateScript( { Test-Path $_ })]
[ValidateScript( { $_ -like '*.ps1' })]
[ValidateScript( { Confirm-PowerShellScriptForNonInteractiveMode $_ })]
[System.IO.FileInfo]
$Path,
[Parameter(
ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 1)]
[ValidateNotNullOrEmpty()]
[Microsoft.Management.Infrastructure.CimInstance]
$TaskTrigger = (New-ScheduledTaskTrigger -AtLogOn)
)
Begin
{
Write-Information 'Starting to register task(s)...'
}
Process
{
$ScheduledTaskActionParams = @{
Execute = "PowerShell.exe"
Argument = "-NoLogo -NoProfile -NonInteractive -File `"$Path`""
}
$registerTaskParameters = @{
Principal = New-ScheduledTaskPrincipal -UserId "$env:USERDOMAIN\$env:USERNAME"
Trigger = $TaskTrigger
TaskName = "Run $(Split-Path -Path $Path -Leaf) by PowerShell"
Action = New-ScheduledTaskAction @ScheduledTaskActionParams
}
Register-ScheduledTask @registerTaskParameters -Force
Get-ScheduledTask | Write-Verbose
}
End
{
Write-Information 'Registered task:'
Get-ScheduledTask -TaskName 'Run * by PowerShell' | Write-Information
}
}
$trigger = New-ScheduledTaskTrigger -At ((Get-Date).AddSeconds(10))
Register-CustomScheduledTask -Path "C:\temp\test.ps1" -Trigger $trigger
Upvotes: 3
Reputation: 1415
Here's a sample Powershell script which creates a scheduled task which can run with admin privileges
passing argument
-RunLevel Highest
makes it run as administrator, you may need to provide valid username/password which has admin right on the machine
$frequencyInMin = 20
$taskAction = New-ScheduledTaskAction -Execute 'Powershell.exe' `
-Argument '-NoProfile -WindowStyle Hidden -command "& {get-eventlog -logname Application -After ((get-date).AddDays(-1)) | Export-Csv -Path c:\temp\logs.csv -Force -NoTypeInformation}"'
$trigger = New-ScheduledTaskTrigger `
-Once `
-At (Get-Date) `
-RepetitionInterval (New-TimeSpan -Minutes $frequencyInMin) `
-RepetitionDuration (New-TimeSpan -Days (365 * $frequencyInMin))
Register-ScheduledTask -Action $taskAction -Trigger $trigger -TaskName "MyTasks\AppLog" -Description "Daily App Logs" -RunLevel Highest
Upvotes: 0