Powershell Script to Automate password Change for Scheduled Tasks

Managing scheduled tasks across multiple Domain Controllers and member servers is a routine yet critical responsibility for every Domain Administrator. Typically, these tasks are executed using Group Managed Service Accounts (gMSAs) for improved security and ease of credential management. However, when a password expires or the account is reset, manually updating credentials across numerous scheduled tasks on different servers can become a time-consuming and error-prone process.

To simplify this challenge, I’ve developed a PowerShell script designed to streamline the credential update process across your environment. The script is flexible and can be customized to suit your setup — you’ll need to update variables such as the username, the list of target servers, and optionally configure email settings (SMTP server and recipient address) if you’d like to receive execution reports. With minimal configuration, this tool can help reduce administrative overhead and ensure consistent task automation across your infrastructure.

The following is the Script and this this would need modifications in line 10,16,19,20 and 22

###################################################################################################################################
#       Author     : Karanth                                                                                                                                                                                                                                                 #
#       Date       : 10/26/2024                                                                                                                                                                                                                                            #
#       Modified   : 04/15/2025                                                                                                                                                                                                                                         #
#       Description: Updates the Service Account password in All Scheduled Tasks on On-Prem Servers                                                                                                                       #
#       Version    : V5                                                                                                                                                                                                                                                         #
###################################################################################################################################

# User account to update in scheduled tasks
$UserAccount = "Domain\Gmsa Account" # -----------------------------------> Update Your Domain name and Username

# Prompt for new password
$NewCred = Get-Credential -UserName $UserAccount -Message "Enter the new password for the user '$UserAccount'"

# Hardcoded list of servers
$Servers = @("Server1","Server2","Server3") # -----------------------------------> Update your Servernames 

# Email configuration
$EmailFrom = "sender@email.com"   # -----------------------------------> Update your email address from which you want to send 
$EmailTo = recipient@email.com"     # -----------------------------------> Update the reciever email address 
$EmailSubject = "Scheduled Task Password Update Report"
$SMTPServer = "SMTP Server Name" # -----------------------------------> Update the SMTP Server name 

# Track results
$TaskResults = @()

# Create CIM Sessions
$CimSessions = @()
foreach ($Server in $Servers) {
    try {
        Write-Verbose "Creating CIM session for $Server"
        $session = New-CimSession -ComputerName $Server -ErrorAction Stop
        $CimSessions += $session
    } catch {
        Write-Warning "Failed to create CIM session for $Server : $($_.Exception.Message)"
        $TaskResults += [PSCustomObject]@{
            ServerName = $Server
            TaskName   = "N/A"
            Status     = "Failed to connect"
            Timestamp  = (Get-Date)
        }
    }
}

if (-not $CimSessions) {
    Write-Warning "No valid CIM sessions established. Exiting script."
    exit
}

# Get all scheduled tasks with a user match
$UserShortName = $UserAccount.Split('\')[-1]
$Tasks = Get-ScheduledTask -CimSession $CimSessions | Where-Object {
    $_.Principal.UserId -like "*$UserShortName*"
}

if (-not $Tasks) {
    Write-Warning "No scheduled tasks found for user matching '$UserShortName'."
}

foreach ($task in $Tasks) {
    $server     = $task.PSComputerName
    $taskPath   = $task.TaskPath
    $taskName   = $task.TaskName
    $fullTaskName = "$taskPath$taskName".Trim()
    $timestamp  = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
    $status     = "Failed"

    try {
        $session = $CimSessions | Where-Object { $_.ComputerName -eq $server }
        Write-Host "Updating Task: '$fullTaskName' on $server"
        Set-ScheduledTask -CimSession $session -TaskName $taskName -TaskPath $taskPath -User $UserAccount -Password $NewCred.GetNetworkCredential().Password
        $status = "Success"
    } catch {
        Write-Warning "Failed to update task '$fullTaskName' on $server : $($_.Exception.Message)"
    }

    $TaskResults += [PSCustomObject]@{
        ServerName = $server
        TaskName   = $fullTaskName
        Status     = $status
        Timestamp  = $timestamp
    }
}

# Generate HTML email body
$EmailBody = @"
<html>
<head>
    <style>
        table { border-collapse: collapse; width: 100%; }
        th, td { border: 1px solid black; padding: 8px; text-align: left; }
        th { background-color: #f2f2f2; }
        .success { background-color: #d4edda; }
        .failed { background-color: #f8d7da; }
    </style>
</head>
<body>
    <h2>Scheduled Task Password Update Status</h2>
    <table>
        <tr>
            <th>Server Name</th>
            <th>Task Name</th>
            <th>Status</th>
            <th>Timestamp</th>
        </tr>
"@

foreach ($Result in $TaskResults) {
    $statusClass = if ($Result.Status -eq "Success") { "success" } else { "failed" }

    $EmailBody += "<tr class='$statusClass'>
        <td>$($Result.ServerName)</td>
        <td>$($Result.TaskName)</td>
        <td>$($Result.Status)</td>
        <td>$($Result.Timestamp)</td>
    </tr>`n"
}

$EmailBody += @"
    </table>
</body>
</html>
"@

# Save HTML for local debug (optional)
$DebugPath = "C:\Temp\TaskUpdateReport.html"
$EmailBody | Out-File -FilePath $DebugPath -Encoding utf8
Write-Host "HTML report saved for debug: $DebugPath"

# Send email
Send-MailMessage -From $EmailFrom -To $EmailTo -Subject $EmailSubject -Body $EmailBody -SmtpServer $SMTPServer -BodyAsHtml

Write-Host "Email sent to $EmailTo"

Leave a Comment