I'm trying to write a PowerShell script that will activate another script on a daily basis. What I have is:
$Sta = New-ScheduledTaskAction -Execute "powershell.exe" -argument "C:\Users\UserName\Desktop\Script.ps1"
$Stt = New-ScheduledTaskTrigger -Daily -At 3am
Register-ScheduledTask Task1 -Action $Sta -Trigger $Stt
It's not working because it can't find the file. PowerShell's default directory is the user's root directory, so I don't know if that's it, even though I've tried using the full path to the file? Or is it due to where the scheduled task is running from? Location says \ and I cannot seem to change that, even in the task scheduler app. I've been Googling for days and I can't figure it out. Anyone have any idea? I'm working on Windows 10 Pro.
Soufflegirl13,
Updated & Tested:
$TaskSet = New-ScheduledTaskSettingsSet -Compatibility Win8
$TaskSet.DisallowStartIfOnBatteries = $True
$TaskSet.StopIfGoingOnBatteries = $True
$TaskSet.IdleSettings.StopOnIdleEnd = $false
#Adjust the following two lines to meet your requirements
$TaskDesc = "Retrieve the status of HyperV"
$TaskName = "Task1 - or whatever you want here"
$Stt = New-ScheduledTaskTrigger -Daily -At 3am
#Adjust the -file parameter to point to your script
$TAArgs = #{Execute = '"' + "c:\windows\system32\windowspowershell" +
"\v1.0\powershell.exe" + '"' ;
Argument = "-file `"G:\BEKDocs\Scripts\Misc\Get-HyperVStatus-V-3.ps1`"" }
$TaskAction = New-ScheduledTaskAction #TAArgs
$RSTArgs = #{Action = $TaskAction
TaskName = "$TaskName"
Trigger = $Stt
User = "$env:USERDOMAIN\$env:username"
RunLevel = "Highest"
Description = "$TaskDesc"
Settings = $TaskSet}
Register-ScheduledTask #RSTargs
I've found that forcing the quote marks around the powershell filespec solved some problems. You might want to try it around the script name if the previous doesn't work.
Of course adjust any settings as you see fit to meet your requirements. Also I've not used this basic code to set a trigger before but I adjusted it to do so according to the documentation for Register-ScheduledTask so it should work.
Update Notes:
I checked the documentation for the New-ScheduledTaskSettingsSet cmdlet and it doesn't include Win10 as a valid value for Compatibility, go figure, so I backed it off to Win8. You can also just not use the Compatibility argument and accept whatever it defaults to.
The code is now fully tested, sorry I forgot to tell you to replace the $TaskName variable with a value or to add the variable, as is now shown in the adjusted code.
HTH
Related
I have two triggers in a task. The first one runs at a specific time. The second one starts at logon and runs every 10 minutes. I have many similar tasks like this situation. I want to use powershell to change the property from 10 minutes to 5 minutes and run indefinitely after logon. How do I specify the SECOND trigger?
$Task = Get-ScheduledTask -TaskName "Task"
$Task.Triggers.LogonTriggers.Repetition.Duration = ""
$Task.Triggers.Repetition.Interval = "PT10M"
You can modify the $Task object and pass it into the Set-ScheduledTask which will apply the changes you've made. The first trigger that runs at a specific time will have it's StartBoundary property set, the second trigger which starts at Logon won't have this property set so we'll use the value of that to make sure we change the correct trigger.
$Task = Get-ScheduledTask -TaskName "Task"
$RepeatingTrigger = $Task.Triggers | Where-Object { $_.StartBoundary -eq $null }
$RepeatingTrigger.Repetition.Interval = "PT5M"
Set-ScheduledTask -InputObject $Task
So I have some powershell I'm trying to use to setup a Scheduled Task during an ADO deployment. In order to get the task set to "Run whether user is logged on or not" I am required to create it using a User and Password according to these:
Set a Scheduled Task to run when user isn't logged in
Schedule task creation with option ""Run whether user is logged in or not"" using powershell
https://learn.microsoft.com/en-us/powershell/module/scheduledtasks/new-scheduledtaskprincipal?view=win10-ps
And several others.
So with the security rules of the company all passwords from ADO have to be in secret variables. These do not decrypt when called basically from within the scripts, you'll get null values. According to these, you have to pass them in as Environment Variables and/or Parameters to the script:
https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=classic%2Cbatch
https://github.com/Microsoft/azure-pipelines-tasks/issues/8345
VSTS: Pass build/release variables into Powershell script task
https://github.com/microsoft/azure-pipelines-agent/issues/145
https://adamtheautomator.com/azure-devops-variables-complete-guide/
Many of these also only show the yaml side, but I'm using classic so this is of no use and I suspect irrelevant based on the next link which then contradicts them saying you can only use parameters on file base scripts and not inline:
https://github.com/MicrosoftDocs/vsts-docs/issues/1083
I have setup an Environment Variable per the MS link on variable usage as part of the ADO step where by i have a name and a value defined as $(mySecret).
I have tried accessing this through various means described in the links above:
$MYSECRET
$env:MYSECRET
$($MYSECRET)
$($env:MYSECRET)
$(MYSECRET)
$(env:MYSECRET)
(All of the following with both Param and param)
param([string]$mySecret)
param($mySecret)
param($MYSECRET)
param($env:mySecret)
param($env:MYSECRET)
All of these return a "Param is not a recognized function" which according to these, is usually due to param not being the first word in the script, which is not the case for me, I have already checked, double checked, pulled out the text to notepad, notepad++ (both just in case) and compared, and verified it is really the very first word in the script:
PowerShell 2.0 and "The term 'Param' is not recognized as the name of a cmdlet, function, script file, or operable program"
PowerShell parameters - "The term 'param' is not recognized as the name of a cmdlet"
powershell unable to recognize parameter
I've even tried to copy and paste some of the Param solutions suggested above, even from the ADO git, and they all fail for this. I believe because of the git issue 1083 linked above.
None of the suggestions or answers from any of the links I've posted have worked.
One of the other links I came across had a suggestion to create up to three other deployment steps for creating variables, pulling them from the ADO environment, executing direct decryption and assignment. Completely over the top for what I believe should be required here. Another suggestion was to create an extra step to create a temp function to pull the secret and parse it with substring with a couple of different start and end values and to piece those back together as apparently the substring function could see beyond the encryption. Even if that did work, that is ridiculous. As such I haven't tried these last 2 suggestions. If that's really the case I would like someone to point me to the git docs stating as such or there needs to be a bug written up on it.
I'm simply at a loss. I just need to access a secret variable in an inline powershell script for a single task during and ADO deployment, does anyone know how to achieve this. Note the task creation code below does work when I use plain text inputs for the user and password, but that's against policy so not an option.
Here is my script:
param($taskPass)
$taskName = $env:ScheduledTaskName
$taskExists = Get-ScheduledTask | Where-Object {$_.TaskName -like $taskName }
if(!$taskExists) {
$Trigger = New-ScheduledTaskTrigger -Daily -At 3am
$Actions = (New-ScheduledTaskAction -Execute "powershell curl -Method POST -Uri $env:VarURL"),
(New-ScheduledTaskAction -Execute "powershell Invoke-Sqlcmd -ServerInstance $env:Server -Database 'MyDB' -Query 'EXEC NightlyProc'")
#The following was suggested from here http://duffney.io/Create-ScheduledTasks-SecurePassword
$SecurePassword = "$taskPass"
Write-Host "Pass: $SecurePassword"
$Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $env:ScheduledTaskUser, $SecurePassword
$Password = $Credentials.GetNetworkCredential().Password
$Task = New-ScheduledTask -Action $Actions -Trigger $Trigger
$Task | Register-ScheduledTask -TaskName $taskName -User $env:ScheduledTaskUser -Password $Password
}
Ok so I finally worked this out. I used the YAML viewer to get a comparison of what the classic interface was creating vs what the MS link said it should be. This involved setting the Environment Variable to the value in the $(mySecret) format (no $env: here just the variable name). Then in the script using the $env:MYSECRET formatting. But also without all of the credential/password manipulation from the duffney.io site. Just setting the -Password parameter for the new Task directly to the $env:MYSECRET variable. No need for params. Task created as 'Run even when user not logged on' just as expected. Final code:
$taskName = $env:ScheduledTaskName
$taskExists = Get-ScheduledTask | Where-Object {$_.TaskName -like $taskName }
if(!$taskExists) {
$Trigger = New-ScheduledTaskTrigger -Daily -At 3am
$Actions = (New-ScheduledTaskAction -Execute "powershell curl -Method POST -Uri $env:URL"),
(New-ScheduledTaskAction -Execute "powershell Invoke-Sqlcmd -ServerInstance $env:Server -Database 'MyDB' -Query 'EXEC NightlyCache'")
$Task = New-ScheduledTask -Action $Actions -Trigger $Trigger
$Task | Register-ScheduledTask -TaskName $taskName -User $env:ScheduledTaskUser -Password $env:TASKPASS
}
Making sure to set an Environment Variable to the following values:
NOTE: CAPS on the name are not necessary here, seems to just be a standard. I've successfully deployed with both the CAPS version and 'TaskPass'. I say this because several of the links I posted above make it seem like they are.
Name: TASKPASS
Value $(ScheduledTaskPass)
Also of note that MS does it's best to hide this value from you. Even if you set it to a local script variable and try to output the value, as I was trying to do for confirmation purposes, you'll still only get asterisks. But it's really there, I/they promise.
In classic type,
In order to access secret variable in inline powershell script,
step1:Define a variable and set it secret variable(using lock icon)( for ex Name: PASSWORD value: ********)
step2: Add/set an Environment variable(below inline script available as an option) to remap your secret variable[since you can't access secret variables directly in scripts(ref: MSdocs)] like for ex Name: PASSWORD value: $(PASSWORD)
step3: While using this variable in script access like $env: PASSWORD
I am trying to achieve the following settings (select "If the task is already running, then the following rule applies") through PowerShell script but unable to get appropriate settings to configure that.
I am using the following code to configure that
$Trigger = New-ScheduledTaskTrigger -At 07:00am -Daily
$Settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Hour 1) -Compatibility Win7 -StartWhenAvailable -Priority 7
$User = "SYSTEM"
$Action = New-ScheduledTaskAction -Execute "some script" -Argument "some argument" -WorkingDirectory "working dir"
Register-ScheduledTask -TaskName "Test Task" -Trigger $Trigger -User $User -Action $Action -Settings $Settings -RunLevel Highest –Force
To do the advanced configuration for the triggers
$Task = Get-ScheduledTask -TaskName "Example Task"
$Task.Triggers[0].ExecutionTimeLimit = "PT10M"
$Task | Set-ScheduledTask -User $User
The setting is configured via New-ScheduledTaskSettingsSet and the parameter you're looking for is -MultipleInstances:
-MultipleInstances
Specifies the policy that defines how Task Scheduler handles multiple instances of the task. The acceptable values for this parameter are:
IgnoreNew. The new task instance is ignored. Parallel. The new task instance starts immediately. Queue. The new task instance starts as soon as the current instance completes.
Type: MultipleInstancesEnum
Accepted values: Parallel, Queue, IgnoreNew
Position: Named
Default value: None
However, the documentation lists only 3 values, and the respective enum (at least at the time of this writing also only has the listed 3 values:
Parallel → Run a new instance in parallel
Queue → Queue a new instance
IgnoreNew → Do not start a new instance
If you create a task manually via the GUI and select the setting "Stop the existing instance" the value .Settings.MultipleInstances is empty, but if you create a Settings object via New-ScheduledTaskSettingsSet omitting the parameter -MultipleInstances it defaults to IgnoreNew. Attempts to change that to an empty value result in validation errors.
This is obviously a bug (missing value in the referenced enum).
The enum now contains 'StopExisting'.
This is my solution in C#.
static void RegisterMyTask(string taskPath, string remoteServer)
{
try
{
using TaskService ts = new(remoteServer);
TaskDefinition taskDef = ts.NewTask();
taskDef.Settings.MultipleInstances = TaskInstancesPolicy.StopExisting;
...
However PowerShell probably has the new enum as well. As I would guess:
-MultipleInstances StopExisting
I had a task scheduled on multiple remote servers.
On day 1 it started running.
Day 2 it failed to start a new instance, but didn't kill the existing instance
Day 3 it failed to start a new instance, but didn't kill the existing instance. Then 30 seconds later, the existing instance was killed by the day 1 timeout setting, but the new instance had already failed for the day.
This fixed my problem.
I'm trying to create a Scheduled Task with the following Trigger:
- Startup
- Run every 5 minutes
- Run indefinitely
In the GUI I can do this easily by selecting:
- Begin the task: at startup
And in the Advanced tab:
- Repeat task every: 5 minutes
- For a duration of: indefinitely
But I'm having trouble doing it with Powershell.
My troubled code:
$repeat = (New-TimeSpan -Minutes 5)
$duration = ([timeSpan]::maxvalue)
$trigger = New-ScheduledTaskTrigger -AtStartup -RepetitionInterval $repeat -RepetitionDuration $duration
It won't take the RepetitionInterval and RepetitionDuration parameters. But I need that functionality.
How could I accomplish my goal?
To set the task literally with a "Startup" trigger and a repetition, it seems you have to reach in to COM (or use the TaskScheduler UI, obviously..).
# Create the task as normal
$action = New-ScheduledTaskAction -Execute "myApp.exe"
Register-ScheduledTask -Action $action -TaskName "My Task" -Description "Data import Task" -User $username -Password $password
# Now add a special trigger to it with COM API.
# Get the service and task
$ts = New-Object -ComObject Schedule.Service
$ts.Connect()
$task = $ts.GetFolder("\").GetTask("My Task").Definition
# Create the trigger
$TRIGGER_TYPE_STARTUP=8
$startTrigger=$task.Triggers.Create($TRIGGER_TYPE_STARTUP)
$startTrigger.Enabled=$true
$startTrigger.Repetition.Interval="PT10M" # ten minutes
$startTrigger.Repetition.StopAtDurationEnd=$false # on to infinity
$startTrigger.Id="StartupTrigger"
# Re-save the task in place.
$TASK_CREATE_OR_UPDATE=6
$TASK_LOGIN_PASSWORD=1
$ts.GetFolder("\").RegisterTaskDefinition("My Task", $task, $TASK_CREATE_OR_UPDATE, $username, $password, $TASK_LOGIN_PASSWORD)
New-ScheduledTaskTrigger uses parameter sets. When you specify that you want the scheduled task to start up "at logon" you are restricting yourself to the following parameter set:
Parameter Set: AtStartup
New-ScheduledTaskTrigger [-AtStartup] [-RandomDelay <TimeSpan> ] [ <CommonParameters>]
What may be more beneficial is if you use your "at startup" scheduled task to register a new scheduled task to run every five minutes using the "once" parameter set:
Parameter Set: Once
New-ScheduledTaskTrigger [-Once] -At <DateTime> [-RandomDelay <TimeSpan> ] [-RepetitionDuration <TimeSpan> ] [-RepetitionInterval <TimeSpan> ] [ <CommonParameters>]
Your Scheduled Task Trigger should successfully be assigned once you are using the correct parameter set.
See my answer here: https://stackoverflow.com/a/61646465/2943191
It is actually relatively simple, once a working example is written, of course.
Instead of -AtLogOn use -AtStartup.
For what it’s worth, I too ran into this issue as I was particularly perturbed that this functionality was pulled from PowerShell for -AtStartup. However, upon further review, the same functionality can be performed by just be using -Once and configuring it to repeat. In the OP’s case of having this run every five minutes, it probably won’t make a difference if this is run at startup or five minutes thereafter.
I have confirmed this with -Once and then configuring it to repeat. It will also perform the repeats when the system is restarted. This is somewhat different from #BryceMcDonald’s answer in that you don’t need to create two triggers—just create the -Once one and you’ll be good to go.
I'm currently automating the creation of scheduled tasks via Powershell, and I'm using the New-ScheduledTaskAction, New-ScheduledTaskTrigger, and Register-ScheduledTask commands. Now, I have a few jobs that need to run under the following conditions :
Run once every Friday
Run once on the 1st of every month
Run once on the 10th day of every month
While the technet documentation for the New-ScheduledTaskTrigger command specifies a Daily and Weekly time span parameter, I do not see one for Monthly, which is critical for defining the run times above.
In the few years I've been using Powershell, I can't think of an instance where I could do something via the standard UI interface, that I couldn't accomplish using one of the available commands.
Is this just flat out not available here, or am I missing something?
UPDATE #1
I just stumbled upon this SuperUser question, which does look promising, but references PSV3 instead of PSV4 - going to give it a shot and report back.
As I said in the original post, the SuperUser question above looked promising, but ultimately did not work with PSV4, and the example given in the post was basically a copy\paste job with almost no context.
I realized I could leverage Schtasks.exe from my Powershell script to handle the monthly aggregations, and it's fairly easy to set up, albeit somewhat tedious :
# set the trigger depending on time, span, and day
$runSpan = $task.SpanToRun;
if ($runSpan.Equals("Daily"))
{
$trigger = New-ScheduledTaskTrigger -Daily -At $task.TimeToRun
Register-ScheduledTask -Action $action -Trigger $trigger -TaskName $task.TaskName -User $Username -Password $Password -Description $task.Description
}
if ($runSpan.Equals("Weekly"))
{
$trigger = New-ScheduledTaskTrigger -Weekly -At $task.TimeToRun -DaysOfWeek $task.DayToRun
Register-ScheduledTask -Action $action -Trigger $trigger -TaskName $task.TaskName -User $Username -Password $Password -Description $task.Description
}
# script out SchTasks magic to create the monthly tasks
if ($runSpan.Equals("Monthly"))
{
$taskParams = #("/Create",
"/TN", $task.TaskName,
"/SC", "monthly",
"/D", $task.DayToRun,
"/ST", $task.TimeToRun,
"/TR", $filePath,
"/F", #force
"/RU", $Username,
"/RP", $Password);
# supply the command arguments and execute
#schtasks.exe $taskParams
schtasks.exe #taskParams
}
I'm using an in-script class to keep track of all the task properties ($task.TimeToRun, $task.DayToRun, etc.), iterating over a list of those, applying the Powershell implementation for daily and weekly tasks, then switching to SchTasks.exe for the monthly spans.
One thing I want to note, is that at first glance, I thought setting the user context under which the task runs could be achieved with the U and P arguments, but that is not the case. That specifies the creds that Schtasks.exe runs under - in order to set the user context for the task, you must use RU and RP.
In addition to the link above, these two were also very helpful :
http://coding.pstodulka.com/2015/08/02/programmatically-scheduling-powershell-scripts-in-task-scheduler/
https://msdn.microsoft.com/en-us/library/windows/desktop/bb736357(v=vs.85).aspx