locked
Windows 2008 R2 SP1 Scheduled Task Defrag RRS feed

  • Question

  • Windows 2008 R2 SP1, No Domain (Workgroup).

    There is a ScheduledDefrag task that has its trigger set to disable by default. Is there a way through Powershell scripting to set that trigger to enable. I have about 4500 servers I would like to turn this on.

    If not Powershell then some other way?

    THANKS !!!

    Gerry

    Wednesday, July 13, 2011 5:36 PM

Answers

  • This is doable using the task scheduler scripting objects. Simple PowerShell example:

    $taskService = new-object -comobject "Schedule.Service"
    $taskService.Connect("localhost")
    $taskFolder = $taskService.GetFolder("\Microsoft\Windows\Defrag")
    $task = $taskFolder.GetTask("ScheduledDefrag")
    $task.Enabled = $TRUE
    

    Replace "localhost" with the server name (you could do this with a list of computer names and get-content).

    HTH,

    Bill

    • Proposed as answer by Just Karl Wednesday, July 13, 2011 9:51 PM
    • Marked as answer by IamMred Saturday, July 16, 2011 6:17 AM
    Wednesday, July 13, 2011 8:51 PM
  • This works great to Enable/Disable the ScheduledDefrag task but it is the trigger inside this task that has its own Enable/Disable (not sure why?).

    Is there something like $task.Settings.trigger = Enable/Disable or True/False ?

    This is a bit more complicated because for some reason you can't just access the trigger and enable or disable it. You instead have to get the TaskDefinition object, set it the way you want, and the re-register the task using the RegisterTaskDefinition method. I tested this on my Windows 7 x64 machine and it worked for me:

    # Used by the RegisterTaskDefinition method
    $TASK_CREATE_OR_UPDATE = 0x6
    
    # Specify the computer name
    $computerName = "localhost"
    # Specify the task's name
    $taskName = "\Microsoft\Windows\Defrag\ScheduledDefrag"
    
    $taskService = new-object -comobject "Schedule.Service"
    $taskService.Connect($computerName)
    $taskFolder = $taskService.GetFolder("\")
    $registeredTask = $taskFolder.GetTask($taskName)
    $registeredTask.Enabled = $TRUE
    $taskDefinition = $registeredTask.Definition
    $taskDefinition.Triggers | foreach-object { $_.Enabled = $TRUE }
    [Void] $taskFolder.RegisterTaskDefinition($taskName, $taskDefinition,
     $TASK_CREATE_OR_UPDATE, $NULL, $NULL, $taskDefinition.Principal.LogonType)
    

    Note that this sample code enables the task and also enables all of the task's triggers (if there are more than one).

    HTH,

    Bill


    • Edited by Bill_Stewart Thursday, July 14, 2011 6:50 PM Code had $FALSE instead of $TRUE for Enabled property; corrected
    • Marked as answer by IamMred Saturday, July 16, 2011 6:17 AM
    Thursday, July 14, 2011 5:31 PM

All replies

  • It doesn't appear that there is a built-in PowerShell cmdlet that will manipulate scheduled tasks.  However, that still leaves us with some very functional tools:

    schtasks.exe - http://www.peetersonline.nl/index.php/powershell/managing-scheduled-tasks-remotely-using-powershell/ (PowerShell commands using schtasks.exe)
    Win32_ScheduledJob - http://msdn.microsoft.com/en-us/library/aa394601(v=vs.85).aspx (technet for Win32_ScheduledJob class)

    Wednesday, July 13, 2011 6:11 PM
  • Hi,

    I think the Win32_ScheduledJob class is not going to work as it does not support Task Scheduler jobs (only "at" jobs).

    Bill

    Wednesday, July 13, 2011 6:20 PM
  • you are correct sir... good catch. 

    "

    The Win32_ScheduledJobWMI class represents a job created with the AT command. The Win32_ScheduledJob class does not represent a job created with the Scheduled Task Wizard from the Control Panel. You cannot change a task created by WMI in the Scheduled Tasks UI."

    http://msdn.microsoft.com/en-us/library/aa394399(v=vs.85).aspx

    Wednesday, July 13, 2011 6:34 PM
  • This is doable using the task scheduler scripting objects. Simple PowerShell example:

    $taskService = new-object -comobject "Schedule.Service"
    $taskService.Connect("localhost")
    $taskFolder = $taskService.GetFolder("\Microsoft\Windows\Defrag")
    $task = $taskFolder.GetTask("ScheduledDefrag")
    $task.Enabled = $TRUE
    

    Replace "localhost" with the server name (you could do this with a list of computer names and get-content).

    HTH,

    Bill

    • Proposed as answer by Just Karl Wednesday, July 13, 2011 9:51 PM
    • Marked as answer by IamMred Saturday, July 16, 2011 6:17 AM
    Wednesday, July 13, 2011 8:51 PM
  • Dang, Bill;

    You beat me to it ;)

    I have a section on Managing Scheduled Tasks in my chapter on Basic Server Management.

    If the user needs to pass credentials, this can be accomplished like so:

    $Credential = Get-Credential -Credential "Contoso\sherrym"
    $TaskService = New-Object -ComObject Schedule.Service
    $TaskService.Connect("Remote-Server",$Credential.GetNetworkCredential().UserName,$Credential.GetNetworkCredential().Domain,$Credential.GetNetworkCredential().Password)
    

    Karl


    http://unlockpowershell.wordpress.com
    Co-Author, Windows PowerShell 2.0 Bible
    -join("6B61726C6D69747363686B65406D742E6E6574"-split"(?<=\G.{2})",19|%{[char][int]"0x$_"})
    Wednesday, July 13, 2011 9:47 PM
  • Hi Karl,

    Good point - I forgot to mention that you can pass credentials to the Connect method.

    Bill

    Wednesday, July 13, 2011 10:00 PM
  • Another good reason to get 'The PowerShell Bible'

    Hi Karl.

     


    jv
    Wednesday, July 13, 2011 10:23 PM
  • This works great to Enable/Disable the ScheduledDefrag task but it is the trigger inside this task that has its own Enable/Disable (not sure why?).

    Is there something like $task.Settings.trigger = Enable/Disable or True/False ?

    There is an XML file used for this task 

    C:\Windows\System32\Tasks\Microsoft\Windows\Defrag\ScheduledDefrag

    I can export an XML file from this task but it looks like I cannot overwrite back over it (unless I an doing something wrong).

    Thanks!!!

    Gerry

    Thursday, July 14, 2011 2:46 PM
  • Where do I get this Powershell Bible (Is that what it is actually called?)

    Gerry

    Thursday, July 14, 2011 2:47 PM
  • Gerry;

    It's actually called "Windows PowerShell 2.0 Bible" and it's available on Amazon for pre-order

    Disclaimer:
    I'm one of the authors, and so I am a bit biased ;)
    Also, although we are done writing the book, we are still in the editing mode.

    Karl


    http://unlockpowershell.wordpress.com
    Co-Author, Windows PowerShell 2.0 Bible
    -join("6B61726C6D69747363686B65406D742E6E6574"-split"(?<=\G.{2})",19|%{[char][int]"0x$_"})
    Thursday, July 14, 2011 2:58 PM
  • This works great to Enable/Disable the ScheduledDefrag task but it is the trigger inside this task that has its own Enable/Disable (not sure why?).

    Is there something like $task.Settings.trigger = Enable/Disable or True/False ?

    This is a bit more complicated because for some reason you can't just access the trigger and enable or disable it. You instead have to get the TaskDefinition object, set it the way you want, and the re-register the task using the RegisterTaskDefinition method. I tested this on my Windows 7 x64 machine and it worked for me:

    # Used by the RegisterTaskDefinition method
    $TASK_CREATE_OR_UPDATE = 0x6
    
    # Specify the computer name
    $computerName = "localhost"
    # Specify the task's name
    $taskName = "\Microsoft\Windows\Defrag\ScheduledDefrag"
    
    $taskService = new-object -comobject "Schedule.Service"
    $taskService.Connect($computerName)
    $taskFolder = $taskService.GetFolder("\")
    $registeredTask = $taskFolder.GetTask($taskName)
    $registeredTask.Enabled = $TRUE
    $taskDefinition = $registeredTask.Definition
    $taskDefinition.Triggers | foreach-object { $_.Enabled = $TRUE }
    [Void] $taskFolder.RegisterTaskDefinition($taskName, $taskDefinition,
     $TASK_CREATE_OR_UPDATE, $NULL, $NULL, $taskDefinition.Principal.LogonType)
    

    Note that this sample code enables the task and also enables all of the task's triggers (if there are more than one).

    HTH,

    Bill


    • Edited by Bill_Stewart Thursday, July 14, 2011 6:50 PM Code had $FALSE instead of $TRUE for Enabled property; corrected
    • Marked as answer by IamMred Saturday, July 16, 2011 6:17 AM
    Thursday, July 14, 2011 5:31 PM
  • Bill:

    This worked on my 2008 R2 Server as well. THANKS!! for your help.

    Greatly Appreciated.

    Gerry

    Monday, July 18, 2011 10:40 AM
  • Sounds good, i will pick one up when its ready.

    Thanks for your help :)

    Gerry.

    Monday, July 18, 2011 10:44 AM
  • This looks great to force the enable operation.  What I would like to do is to modify the existing task so that it runs monthly on the first of every month at 4:00 AM, instead of every Wednesday at 1:00 AM.  I first tried using the schtasks /change command, and that doesn't provide the mechanism to do it.  I also tried deleting the task and creating a new one, but as soon as I started up the dfrgui.exe program, it recreated the original.

    Then I saw the above post, using powershell (which I've never used before), but it only shows how to enable it.  I can't find any object definitions to know how to change the scheduled times.  Any help here would be greatly appreciated!


    Tuesday, July 26, 2011 6:45 PM
  • Hi,

    You can do this by clearing the existing triggers and using the TriggerCollection object's Create method to create a new monthly trigger. For example:

    $TASK_CREATE_OR_UPDATE = 6
    $TASK_TRIGGER_MONTHLY = 4
    $ALL_MONTHS = 0xFFF
    
    $computerName = "localhost"
    $taskName = "\Microsoft\Windows\Defrag\ScheduledDefrag"
    $taskService = new-object -comobject "Schedule.Service"
    $taskService.Connect($computerName)
    $taskFolder = $taskService.GetFolder("\")
    $registeredTask = $taskFolder.GetTask($taskName)
    $registeredTask.Enabled = $TRUE
    $taskDefinition = $registeredTask.Definition
    $triggerCollection = $taskDefinition.Triggers
    $triggerCollection.Clear()
    $monthlyTrigger = $triggerCollection.Create($TASK_TRIGGER_MONTHLY)
    $monthlyTrigger.DaysOfMonth = 1
    $monthlyTrigger.Enabled = $TRUE
    $monthlyTrigger.Id = "DefragMonthlyTrigger"
    $monthlyTrigger.MonthsOfYear = $ALL_MONTHS
    $monthlyTrigger.StartBoundary = "2011-01-01T04:00:00"
    [Void] $taskFolder.RegisterTaskDefinition($taskName, $taskDefinition,
     $TASK_CREATE_OR_UPDATE, $NULL, $NULL, $taskDefinition.Principal.LogonType)
    

    HTH,

    Bill

    Tuesday, July 26, 2011 10:08 PM
  • Well, maybe it isn't working quite right.  I took the above code and saved it into Win7Defrag.ps1.  Then, in my VB6 (yeah, that's right, VB6,  that's the way it goes...) program, I have it execute:

     Const WIN7DEFRAG As String = "Win7Defrag.ps1"
     Set objShell = New IWshRuntimeLibrary.WshShell
     sCmd = "Powershell.exe -ExecutionPolicy Unrestricted -File " & WIN7DEFRAG
     lRet = objShell.Run(sCmd, vbHide, True)
    

    It appears to work properly, but then when I go to control panel to run the task scheduler and examine the scheduled tasks, it gives me the following error:  "The selected task "{0}" no longer exists. To see the current tasks, click Refresh."  In the Task Status and Active Task sections, it tells me, "Reading Data Failed."  If I go to the left section of the window where it has the Task Scheduler Library, I can drill into Microsoft\Windows and see the Defrag folder.  If I click on it, it gives me the "selected task {0}" error again.  If I run dfrgui.exe, it does properly show the scheduling of the defrag to be monthly on the first of each month at 4 AM.

    Did I use a bad approach?  (It has to be something I invoke from within VB6.)  Something else possibly wrong that can be fixed?

    Again, thanks so much for your help.

    Mickey


    Wednesday, July 27, 2011 12:29 AM
  • Hi,

    Run it from a PowerShell prompt and check if it works that way.

    Bill

    Wednesday, July 27, 2011 2:23 PM
  • Yes and then no.  By that I mean that when I ran the command

      Powershell.exe -ExecutionPolicy Unrestricted -File Win7Defrag1.ps1

    from a cmd.exe window, after it completed I was able to start up the scheduled tasks window and it showed everything fine.  I rebooted the computer, went to look at scheduled tasks again, and now I got that same "selected task {0}" error.

    I can't run it directly from a powershell prompt because script execution within powershell is disabled.

    Am I doing something wrong, or is there a modification that can solve this?


    Wednesday, July 27, 2011 7:56 PM
  • Hi,

    I noticed the same behavior. Try removing this line from the code:

    $monthlyTrigger.Id = "DefragMonthlyTrigger"

    HTH,

    Bill

    Wednesday, July 27, 2011 8:24 PM
  • Nope.  Same behavior as before.
    Wednesday, July 27, 2011 10:22 PM
  • Hi,

    Sorry, I don't know the cause. The code looks correct and the methodology seems sound. (Sometimes free help is not so helpful) I will see if I can fix it but no guarantees.

    Bill

    Wednesday, July 27, 2011 10:30 PM
  • You do your best, and I appreciate it.  Anyone else out there have any clues?
    Thursday, July 28, 2011 12:15 AM
  • Hi,

    Try to perform this task from the defrag GUI (set it to monthly, first day of every month, 4am) and enable the task and see if you have the same problem after a reboot. Does the problem persist?

    Bill

    Thursday, July 28, 2011 5:46 PM
  • Good observation!  Yes, using task scheduler to modify the task, saving and then rebooting the system causes this same error!  Sure sounds like a bug to me.
    Thursday, July 28, 2011 7:29 PM
  • I am also seeing a warning message in the history for that task when it is modified to monthly (either through GUI or the script):

    Task registered task "\Microsoft\Windows\Defrag\ScheduledDefrag" , but not all specified triggers will start the task. User Action: Ensure all the task triggers are valid as configured. Additional Data: Error Value: 2147942487.

    I don't see this behavior when modifying a sample task I created; very odd. In any case, the script code is methodologically sound; the problem is elsewhere.

    Bill

    Thursday, July 28, 2011 7:39 PM
  • At this point we've decided just to leave the task as it is currently defined (weekly instead of monthly) and forget about the entire thing.  I really do appreciate all of the help you provided.  It's been instructive even if it didn't ultimately do what we wanted.
    Thursday, July 28, 2011 11:49 PM
  • This works great to Enable/Disable the ScheduledDefrag task but it is the trigger inside this task that has its own Enable/Disable (not sure why?).

    Is there something like $task.Settings.trigger = Enable/Disable or True/False ?

    This is a bit more complicated because for some reason you can't just access the trigger and enable or disable it. You instead have to get the TaskDefinition object, set it the way you want, and the re-register the task using the RegisterTaskDefinition method. I tested this on my Windows 7 x64 machine and it worked for me:

    # Used by the RegisterTaskDefinition method
    $TASK_CREATE_OR_UPDATE = 0x6
    
    # Specify the computer name
    $computerName = "localhost"
    # Specify the task's name
    $taskName = "\Microsoft\Windows\Defrag\ScheduledDefrag"
    
    $taskService = new-object -comobject "Schedule.Service"
    $taskService.Connect($computerName)
    $taskFolder = $taskService.GetFolder("\")
    $registeredTask = $taskFolder.GetTask($taskName)
    $registeredTask.Enabled = $TRUE
    $taskDefinition = $registeredTask.Definition
    $taskDefinition.Triggers | foreach-object { $_.Enabled = $TRUE }
    [Void] $taskFolder.RegisterTaskDefinition($taskName, $taskDefinition,
     $TASK_CREATE_OR_UPDATE, $NULL, $NULL, $taskDefinition.Principal.LogonType)
    

    Note that this sample code enables the task and also enables all of the task's triggers (if there are more than one).

    HTH,

    Bill


    Though your code works perfectly if you set all triggers the same.

    We need to set them individually...

    Although the code below doesn't throw any errors, it also doesn't work:

    ...

    # Specify the task's name (*Test task*)
    $taskName = "\Adobe Flash Player Updater"

    $taskService = new-object -comobject "Schedule.Service"
    $taskService.Connect($computerName)
    $taskFolder = $taskService.GetFolder("\")
    $registeredTask = $taskFolder.GetTask($taskName)
    $registeredTask.Enabled = $TRUE
    $taskDefinition = $registeredTask.Definition
    $Triggers = $TaskDefinition.Triggers
    foreach ($trigger.id in $Triggers)
    {
    if ($trigger.id -eq "Daily")  {$_.Enabled = $True}
    if ($trigger.id -eq "Weekly") {$_.Enabled = $False}
    }
    [Void] $taskFolder.RegisterTaskDefinition($taskName, $taskDefinition, $TASK_CREATE_OR_UPDATE, $NULL, $NULL, $taskDefinition.Principal.LogonType)




    • Edited by wmikef Tuesday, November 20, 2012 5:41 PM
    Tuesday, November 20, 2012 5:20 PM
  • Hi,

    This question is already marked as answered. If you still need help, please start a new question.

    Bill

    Tuesday, November 20, 2012 6:06 PM