Files

70 lines
3.8 KiB
PowerShell

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
function Get-XtrhJava {
param([string]$JavaHome)
if (-not $JavaHome) { $JavaHome = $env:JAVA_HOME }
if ($JavaHome) {
$candidate = Join-Path $JavaHome 'bin/java.exe'
if (Test-Path -LiteralPath $candidate) { return (Resolve-Path -LiteralPath $candidate).Path }
throw 'JAVA_HOME 中没有找到 bin/java.exe。'
}
$command = Get-Command java.exe -ErrorAction SilentlyContinue
if ($command) { return $command.Source }
throw '请先安装 Java 17 或更新版本,并设置 JAVA_HOME。'
}
function Protect-XtrhPrivateFile {
param([Parameter(Mandatory)][string]$Path)
# 私有凭证只允许当前部署用户、SYSTEM 和本机管理员读取,避免共享目录泄露。
# 读取现有对象后仅修改访问规则;不改所有者和审计规则,普通部署用户也可执行。
$access = New-Object System.Security.AccessControl.FileSecurity($Path, [System.Security.AccessControl.AccessControlSections]::Access)
$access.SetAccessRuleProtection($true, $false)
foreach ($rule in $access.GetAccessRules($true, $false, [System.Security.Principal.SecurityIdentifier])) {
[void]$access.RemoveAccessRuleSpecific($rule)
}
$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent().User
foreach ($sid in @($identity, (New-Object System.Security.Principal.SecurityIdentifier('S-1-5-18')), (New-Object System.Security.Principal.SecurityIdentifier('S-1-5-32-544')))) {
$access.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule($sid, 'FullControl', 'Allow')))
}
$file = Get-Item -LiteralPath $Path
if ($file.PSObject.Methods['SetAccessControl']) { $file.SetAccessControl($access) }
else { [System.IO.FileSystemAclExtensions]::SetAccessControl($file, $access) }
}
function Write-XtrhText {
param([Parameter(Mandatory)][string]$Path, [Parameter(Mandatory)][string]$Content)
[System.IO.File]::WriteAllText($Path, $Content, (New-Object System.Text.UTF8Encoding($false)))
}
function ConvertTo-XtrhPropertyValue {
param([Parameter(Mandatory)][string]$Value)
# Java properties 的字符编码可能因加载器不同而变化,中文节点名用 Unicode 转义保存。
$builder = New-Object System.Text.StringBuilder
foreach ($character in $Value.ToCharArray()) {
if ([int]$character -gt 127) { [void]$builder.Append(('\u{0:x4}' -f [int]$character)) }
elseif ($character -eq '\') { [void]$builder.Append('\\') }
else { [void]$builder.Append($character) }
}
return $builder.ToString()
}
function Get-XtrhOwnedProcess {
param([Parameter(Mandatory)][string]$InstallRoot, [Parameter(Mandatory)]$Record)
$process = Get-Process -Id ([int]$Record.pid) -ErrorAction SilentlyContinue
if (-not $process) { return $null }
$live = Get-CimInstance Win32_Process -Filter ('ProcessId=' + [int]$Record.pid)
$expectedJar = [System.IO.Path]::GetFullPath((Join-Path $InstallRoot 'xtrh-services.jar'))
$javaPath = [System.IO.Path]::GetFullPath([string]$Record.javaPath)
# PID 会被操作系统复用;同时校验启动时间、Java 路径和 -jar 参数才能结束进程。
if (-not $live -or $process.StartTime.ToUniversalTime().Ticks -ne [long]$Record.startTicks -or
[System.IO.Path]::GetFullPath([string]$live.ExecutablePath) -ne $javaPath) {
throw '进程身份不匹配;已拒绝结束该 PID。'
}
$match = [regex]::Match([string]$live.CommandLine, '(?i)(?:^|\s)-jar\s+(?:"(?<jar>[^"]+)"|(?<jar>\S+))')
if (-not $match.Success -or [System.IO.Path]::GetFullPath($match.Groups['jar'].Value) -ne $expectedJar) {
throw '进程启动文件与本部署目录不一致;已拒绝结束该 PID。'
}
return $process
}