PayrollManagementSystem/scripts/windows/Install-PayrollTasks.ps1
liuwenxin 108bf87225 feat(核算)!: 添加 T+ 正式核算与采集托管
补齐源快照、资料预演、正式导入及工资核算的依赖链路。
新增版本化输入、逐段 FIFO、生成锁和结构化当月调整,
并提供默认关闭的周期采集、有限重试及 Windows 托管。

原始客户资料、私有配置及首页改动不纳入本次提交。

BREAKING CHANGE: 升级前需应用新增迁移,并通过
PAYROLL_MAKER_USER_ID 绑定实际工资制作人,否则业务只读。
旧单批次核算默认关闭;历史兼容需显式启用
PAYROLL_ALLOW_LEGACY_CALCULATION。生产启用和真实金额待验收。
2026-11-02 09:42:53 +08:00

67 lines
4.0 KiB
PowerShell
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[CmdletBinding(SupportsShouldProcess = $true)]
param(
[Parameter(Mandatory = $true)][string]$ProjectRoot,
[Parameter(Mandatory = $true)][string]$PythonPath,
[Parameter(Mandatory = $true)][string]$RuntimeDirectory,
[Parameter(Mandatory = $true)][string]$ConnectionFile,
[string]$TaskPath = '\PayrollManagementSystem\',
[string]$ServiceAccount,
[int]$ApiPort = 8000,
[switch]$Apply,
[switch]$TestMode
)
. (Join-Path $PSScriptRoot 'TaskHost.Common.ps1')
$plan = Get-PayrollTaskPlan -ProjectRoot $ProjectRoot -PythonPath $PythonPath -RuntimeDirectory $RuntimeDirectory `
-ConnectionFile $ConnectionFile -TaskPath $TaskPath -ApiPort $ApiPort
if ($TestMode -and $TaskPath -notmatch '-Test-[0-9a-f]{8}\\$') { throw '测试模式必须使用独立测试任务目录。' }
if (-not $Apply -or -not $PSCmdlet.ShouldProcess($TaskPath, '注册默认禁用的三个项目托管任务')) {
$plan | ConvertTo-Json -Depth 5
return
}
foreach ($task in $plan.Tasks) {
if (Get-ScheduledTask -TaskPath $TaskPath -TaskName $task.Name -ErrorAction SilentlyContinue) { throw '任务已存在,拒绝覆盖;请先核对当前安装。' }
}
if ($TestMode) {
$account = [Security.Principal.WindowsIdentity]::GetCurrent().Name
$principal = New-ScheduledTaskPrincipal -UserId $account -LogonType Interactive -RunLevel Limited
$credential = $null
} else {
Assert-TaskValue $ServiceAccount
if ($ServiceAccount -match '^(SYSTEM|LocalSystem|NT AUTHORITY\\SYSTEM)$') { throw '请使用已有受限服务账号,不使用SYSTEM。' }
$credential = Get-Credential -UserName $ServiceAccount -Message '请输入已有受限服务账号的凭据(不会写入命令行或清单)'
if ($null -eq $credential) { throw '未提供服务账号凭据,未注册任务。' }
$account = $credential.UserName
$principal = New-ScheduledTaskPrincipal -UserId $account -LogonType Password -RunLevel Limited
}
$serviceSid = Resolve-PayrollAccountSid $account
if ($serviceSid -eq 'S-1-5-18') { throw '请使用已有受限服务账号,不使用SYSTEM。' }
$plan | Add-Member -NotePropertyName ServiceSid -NotePropertyValue $serviceSid
$plan | Add-Member -NotePropertyName LogonType -NotePropertyValue ([string]$principal.LogonType)
Assert-PayrollHostAccess -Plan $plan -ServiceSid $serviceSid
if (Test-Path -LiteralPath (Join-Path $plan.RuntimeDirectory 'task-manifest.json')) { throw '运行目录已有安装清单,拒绝覆盖。' }
'任务已安装但未启用' | Set-Content -LiteralPath $plan.StopFile -Encoding UTF8
$registered = @()
try {
foreach ($task in $plan.Tasks) {
$action = New-ScheduledTaskAction -Execute $task.Execute -Argument $task.Arguments -WorkingDirectory $task.WorkingDirectory
$triggers = @(New-ScheduledTaskTrigger -AtStartup)
if ($task.Role -eq 'maintenance') {
$triggers += New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1) -RepetitionInterval (New-TimeSpan -Minutes 1)
}
$definition = New-ScheduledTask -Action $action -Trigger $triggers -Settings (Get-PayrollTaskSettings) -Principal $principal
if ($TestMode) {
Register-ScheduledTask -TaskPath $TaskPath -TaskName $task.Name -InputObject $definition | Out-Null
} else {
$secretPassword = $credential.GetNetworkCredential().Password
try { Register-ScheduledTask -TaskPath $TaskPath -TaskName $task.Name -InputObject $definition -User $account -Password $secretPassword | Out-Null }
finally { $secretPassword = $null }
}
$registered += $task.Name
}
$plan | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $plan.RuntimeDirectory 'task-manifest.json') -Encoding UTF8
Write-Output '三个任务已注册且默认禁用;检查配置后显式执行Start。自动采集开关仍由应用配置控制。'
} catch {
Write-Error ('安装未完成,已注册的任务保持禁用:' + ($registered -join ', ') + '。请核对项目任务目录。')
throw
}