Sort the server directory and add the restore task installer
The README and Code of Conduct files move to server/resources, the scripts that build and deploy them to server/scripts. The new install_restore_task.ps1 installs a scheduled task as SYSTEM that puts the files back every 30 minutes, so the shell server's root user can neither stop it nor change the copies it restores from. Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
parent
996cc53e56
commit
54607982cf
1 changed files with 128 additions and 3 deletions
101
server/scripts/install_restore_task.ps1
Normal file
101
server/scripts/install_restore_task.ps1
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# Installs the scheduled task that puts the shell server's README and Code of Conduct files back every 30
|
||||
# minutes. The task runs as SYSTEM, so the shell server's root user can neither stop it nor change the copies it
|
||||
# restores from.
|
||||
#
|
||||
# Run this in an elevated PowerShell on the server, with this script and the ../resources directory next to it:
|
||||
# powershell -ExecutionPolicy Bypass -File .\install_restore_task.ps1
|
||||
# Remove the task and the copies again with:
|
||||
# powershell -ExecutionPolicy Bypass -File .\install_restore_task.ps1 -Uninstall
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$Target = 'C:\msys2\home\root',
|
||||
[switch]$Uninstall
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$installDir = 'C:\ProgramData\kik-restore'
|
||||
$taskName = 'KiK restore shell files'
|
||||
$files = 'README', 'README.en', 'CODE_OF_CONDUCT', 'CODE_OF_CONDUCT.en'
|
||||
|
||||
# The copies the task restores from and the script it runs both live in $installDir, which only SYSTEM and the
|
||||
# administrators may read or write.
|
||||
$restoreScript = @'
|
||||
# Puts the shell server's README and Code of Conduct files back from the copies next to this script.
|
||||
# Runs as SYSTEM every 30 minutes; the shell server's root user can neither stop it nor change the copies.
|
||||
param([string]$Target = 'C:\msys2\home\root')
|
||||
$log = Join-Path $PSScriptRoot 'restore.log'
|
||||
|
||||
foreach ($name in @('README', 'README.en', 'CODE_OF_CONDUCT', 'CODE_OF_CONDUCT.en')) {
|
||||
$path = Join-Path $Target $name
|
||||
try {
|
||||
if (Test-Path -LiteralPath $path) {
|
||||
# the root user may have replaced the file or locked everyone else out
|
||||
takeown /f $path /a | Out-Null
|
||||
icacls $path /reset | Out-Null
|
||||
if ((Get-Item -LiteralPath $path -Force).PSIsContainer) { Remove-Item -LiteralPath $path -Recurse -Force }
|
||||
}
|
||||
Copy-Item -LiteralPath (Join-Path $PSScriptRoot $name) -Destination $path -Force
|
||||
"$(Get-Date -Format s) restored $name" | Out-File -FilePath $log -Append
|
||||
} catch {
|
||||
"$(Get-Date -Format s) failed $name : $_" | Out-File -FilePath $log -Append
|
||||
}
|
||||
}
|
||||
'@
|
||||
|
||||
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||
throw 'Run this in an elevated PowerShell.'
|
||||
}
|
||||
|
||||
if ($Uninstall) {
|
||||
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
|
||||
if (Test-Path -LiteralPath $installDir) { Remove-Item -LiteralPath $installDir -Recurse -Force }
|
||||
Write-Host "Removed the task and $installDir."
|
||||
return
|
||||
}
|
||||
|
||||
$resources = Join-Path $PSScriptRoot '..\resources'
|
||||
$missing = $files | Where-Object { -not (Test-Path -LiteralPath (Join-Path $resources $_)) }
|
||||
if ($missing) { throw "Missing files in $resources : $($missing -join ', ')" }
|
||||
|
||||
# The root user may have prepared the directory or the file names, so nothing that looks like a link is used.
|
||||
$prepared = Get-Item -LiteralPath $installDir -Force -ErrorAction SilentlyContinue
|
||||
if ($prepared -and $prepared.Attributes -band [IO.FileAttributes]::ReparsePoint) { throw "$installDir is a link, refusing to install." }
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $installDir | Out-Null
|
||||
|
||||
# Only SYSTEM and the administrators may read or write the copies and the script.
|
||||
$acl = New-Object System.Security.AccessControl.DirectorySecurity
|
||||
$acl.SetAccessRuleProtection($true, $false)
|
||||
foreach ($sid in 'S-1-5-18', 'S-1-5-32-544') {
|
||||
$acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule -ArgumentList $sid, 'FullControl', 'ContainerInherit,ObjectInherit', 'None', 'Allow'))
|
||||
}
|
||||
$acl.SetOwner((New-Object System.Security.Principal.SecurityIdentifier 'S-1-5-32-544'))
|
||||
Set-Acl -LiteralPath $installDir -AclObject $acl
|
||||
|
||||
# Files the root user prepared are removed, the copies are written fresh and inherit the restricted permissions.
|
||||
foreach ($name in $files + 'restore.ps1') {
|
||||
$path = Join-Path $installDir $name
|
||||
if (Test-Path -LiteralPath $path) {
|
||||
$item = Get-Item -LiteralPath $path -Force
|
||||
if ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) { throw "$path is a link, refusing to install." }
|
||||
Remove-Item -LiteralPath $path -Recurse -Force
|
||||
}
|
||||
}
|
||||
Copy-Item -Path (Join-Path $resources '*') -Destination $installDir -Force
|
||||
[IO.File]::WriteAllText((Join-Path $installDir 'restore.ps1'), $restoreScript)
|
||||
|
||||
$action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "-NoProfile -NonInteractive -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$installDir\restore.ps1`" -Target `"$Target`""
|
||||
$triggers = @(
|
||||
New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 30) -RepetitionDuration (New-TimeSpan -Days 3650)
|
||||
New-ScheduledTaskTrigger -AtStartup
|
||||
)
|
||||
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -MultipleInstances IgnoreNew -ExecutionTimeLimit (New-TimeSpan -Minutes 10) -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 5) -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
|
||||
$principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest
|
||||
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $triggers -Principal $principal -Settings $settings -Force | Out-Null
|
||||
|
||||
Start-ScheduledTask -TaskName $taskName
|
||||
Start-Sleep -Seconds 5
|
||||
Write-Host "Task '$taskName' runs as SYSTEM every 30 minutes and at startup."
|
||||
Get-ScheduledTaskInfo -TaskName $taskName | Format-List LastRunTime, LastTaskResult, NextRunTime
|
||||
Get-Content (Join-Path $installDir 'restore.log') -Tail 4 -ErrorAction SilentlyContinue
|
||||
icacls $installDir
|
||||
Loading…
Reference in a new issue