Need to disable a clusterschduled task in windows 2012, using following command
however it is not disabling clusterscheduled tasks.
get-ClusteredScheduledTask -disable
Disable-ScheduledTask -TaskName
The pipe | is causing the entire set of objects returned from get-ClusteredScheduledTasks to be passed to the Disable-ScheduledTask. The use of the -TaskName is causing an error in the Disable-ScheduledTask command, because the pipe tells it "apply this command to these objects," but you then immediately try to apply the command to a single task named "schTest 123". This article provides some deeper explanation on command piping.
A couple different ways to solve this, depending on what you're trying to do:
1) If your goal is to disable ALL tasks that are currently scheduled:
$tasks = get-ScheduledTasks | where { $_.State -eq "Ready" } # exclude any tasks that are already disabled so we don't accidentally re-enable them later
$tasks | Disable-ScheduledTask
# do your work
$tasks | Enable-ScheduledTask
OR
$tasks = get-ScheduledTasks | where { $_.State -eq "Ready" }
$tasks | foreach { Disable-ScheduledTask -TaskName $_.TaskName }
# do your work
$tasks | foreach { Enable-ScheduledTask -TaskName $_.TaskName }
These are functionally identical, but the first one is certainly semantically cleaner.
2) If your goal is to disable only a single task by name
Disable-ScheduledTask -TaskName $myTaskName
# do your work
Enable-ScheduledTask -TaskName $myTaskName
3) If you want to be certain a single task exists prior to disabling/enabling
$task = get-ClusteredScheduledTasks | where { $_.TaskName -eq $myTaskName }
if ( $task -eq $Null ) { throw ( "Could not find scheduled task " + $myTaskName ) }
Disable-ScheduledTask -TaskName $task.TaskName
# do work
Enable-ScheduledTask -TaskName $task.TaskName
Related
Afternoon all,
I've got a script that runs scheduled tasks on some remote computers through Cimsessions.
Start-ScheduledTask -CimSession $CimSessions -TaskName "<Task-Name>"
I then have a timer that runs in a Do/Until loop until the tasks are completed. However, the loop ends when one server has completed the task even if others have finished. Is there a way I can re-write my loop to continue until all servers have registered that their task is not running
$StartTime = Get-Date
Do{
$ElapsedTime = (Get-Date) - $StartTime
$TotalTime = "{0:HH:mm:ss}" -f ([datetime]$ElapsedTime.Ticks)
$CurrentLine = $host.UI.RawUI.CursorPosition
Write-Output "Running Scheduled Task... [Total Elapsed Time: $(stc $TotalTime yellow)]"
sleep -s 2
$host.UI.RawUI.CursorPosition = $CurrentLine
}Until((Get-ScheduledTask -CimSession $CimSessions -TaskName "<Task-Name").State -ne 'Running')
Note: the line of code $(stc $TotalTime yellow) is just a custom function that changes the color of the text to yellow
The condition:
Until((Get-ScheduledTask -CimSession $CimSessions -TaskName "<Task-Name>").State -ne 'Running')
Is saying, "run this loop and stop as soon as there is one object with it's State property not equal to Running". What you want instead is, "run this loop while there are objects having the State property equal to Running", hence the condition should be:
# with `-contains`
while((Get-ScheduledTask -CimSession $CimSessions -TaskName "<Task-Name>").State -contains 'Running')
# with `-in`
while('Running' -in (Get-ScheduledTask -CimSession $CimSessions -TaskName "<Task-Name>").State)
As aside, you could greatly simplify the task of $ElapsedTime = (Get-Date) - $StartTime by leveraging the StopWatch Class. Here is a little example:
$timer = [System.Diagnostics.Stopwatch]::StartNew()
do {
$timer.Elapsed.ToString('hh\:mm\:ss')
Start-Sleep 1
} until($timer.Elapsed.Seconds -ge 5)
I have a PowerShell script that starts a task on a remote server. The task takes hours to run so I need to have a loop in my code to check the task every few minutes to see if it's still running before the script proceeds to the next step. I tried running the following:
$svc_cred = Get-Credential -Credential <DOMAIN>\<ServiceAccount>
$global:Remote_session = New-PSSession -ComputerName <Server> -Credential $svc_cred
Invoke-Command -Session $global:Remote_session -ScriptBlock {
$results = Get-ScheduledTask -TaskName "Export_users" -TaskPath "\"
Write-Output "Taskname: $results.TaskName"
Write-Output "State: $results.State"
}
But this produces the output:
Taskname: MSFT_ScheduledTask (TaskName = "Export_users", TaskPath = "\").TaskName
State: MSFT_ScheduledTask (TaskName = "Export_users", TaskPath = "\").State
My desired outpout is:
Taskname: Export_users
State: Running
How do I code this to allow access the script to check if State is equal to "Running"?
You can use the State property of a scheduled task on a while loop, like this:
Start-ScheduledTask -TaskName 'SomeTaskName'
while ((Get-ScheduledTask -TaskName 'SomeTaskName').State -ne 'Ready') {
##Wait a while
Start-Sleep -Seconds 10
}
The comment from Santiago Squarzon answered my question.
"Taskname: $($results.TaskName)" and "State: $($results.State)" or even simpler, $results | Select-Object TaskName, State –
Santiago Squarzon
Thought I would share this quick function I made for myself, feel free to adapt it and improve it according to your needs.
Sometimes you want to run commands as the logged on user of a remote computer.
As you know, some commands show output for the user who runs it and if you run the same command with Invoke-Command, it won't return the user's information, but yours). Get-Printer is an example amongst many others.
There is no easy, quick way of running commands as the logged on user natively without any third-party apps like PsExec or others so I made this quick function that uses VBS, PS1 and Scheduled Task to make it happen.
It runs completly silently for the user (thanks to the VBS) and the output is shown in your console. Please note it assumes the remote computer has a C:\TEMP.
Created in a Windows 10, powershell v 5.1.17763.503 environement.
I don't pretend it's final and perfect, it's the simplest way I found to do what is needed and I just wanted to share it with you guys as it can be very useful!
Check the comments for explanation of the code and feel free to use it as you wish. Please share your version as I'm curious to see people improve it. A good idea would be to make it support multiple computers, but as I said it's a quick function I did I don't have too much time to put into refining it.
That being said, I had no problems using it multiple times as is :)
*Output returned is in form of a string, if you want to have a proper object, add '| ConvertFrom-String' and play with it :)
PLEASE NOTE: The surefire way of grabbing the username of who is currently logged on is via QWINSTA (since Win32_ComputerSystem - Username is only reliable if a user is logged on LOCALLY, it won't be right if a user is using RDP/RemoteDesktop). So this is what I used to grab the username, however, please note that in our french environement the name of the username property in QWINSTA is "UTILISATEUR",so you have to change that to your needs (english or other language) for it to work. If I remember correctly, it's "USERNAME" in english.
On this line:
$LoggedOnUser = (qwinsta /SERVER:$ComputerName) -replace '\s{2,22}', ',' | ConvertFrom-Csv | Where-Object {$_ -like "*Acti*"} | Select-Object -ExpandProperty UTILISATEUR
See code in the answer below.
function RunAsUser {
Param ($ComputerName,$Scriptblock)
#Check that computer is reachable
Write-host "Checking that $ComputerName is online..."
if (!(Test-Connection $ComputerName -Count 1 -Quiet)) {
Write-Host "$ComputerName is offline" -ForegroundColor Red
break
}
#Check that PsRemoting works (test Invoke-Command and if it doesn't work, do 'Enable-PsRemoting' via WMI method).
#*You might have the adjust this one to suit your environement.
#Where I work, WMI is always working, so when PsRemoting isn't, I enable it via WMI first.
Write-host "Checking that PsRemoting is enabled on $ComputerName"
if (!(invoke-command $ComputerName { "test" } -ErrorAction SilentlyContinue)) {
Invoke-WmiMethod -ComputerName $ComputerName -Path win32_process -Name create -ArgumentList "powershell.exe -command Enable-PSRemoting -SkipNetworkProfileCheck -Force" | Out-Null
do {
Start-Sleep -Milliseconds 200
} until (invoke-command $ComputerName { "test" } -ErrorAction SilentlyContinue)
}
#Check that a user is logged on the computer
Write-host "Checking that a user is logged on to $ComputerName..."
$LoggedOnUser = (qwinsta /SERVER:$ComputerName) -replace '\s{2,22}', ',' | ConvertFrom-Csv | Where-Object {$_ -like "*Acti*"} | Select-Object -ExpandProperty UTILISATEUR
if (!($LoggedOnUser) ) {
Write-Host "No user is logged on to $ComputerName" -ForegroundColor Red
break
}
#Creates a VBS file that will run the scriptblock completly silently (prevents the user from seeing a flashing powershell window)
#"
Dim wshell, PowerShellResult
set wshell = CreateObject("WScript.Shell")
Const WindowStyle = 0
Const WaitOnReturn = True
For Each strArg In WScript.Arguments
arg = arg & " " & strArg
Next 'strArg
PowerShellResult = wshell.run ("PowerShell " & arg & "; exit $LASTEXITCODE", WindowStyle, WaitOnReturn)
WScript.Quit(PowerShellResult)
"# | out-file "\\$ComputerName\C$\TEMP\RAU.vbs" -Encoding ascii -force
#Creates a script file from the specified '-Scriptblock' parameter which will be ran as the logged on user by the scheduled task created below.
#Adds 'Start-Transcript and Stop-Transcript' for logging the output.
$Scriptblock = "Start-Transcript C:\TEMP\RAU.log -force" + $Scriptblock + "Stop-Transcript"
$Scriptblock | out-file "\\$ComputerName\C$\TEMP\RAU.ps1" -Encoding utf8 -force
#On the remote computer, create a scheduled task that runs the .ps1 script silently in the user's context (with the help of the vbs)
Write-host "Running task on $ComputerName..."
Invoke-Command -ComputerName $ComputerName -ArgumentList $LoggedOnUser -ScriptBlock {
param($loggedOnUser)
$SchTaskParameters = #{
TaskName = "RAU"
Description = "-"
Action = (New-ScheduledTaskAction -Execute "wscript.exe" -Argument "C:\temp\RAU.vbs C:\temp\RAU.ps1")
Settings = (New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -DontStopOnIdleEnd)
RunLevel = "Highest"
User = $LoggedOnUser
Force = $true
}
#Register and Start the task
Register-ScheduledTask #SchTaskParameters | Out-Null
Start-ScheduledTask -TaskName "RAU"
#Wait until the task finishes before continuing
do {
Write-host "Waiting for task to finish..."
$ScheduledTaskState = Get-ScheduledTask -TaskName "RAU" | Select-Object -ExpandProperty state
start-sleep 1
} until ( $ScheduledTaskState -eq "Ready" )
#Delete the task
Unregister-ScheduledTask -TaskName "RAU" -Confirm:$false
}
Write-host "Task completed on $ComputerName"
#Grab the output of the script from the transcript and remove the header (first 19) and footer (last 5)
$RawOutput = Get-Content "\\$ComputerName\C$\temp\RAU.log" | Select-Object -Skip 19
$FinalOutput = $RawOutput[0..($RawOutput.length-5)]
#Shows output
return $FinalOutput
#Delete the output file and script files
Remove-Item "\\$ComputerName\C$\temp\RAU.log" -force
Remove-Item "\\$ComputerName\C$\temp\RAU.vbs" -force
Remove-Item "\\$ComputerName\C$\temp\RAU.ps1" -force
}
#____________________________________________________
#Example command
#Note: Sometimes Start-Transcript doesn't show the output for a certain command, so if you run into empty output, add: ' | out-host' or '| out-default' at the end of the command not showing output.
$Results = RunAsUser -ComputerName COMP123 -Scriptblock {
get-printer | Select-Object name,drivername,portname | Out-host
}
$Results
#If needed, you can turn the output (which is a string for the moment) to a proper powershell object with ' | ConvertFrom-String'
I have the below PowerShell code to validate if a scheduled task exists and to check its state.
$SchTsk = Get-ScheduledTask | Select Name, State | ? {$_.Name -eq $SchTask}
If ($SchTsk -ne $Null)
{
Write-Host "SchTask $SchTask exists"
If ($SchTsk.State -eq 3)
{
Write-Host "SchTask State: READY!"
}
}
The code works fine on Windows Server 2008 but does not work on Windows Server 2003. In 2003 I get an error:
New-Object : Cannot load COM type Schedule.Service.
From what I've read it seems that the Schedule.Service COM object does not exist on Server 2003.
So...is there a work-around for this issue to validate a scheduled task and its state on Server 2003?
The following is a sample PowerShell script that reads from the COM object mentioned above and outputs some Task Schedule Information:
#Connecting to COM Object
$schedService = New-Object -ComObject Schedule.Service
$schedService.Connect($Computer)
# Get Scheduled Tasks on Root Folder (Task Scheduler Library)
$folder = $SchedService.GetFolder("")
$tasks = $folder.GetTasks("")
# Output Task Details
$tasks | % {
"-" * 40
"Task " + $_.Name + ":"
"-" * 40
$_.Definition.Actions
}
I have PowerShell scripts running on Win2008 and Win2003, and found the command "schtasks" to be good enough for looking up information about scheduled tasks. This isn't a powershell command, but it's a standard function in Windows, and is compatible with Windows 2003 and 2008.
$scheduledTasks = schtasks /query /v /fo csv | ConvertFrom-Csv
#this will return an array of scheduled tasks with all info available for the task
To check if a scheduled task is ready on 2003, you'll need to make sure "Scheduled Task State" is "Enabled", and Status is blank.
On 2008 and above, Status will return enabled, disabled, running, etc.
If all you want to do is gather the basic properties of a task so you know it's name state and next run time you can use schtasks with the following methods:
function New-TaskInfo()
{
param ($TaskPath, $TaskName, $NextRunTime, $Status);
$task = new-object PSObject;
$task | add-member -type NoteProperty -Name Path-Value $TaskPath;
$task | add-member -type NoteProperty -Name Name -Value $TaskName;
$task | add-member -type NoteProperty -Name NextRunTime -Value $NextRunTime;
$task | add-member -type NoteProperty -Name Status -Value $Status;
return $task;
}
function Get-ScheduledTaskInfo
{
$tasks = #();
$queryOutput = schtasks /QUERY /FO CSV
foreach($line in $queryOutput)
{
$columns = $line.Split(',');
$taskPath = $columns[0].Replace('"', '');
if($taskPath -eq "TaskName")
{
#Ignore headder lines
continue;
}
$taskName = [System.IO.Path]::GetFileName($taskPath);
$nextRunTime = $columns[1].Replace('"', '');
$status = $columns[2].Replace('"', '');
$task = New-TaskInfo -TaskPath $taskPath -TaskName $taskName -NextRunTime $nextRunTime -Status $status;
Write-Host -ForegroundColor Green "Add Task $task";
$tasks += $task;
}
return $tasks;
}
If you then want to perform an action for a specific task you can use schtasks directly specifying data stored in the objects collected earlier.
$task = Get-ScheduledTaskInfo | Where-Object {$_.Name -eq 'TaskName'}
if($task.Status -eq 'Ready')
{
Write-Host -ForegroundColor Green "Task" $task.Name "Is" $task.Status;
#End the target task
schtasks /END /TN $task.Path;
}
You'll find all the informations you need about the missing COM object in Working with scheduled tasks from Windows PowerShell.
Using Windows Server 2012 you can use Scheduled Tasks Cmdlets in Windows PowerShell.
#ameer deen.. The code you have given returns the tasks at the root level only. Windows 2008 onwards several modifications are made to task manager and one of them is folder structure. To list all the tasks in side sub folders as well, we need to query the subfolders and iterate through them.
You can find the code sample for querying all(including the ones in subfolders) scheduled tasks at http://techibee.com/powershell/powershell-get-scheduled-tasks-list-from-windows-72008-computers/1647
I can't figure out why the below code won't work:
Function createFirefoxTask() {
$schedule = new-object -com Schedule.Service
$schedule.connect()
$tasks = $schedule.getfolder("\").gettasks(0)
foreach ($task in ($tasks | select Name)) {
echo "TASK: $task.name"
if($task.equals("FirefoxMaint")) {
write-output "$task already exists"
break
}
}
}
createFirefoxTask
The output I get is this:
FirefoxMaint
TASK: #{Name=FirefoxMaint}.name
TASK: #{Name=Task1}.name
TASK: #{Name=Task2}.name
TASK: #{Name=Task3}.name
TASK: #{Name=Task4}.name
TASK: #{Name=Task5}.name
If I echo $task.name from the shell without going through the script, it properly displays the name.
In order to prevent errors with Get-ScheduledTask in case the task doesn't exist - you might want to consider doing :
$taskName = "FireFoxMaint"
$taskExists = Get-ScheduledTask | Where-Object {$_.TaskName -like $taskName }
if($taskExists) {
# Do whatever
} else {
# Do whatever
}
Try this one:
Get-ScheduledTask -TaskName "Task Name" -ErrorAction SilentlyContinue -OutVariable task
if (!$task) {
# task does not exist, otherwise $task contains the task object
}
When used in a double-quoted string, variable evaluation will stop at punctuation. You can use $() to denote a subexpression within a string, like this:
"TASK: $($task.name)"
PowerShell will then evaluate the expression inside the parentheses and expand the string with the outcome
If you are using v3.0, then you can do this using Get-ScheduledTask. Forexample,
$task = Get-ScheduledTask -TaskName "FirefoxMaint" -TaskPath \
Then, just need to check the value of $task.
You can use the following code to test to see if a scheduled task exists in PowerShell:
if(Get-ScheduledTask FirefoxMaint -ErrorAction Ignore) { #found } else { #not found}