[CmdletBinding(SupportsShouldProcess = $true)] param( [Parameter(Mandatory = $true)][string]$PythonPath, [Parameter(Mandatory = $true)][string]$BackupDirectory, [string]$ProjectRoot, [string]$Container = 'ys-mysql-dev', [string]$Database = 'payroll', [switch]$Apply ) $ErrorActionPreference = 'Stop' if (-not $ProjectRoot) { $ProjectRoot = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent } $project = [IO.Path]::GetFullPath($ProjectRoot) $python = [IO.Path]::GetFullPath($PythonPath) $backups = [IO.Path]::GetFullPath($BackupDirectory) $script = Join-Path $project 'scripts\payroll_backup.py' if (-not (Test-Path -LiteralPath $python -PathType Leaf) -or -not (Test-Path -LiteralPath $script -PathType Leaf)) { throw 'Python 或备份程序不存在。' } if ($Container -notmatch '^[A-Za-z0-9_.-]+$' -or $Database -notmatch '^[A-Za-z][A-Za-z0-9_]{0,63}$') { throw '容器或数据库标识无效。' } if (@($python, $script, $backups) | Where-Object { $_.Contains('"') }) { throw '路径不能含双引号。' } $taskPath = '\PayrollManagementSystem-Backup\' $common = ' --directory "' + $backups + '" --container ' + $Container + ' --database ' + $Database $definitions = @( @{ Name = 'DailyFull'; Action = 'full'; Time = '02:30' }, @{ Name = 'ChangedIncremental'; Action = 'incremental'; Time = '00:10' }, @{ Name = 'BackupCheck'; Action = 'check'; Time = '07:30' } ) foreach ($definition in $definitions) { $arguments = '"' + $script + '" ' + $definition.Action + $common [pscustomobject]@{ TaskPath = $taskPath; Name = $definition.Name; Python = $python; Arguments = $arguments; Enabled = [bool]$Apply } if (-not $Apply) { continue } $existing = Get-ScheduledTask -TaskPath $taskPath -TaskName $definition.Name -ErrorAction SilentlyContinue if ($existing -and (@($existing.Actions).Count -ne 1 -or $existing.Actions[0].Execute -ne $python -or $existing.Actions[0].Arguments -ne $arguments)) { throw '同名任务已有不同动作,拒绝覆盖。' } if ($PSCmdlet.ShouldProcess($definition.Name, '注册当前用户本地开发备份任务')) { $scheduler = New-Object -ComObject 'Schedule.Service' $scheduler.Connect() try { $null = $scheduler.GetFolder($taskPath) } catch { $null = $scheduler.GetFolder('\').CreateFolder('PayrollManagementSystem-Backup') } $action = New-ScheduledTaskAction -Execute $python -Argument $arguments -WorkingDirectory $project $trigger = if ($definition.Action -eq 'incremental') { New-ScheduledTaskTrigger -Once -At ((Get-Date).Date.AddMinutes(10)) -RepetitionInterval (New-TimeSpan -Minutes 15) } else { New-ScheduledTaskTrigger -Daily -At $definition.Time } $principal = New-ScheduledTaskPrincipal -UserId ([Security.Principal.WindowsIdentity]::GetCurrent().Name) -LogonType Interactive -RunLevel Limited $settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -MultipleInstances IgnoreNew -RestartCount 2 -RestartInterval (New-TimeSpan -Minutes 5) Register-ScheduledTask -TaskPath $taskPath -TaskName $definition.Name -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force | Out-Null } }