4

The Task Scheduler(TS) isn't saving domain information for run task as user.

Steps to replicate:

In General->Security Options it shows which user the task will run as with the button "Change User or Group" beside it.

The TS lets me change the user to a domain user and shows "DOMAIN\USER" in the field.

Pressing OK prompts me to enter the password for "DOMAIN\USER" which I do.

Opening up the TS task again shows that the domain part of the "DOMAIN\USER" has been stripped out of the Run As field.

When that task is run it Does not run as the "DOMAIN\USER".

Expected Behavior

TS should run task as run as user like it does on Server 2012r2.

OS Details

OS is windows server 2016 standard build | Version 10.0.14393 Build 14393 and server is part of a domain.

EDIT: In windows 10 it looks like it does the same thing but the user does end up being run as correctly. In the exported task XML used to look like this: <UserId>DOMAIN\USER</UserId> but now it looks like this:[numbers-with-a-lot-of-hypens-that-starts-with-a-letter]</UserId>

EDIT-2: It looks like what's being stored in the XML settings is a Windows SID (security identifier).

4
  • check if you domain policy allows "Stored credential". Check if grant "allow log on as batch job" user rights helps.
    – strongline
    Aug 7, 2017 at 18:28
  • I don't have access to the domain policy but scheduled tasks using the same user on a Windows server 2012r2 work fine. It stores the credentials ok and runs if the user isn't logged on as the domain user.
    – John Aho
    Aug 7, 2017 at 19:32
  • different machine could be getting different policies. Run gpresult to find out. To see what user rights this account has, run "whoami /all"
    – strongline
    Aug 8, 2017 at 1:22
  • @strongline - The 2016 server has one privilege set that the other doesn't: SeDelegateSessionUserImpersonatePrivilege = disabled
    – John Aho
    Aug 8, 2017 at 17:49

2 Answers 2

2

Turns out it was an extra privilege that was on the new box that needed to be disabled and then Task Scheduler runs fine. "SeDelegateSessionUserImpersonatePrivilege" was the culprit.

What caused me to believe it was the task scheduler is that the task scheduler has changed how it saves the user in the Xml and it used to save it as “DOMAIN\USER” but now it saves it as a SID (security id) and doesn’t display the domain portion in the ‘RUN AS’ section of the task scheduler.

When I ran whoami /all I saw that one privilege was on the new box but not the old box.

That privilege was: SeDelegateSessionUserImpersonatePrivilege = disabled

Removing this privilege fixes the issue.

So on Windows Server 2016 std build 14393 enabling or removing the privilege SeDelegateSessionUserImpersonatePrivilege fixes this issue of Tasks not running as the stored user in Task Scheduler.

EDIT: Windows Server 2016 Task Scheduler runs correctly tasks that were set up right the first time with no edits and that had the checkbox ‘Run with highest privileges’ unchecked and starting in the future. So if you need to modify a scheduled tasks you should probably create a brand new task then delete the old one rather than edit an existing task.

3
  • Where do remove this setting?
    – Squashman
    Apr 1, 2019 at 21:45
  • This setting is in the Group Policy Management console.. To open the Group Policy Management Console. Go back to the Accessories category in the All Programs section of the Start menu. Click "Run," type "gpmc.msc" in the box and then click "OK" to open it.
    – John Aho
    Jun 7, 2019 at 1:14
  • When you're in group policy editor, ensure the policy for SeDelegateSessionUserImpersonatePrivilege is not grayed out. If it is grayed out, then there's probably a domain policy overriding it. @Squashman, the GPO is 'Obtain an impersonation token for another user in the same session' in Computer Configuration\Windows Settings\Security Settings\Local Policies\User Rights Assignment .
    – Skurfur
    Mar 23, 2022 at 12:32
0

The GPO solution by @John Aho is probably better for those that have full control over Group Policy but won't work for corporate environment I'm in. After hours of searching for a fix, I gave up and created 2 workaround functions in PowerShell:

function Get-FullUsername {
    <#
    .SYNOPSIS
        Given a task, returns the executing username with a domain prefix.

    .DESCRIPTION
        Returns username, with domain prefix, of the account that is used to run the task.  
        Magic used: Exports the task to XML, parses and converts the SID. 
        Lame but some Windows 10, Windows Server 2016 and 2019 seem to not want to show the 
        full username.  If you have full access to GPO, then check out easier ways to get to this info.
        For more on the GPO solution, see SO post in the links.

        If using pipeline, I recommend first filter by the username you're looking 
        for: e.g. Where-Object { $_.Principal.UserId -eq john } 

    .PARAMETER Task
        Task Object. Specifically a object of Microsoft.Management.Infrastructure.CimInstance#MSFT_ScheduledTask

    .EXAMPLE
        $ObjTask = Get-ScheduledTask -TaskName "DR - Backup files"
        Get-FullUsername -Task $ObjTask

    .EXAMPLE
        Get-ScheduledTask -TaskName "Restart sentinel"  | Get-FullUsername

    .EXAMPLE
        Get-ScheduledTask | Where-Object { $_.Principal.UserId -eq "john" } | Get-FullUsername -Verbose

    .OUTPUTS
        [String] Domain\username.

    .LINK
        https://serverfault.com/questions/867351/windows-server-2016-task-scheduler-doesnt-save-domain-user-to-run-as-properly 

    #>

    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [object]$Task=$false
    )

    process
    {
        [xml]$XmlTask = Export-ScheduledTask -TaskName $Task.TaskName -TaskPath $Task.TaskPath
        $SID = $($XmlTask.Task.Principals.Principal.UserId)
        $ObjSID = New-Object System.Security.Principal.SecurityIdentifier ($SID)
        $ObjUser = $ObjSID.Translate( [System.Security.Principal.NTAccount] )
        $DomainUsername = $ObjUser.Value

        Write-Verbose "------------------------------------------------"
        Write-Verbose "TaskName: $($Task.TaskName)"
        Write-Verbose "TaskPath: $($Task.TaskPath)"
        Write-Verbose "SID: $SID"
        Write-Verbose "Returning Username: $DomainUsername "

        echo $DomainUsername
    }
}

function Get-ScheduledTasksByFullUsername {
    <#
    .SYNOPSIS
        Find tasks that are run under account given by FullUsername.

    .DESCRIPTION
        Currently can't search for tasks by a given username.  Even worse, the UserId returned
        by objects from Get-ScheduledTask is the shortname of a username (no domain).  If you have
        accounts in multiple domains running different tasks and you want to update the stored passwords
        for only 1 account in a domain, this is a problem.  Using this function you can get exactly 
        the tasks you need to update.

    .PARAMETER Tasks
        Optional array of Tasks Objects. Specifically a object of Microsoft.Management.Infrastructure.CimInstance#MSFT_ScheduledTask
        Accepts Tasks from pipeline so you can filter.

    .PARAMETER FullUsername
        Username with domain prefix (e.g. MAKESTUFFINC\john )

    .EXAMPLE
        Get-ScheduledTasksByFullUsername  -FullUsername "MAKESTUFFINC\john"

    .EXAMPLE
        Get-ScheduledTask | Get-ScheduledTasksByFullUsername -FullUsername "MAKESTUFFINC\john" -Verbose

    .EXAMPLE
        Get-ScheduledTask -TaskName "DR - Backup files" | Get-ScheduledTasksByFullUsername -FullUsername "MAKESTUFFINC\john"

    .EXAMPLE
        # Update all schedule tasks that are running under account by given credential. Credit to Jeremy Baumgartner.
        $TaskCredential = Get-Credential
        Get-ScheduledTasksByFullUsername -FullUsername $TaskCredential.UserName | Set-ScheduledTask -User $TaskCredential.UserName -Password $TaskCredential.GetNetworkCredential().Password

    .OUTPUTS
        Task objects - Specifically MSFT_ScheduledTask task objects.

    .LINK
        https://serverfault.com/questions/867351/windows-server-2016-task-scheduler-doesnt-save-domain-user-to-run-as-properly 

    .LINK
        https://nointerrupts.com/2018/10/18/update-scheduled-task-password-with-powershell/

    #>

    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$false,ValueFromPipeline=$true)]
        [object[]]$Tasks=$false,
        [Parameter(Mandatory=$true,ValueFromPipeline=$false)]
        [ValidateNotNullOrEmpty()]
        [string]$FullUsername=$false
    )

    begin {
        $ShortUsername = Split-Path $FullUsername -Leaf
        Write-Verbose "Full Username: $FullUsername"
        Write-Verbose "Short Username: $ShortUsername"
        $DefaultTasks = Get-ScheduledTask | Where-Object { $_.Principal.UserId -eq $ShortUsername } 
    }

    process {
        if (-not $Tasks) {
            # Use default tasks to search through
            Write-Verbose "Searching through tasks running under short username $ShortUsername."
            $Tasks = $DefaultTasks
        }

        ForEach($Task in $Tasks) {
            if ($Task) {
                Write-Verbose "================================================"
                Write-Verbose "Checking on $($Task.TaskName)"
                if (($(Get-FullUsername -Task $Task ) -eq $FullUsername)) {
                    # Let task live on in pipeline if matches criteria
                    $Task
                }
            }
        }
    }
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .