8

I am working on some release automation scripts that use Powershell to update existing scheduled tasks which execute various applications. In my script, I can set the Path and Working Directory of the application, but it doesn't seem to save the changes back to the task.

function CreateOrUpdateTaskRunner {
    param (
        [Parameter(Mandatory = $TRUE, Position = 1)][string]$PackageName,
        [Parameter(Mandatory = $TRUE, Position = 2)][Version]$Version,
        [Parameter(Mandatory = $TRUE, Position = 3)][string]$ReleaseDirectory
    )

    $taskScheduler = New-Object -ComObject Schedule.Service
    $taskScheduler.Connect("localhost")
    $taskFolder = $taskScheduler.GetFolder('\')

    foreach ($task in $taskFolder.GetTasks(0)) {

        # Check each action to see if it references the current package
        foreach ($action in $task.Definition.Actions) {

            # Ignore actions that do not execute code (e.g. send email, show message)
            if ($action.Type -ne 0) {
                continue
            }

            # Ignore actions that do not execute the specified task runner
            if ($action.WorkingDirectory -NotMatch $application) {
                continue
            }

            # Find the executable
            $path = Join-Path $ReleaseDirectory -ChildPath $application | Join-Path -ChildPath $Version
            $exe = Get-ChildItem $path -Filter "*.exe" | Select -First 1

            # Update the action with the new working directory and executable
            $action.WorkingDirectory = $exe.DirectoryName
            $action.Path = $exe.FullName
        }
    }
}

I have so far been unable to find an obvious Save function in the documentation (https://msdn.microsoft.com/en-us/library/windows/desktop/aa383607(v=vs.85).aspx). Am I taking the wrong approach here, and need to mess around with the task XML?

David Keaveny
  • 408
  • 1
  • 6
  • 12
  • What version of powershell are you working with? Use `Get-Host` to find out. – Colyn1337 Feb 11 '15 at 18:30
  • Version 2.0 (see http://serverfault.com/questions/666671/using-reflection-in-powershell-with-different-net-framework-versions for some of my verson-related woes!). If your solution works with a later version of Powershell that is supported by Server 2008 R2 then that will give me extra "push" to get the servers upgraded :-) – David Keaveny Feb 12 '15 at 03:37
  • Server 2008R2 supports up to 4.0 currently. See Windows PowerShell Requirements: https://technet.microsoft.com/en-us/library/hh847769.aspx – Davidw Feb 18 '15 at 04:59

1 Answers1

2

The RegisterTask method has an update flag that you would use. Something like this:

# Update the action with the new working directory and executable
$action.WorkingDirectory = $exe.DirectoryName
$action.Path = $exe.FullName

#Update Task
$taskFolder.RegisterTask($task.Name, $task.Definition, 4, "<username>", "<password>", 1, $null)

See the msdn article for details on each parameter.

James Santiago
  • 876
  • 5
  • 11
  • I really hope this isn't the only solution, as I don't want to be storing username/password combinations in my release scripts if I can help it... – David Keaveny Feb 19 '15 at 01:48
  • I believe you can specify the local system account and leave the password null. – James Santiago Feb 19 '15 at 02:24
  • My scheduled tasks run under specifically-created service accounts, with database access using Windows authentication, so I would still need to keep the existing credentials. – David Keaveny Feb 20 '15 at 00:37
  • Only well known system accounts get to skip the password requirement same as if you'd update these tasks manually. Even the new powershell cmdlets require the username and password when using a non-well known account. I suppose you could prompt for a password during run time, store it as a secure string in a variable, then access it when needed so it's only stored in memory when running the script. – James Santiago Feb 20 '15 at 01:13