# ========================================================= # MAX Windows Toolkit - 定时任务管理 # ========================================================= $Common = "C:\Setup\windows\lib\common.ps1" if (Test-Path $Common) { . $Common } else { function Write-Header { param([string]$Title) Clear-Host; Write-Host "==== $Title ====" -ForegroundColor Green } function Write-OK { Write-Host " OK $($args[0])" -ForegroundColor Green } function Write-Warn { Write-Host " !! $($args[0])" -ForegroundColor Yellow } function Write-Err { Write-Host " XX $($args[0])" -ForegroundColor Red } function Write-Info { Write-Host " $($args[0])" -ForegroundColor White } function Write-Muted { Write-Host " $($args[0])" -ForegroundColor DarkGray } function Pause-Max { Write-Host ""; Read-Host "按 Enter 返回..." } function Write-Line { Write-Host "------------------------------" -ForegroundColor DarkGray } function Write-Section { param([string]$Text) Write-Host ""; Write-Host "-- $Text --" -ForegroundColor Magenta } function Test-IsAdmin { try { $id = [Security.Principal.WindowsIdentity]::GetCurrent(); $p = New-Object Security.Principal.WindowsPrincipal($id); return $p.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } catch { return $false } } function Show-AdminWarn { if (-not (Test-IsAdmin)) { Write-Warn "未以管理员身份运行,部分功能可能失败" } } } Show-AdminWarn $ErrorActionPreference = "Continue" function Normalize-TaskPath { param([string]$TaskPath) if ([string]::IsNullOrWhiteSpace($TaskPath)) { return "\" } if (-not $TaskPath.StartsWith("\")) { $TaskPath = "\$TaskPath" } if (-not $TaskPath.EndsWith("\")) { $TaskPath = "$TaskPath\" } return $TaskPath } function Show-TaskList { param([switch]$OnlyEnabled) Write-Section "计划任务列表" try { $tasks = Get-ScheduledTask -ErrorAction Stop if ($OnlyEnabled) { $tasks = $tasks | Where-Object { $_.State -ne "Disabled" } } $rows = $tasks | Sort-Object TaskPath, TaskName | ForEach-Object { [PSCustomObject]@{ State = $_.State TaskPath = $_.TaskPath TaskName = $_.TaskName } } $rows | Format-Table State, TaskPath, TaskName -AutoSize Write-OK "共 $($rows.Count) 个任务" } catch { Write-Err "读取计划任务失败:$($_.Exception.Message)" } } function Select-Task { $taskName = Read-Host " 请输入任务名称 TaskName" if ([string]::IsNullOrWhiteSpace($taskName)) { Write-Err "任务名称不能为空" return $null } $taskPath = Read-Host " 请输入任务路径 TaskPath,留空则自动查找" try { if ([string]::IsNullOrWhiteSpace($taskPath)) { $matches = @(Get-ScheduledTask -TaskName $taskName -ErrorAction Stop) if ($matches.Count -eq 1) { return $matches[0] } if ($matches.Count -gt 1) { Write-Warn "发现多个同名任务:" for ($i = 0; $i -lt $matches.Count; $i++) { Write-Info "$($i + 1). $($matches[$i].TaskPath)$($matches[$i].TaskName)" } $choice = Read-Host " 请选择编号" if ($choice -match "^\d+$") { $index = [int]$choice - 1 if ($index -ge 0 -and $index -lt $matches.Count) { return $matches[$index] } } } } else { $normalizedPath = Normalize-TaskPath -TaskPath $taskPath return Get-ScheduledTask -TaskName $taskName -TaskPath $normalizedPath -ErrorAction Stop } } catch { Write-Err "未找到任务:$taskName" } return $null } function Show-TaskDetail { $task = Select-Task if (-not $task) { return } try { $info = Get-ScheduledTaskInfo -TaskName $task.TaskName -TaskPath $task.TaskPath -ErrorAction SilentlyContinue Write-Section "任务详情" Write-Info "路径:$($task.TaskPath)" Write-Info "名称:$($task.TaskName)" Write-Info "状态:$($task.State)" Write-Info "描述:$($task.Description)" if ($info) { Write-Info "上次运行:$($info.LastRunTime)" Write-Info "上次结果:$($info.LastTaskResult)" Write-Info "下次运行:$($info.NextRunTime)" } Write-Section "执行动作" foreach ($action in $task.Actions) { Write-Info "程序:$($action.Execute)" Write-Info "参数:$($action.Arguments)" Write-Info "目录:$($action.WorkingDirectory)" } } catch { Write-Err "读取任务详情失败:$($_.Exception.Message)" } } function Convert-DayInput { param([string]$Text) $map = @{ "1" = "Monday" "2" = "Tuesday" "3" = "Wednesday" "4" = "Thursday" "5" = "Friday" "6" = "Saturday" "7" = "Sunday" "周一" = "Monday" "周二" = "Tuesday" "周三" = "Wednesday" "周四" = "Thursday" "周五" = "Friday" "周六" = "Saturday" "周日" = "Sunday" "周天" = "Sunday" "Monday" = "Monday" "Tuesday" = "Tuesday" "Wednesday" = "Wednesday" "Thursday" = "Thursday" "Friday" = "Friday" "Saturday" = "Saturday" "Sunday" = "Sunday" } $days = @() foreach ($part in ($Text -split ",")) { $key = $part.Trim() if ($map.ContainsKey($key)) { $days += $map[$key] } } return @($days | Sort-Object -Unique) } function New-CustomScheduledTask { if (-not (Test-IsAdmin)) { Write-Warn "提示:创建高权限计划任务建议使用管理员权限运行" } $taskName = Read-Host " 任务名称" if ([string]::IsNullOrWhiteSpace($taskName)) { Write-Err "任务名称不能为空" return } $taskPath = Read-Host " 任务路径,留空为根目录,例如 \UNV\" $taskPath = Normalize-TaskPath -TaskPath $taskPath $program = Read-Host " 执行程序或脚本路径,例如 C:\Scripts\backup.ps1" if ([string]::IsNullOrWhiteSpace($program)) { Write-Err "执行路径不能为空" return } $extraArgs = Read-Host " 附加参数,留空则无" if ($program.ToLower().EndsWith(".ps1")) { $execute = "powershell.exe" $argument = "-ExecutionPolicy Bypass -NoProfile -File `"$program`"" if (-not [string]::IsNullOrWhiteSpace($extraArgs)) { $argument = "$argument $extraArgs" } } else { $execute = $program $argument = $extraArgs } Write-Section "触发类型" Write-Info "1. 每天" Write-Info "2. 每周" Write-Info "3. 用户登录时" Write-Info "4. 系统启动时" $triggerChoice = Read-Host " 请选择" $trigger = $null try { switch ($triggerChoice) { "1" { $time = Read-Host " 执行时间,例如 02:00" $trigger = New-ScheduledTaskTrigger -Daily -At $time } "2" { $dayText = Read-Host " 星期几,例如 1,3,5 或 周一,周三" $days = Convert-DayInput -Text $dayText if (-not $days -or $days.Count -eq 0) { Write-Err "星期输入无效" return } $time = Read-Host " 执行时间,例如 02:00" $trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek $days -At $time } "3" { $trigger = New-ScheduledTaskTrigger -AtLogOn } "4" { $trigger = New-ScheduledTaskTrigger -AtStartup } default { Write-Err "触发类型无效" return } } } catch { Write-Err "创建触发器失败:$($_.Exception.Message)" return } $description = Read-Host " 任务描述,留空则无" try { $action = New-ScheduledTaskAction -Execute $execute -Argument $argument $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable Write-Warn "即将创建任务:" Write-Info "路径:$taskPath" Write-Info "名称:$taskName" Write-Info "程序:$execute" Write-Info "参数:$argument" $confirm = Read-Host " 输入 YES 确认创建" if ($confirm -ne "YES") { Write-Warn "已取消" return } Register-ScheduledTask ` -TaskName $taskName ` -TaskPath $taskPath ` -Action $action ` -Trigger $trigger ` -Settings $settings ` -Description $description ` -RunLevel Highest ` -Force | Out-Null Write-OK "任务已创建:$taskPath$taskName" } catch { Write-Err "创建任务失败:$($_.Exception.Message)" } } function Enable-OrDisableTask { $task = Select-Task if (-not $task) { return } Write-Info "1. 启用任务" Write-Info "2. 禁用任务" $choice = Read-Host " 请选择" try { if ($choice -eq "1") { Enable-ScheduledTask -TaskName $task.TaskName -TaskPath $task.TaskPath -ErrorAction Stop | Out-Null Write-OK "已启用:$($task.TaskPath)$($task.TaskName)" } elseif ($choice -eq "2") { Disable-ScheduledTask -TaskName $task.TaskName -TaskPath $task.TaskPath -ErrorAction Stop | Out-Null Write-Warn "已禁用:$($task.TaskPath)$($task.TaskName)" } else { Write-Err "无效选项" } } catch { Write-Err "操作失败:$($_.Exception.Message)" } } function Remove-CustomScheduledTask { $task = Select-Task if (-not $task) { return } Write-Warn "即将删除任务:$($task.TaskPath)$($task.TaskName)" $confirm = Read-Host " 输入 DELETE 确认删除" if ($confirm -ne "DELETE") { Write-Warn "已取消" return } try { Unregister-ScheduledTask -TaskName $task.TaskName -TaskPath $task.TaskPath -Confirm:$false -ErrorAction Stop Write-OK "任务已删除" } catch { Write-Err "删除失败:$($_.Exception.Message)" } } function Export-TaskList { $logDir = "C:\Setup\Logs" New-Item -ItemType Directory -Path $logDir -Force | Out-Null $file = Join-Path $logDir "scheduled-tasks-$(Get-Date -Format 'yyyyMMdd-HHmmss').csv" try { $rows = Get-ScheduledTask -ErrorAction Stop | Sort-Object TaskPath, TaskName | ForEach-Object { $info = Get-ScheduledTaskInfo -TaskName $_.TaskName -TaskPath $_.TaskPath -ErrorAction SilentlyContinue [PSCustomObject]@{ TaskPath = $_.TaskPath TaskName = $_.TaskName State = $_.State LastRunTime = if ($info) { $info.LastRunTime } else { "" } LastTaskResult = if ($info) { $info.LastTaskResult } else { "" } NextRunTime = if ($info) { $info.NextRunTime } else { "" } Description = $_.Description } } $rows | Export-Csv -Path $file -Encoding UTF8 -NoTypeInformation Write-OK "已导出:$file" } catch { Write-Err "导出失败:$($_.Exception.Message)" } } :taskLoop while ($true) { Write-Header "定时任务管理" Write-Info "1. 查看所有计划任务" Write-Info "2. 查看启用中的计划任务" Write-Info "3. 查看指定任务详情" Write-Info "4. 创建新计划任务" Write-Info "5. 启用/禁用任务" Write-Info "6. 删除任务" Write-Info "7. 导出任务列表" Write-Info "0. 退出" Write-Line $choice = Read-Host " 请选择" switch ($choice) { "1" { Show-TaskList; Pause-Max } "2" { Show-TaskList -OnlyEnabled; Pause-Max } "3" { Show-TaskDetail; Pause-Max } "4" { New-CustomScheduledTask; Pause-Max } "5" { Enable-OrDisableTask; Pause-Max } "6" { Remove-CustomScheduledTask; Pause-Max } "7" { Export-TaskList; Pause-Max } "0" { break :taskLoop } default { Write-Err "无效选项"; Pause-Max } } }