Files
kanhole/packaging/windows/install.ps1
T
kannn 2cd3052da1
golangci-lint / lint (push) Failing after 1m5s
rebrand: frp -> kanhole (kanhole server, kanholec client)
2026-05-29 09:05:34 +00:00

310 lines
11 KiB
PowerShell

<#
.SYNOPSIS
kanholec Windows Setup Wizard (Interactive PowerShell Installer)
.DESCRIPTION
Interactive installer for kanholec with EULA acceptance, directory selection,
and optional features (PATH, shortcuts, desktop icon).
.PARAMETER Unattended
Run in silent mode with defaults.
.PARAMETER InstallDir
Installation directory (default: $env:ProgramFiles\kanholec).
.EXAMPLE
.\install.ps1
.\install.ps1 -Unattended
#>
param(
[switch]$Unattended,
[string]$InstallDir = "$env:ProgramFiles\kanholec"
)
$ErrorActionPreference = "Stop"
$host.UI.RawUI.WindowTitle = "kanholec Setup Wizard"
$env:KANHOLEC_VERSION = "0.62.0"
function Write-Banner {
Clear-Host
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " kanholec - kanhole Client v$env:KANHOLEC_VERSION" -ForegroundColor Cyan
Write-Host " Setup Wizard" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
}
function Show-License {
param([string]$Path)
Write-Banner
Write-Host "License Agreement" -ForegroundColor Yellow
Write-Host "==================" -ForegroundColor Yellow
Write-Host ""
if (Test-Path $Path) {
Get-Content $Path | ForEach-Object { Write-Host $_ }
} else {
Write-Host "kanholec is licensed under the Apache License, Version 2.0."
Write-Host "See http://www.apache.org/licenses/LICENSE-2.0"
}
Write-Host ""
if (-not $Unattended) {
$choice = $host.UI.PromptForChoice(
"License Agreement",
"Do you accept the terms?",
[System.Management.Automation.Host.ChoiceDescription[]]@(
@{Label="&Agree"; Help="I accept the agreement"},
@{Label="&Decline"; Help="I do not accept the agreement"}
),
1
)
if ($choice -ne 0) {
Write-Host "Setup cancelled. You must accept the license to install." -ForegroundColor Red
exit 1
}
}
}
function Select-Directory {
param([string]$DefaultPath)
Write-Banner
Write-Host "Installation Directory" -ForegroundColor Yellow
Write-Host "======================" -ForegroundColor Yellow
Write-Host ""
Write-Host "Default: $DefaultPath" -ForegroundColor Gray
Write-Host ""
if (-not $Unattended) {
$input = Read-Host "Press Enter to accept, or type a custom path"
if ($input -ne "") {
return $input
}
}
return $DefaultPath
}
function Select-Components {
Write-Banner
Write-Host "Select Components" -ForegroundColor Yellow
Write-Host "=================" -ForegroundColor Yellow
Write-Host ""
$components = @{
"Main" = @{Desc="kanholec binary and config"; Default=$true}
"Path" = @{Desc="Add to system PATH"; Default=$true}
"StartMenu" = @{Desc="Start Menu shortcuts"; Default=$true}
"Desktop" = @{Desc="Desktop shortcut"; Default=$false}
}
$selected = @{}
$i = 1
$choices = @()
foreach ($key in $components.Keys) {
$c = $components[$key]
$default = if ($c.Default) { "Y" } else { "N" }
$displayDefault = if ($c.Default) { "Yes" } else { "No" }
Write-Host " $i. $($c.Desc) [$displayDefault]" -ForegroundColor Gray
$choices += @{Key=$key; Default=$default}
$i++
}
Write-Host ""
if (-not $Unattended) {
Write-Host "Press Enter for defaults, or type numbers to toggle (e.g. 1,3):" -ForegroundColor Yellow
$input = Read-Host
if ($input -ne "") {
$toggleIndices = $input -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne "" }
for ($j = 0; $j -lt $choices.Count; $j++) {
$idx = $j + 1
$isToggled = [string]$idx -in $toggleIndices
$c = $components[$choices[$j].Key]
$default = $c.Default
$selected[$choices[$j].Key] = if ($isToggled) { -not $default } else { $default }
}
} else {
foreach ($ch in $choices) { $selected[$ch.Key] = $components[$ch.Key].Default }
}
} else {
foreach ($ch in $choices) { $selected[$ch.Key] = $components[$ch.Key].Default }
}
Write-Host ""
Write-Host "Selected components:" -ForegroundColor Green
foreach ($key in $selected.Keys) {
$mark = if ($selected[$key]) { "[X]" } else { "[ ]" }
Write-Host " $mark $($components[$key].Desc)" -ForegroundColor $(if ($selected[$key]) { "Green" } else { "DarkGray" })
}
Start-Sleep 1
return $selected
}
function Install-Frpc {
param(
[string]$InstallDir,
[hashtable]$Components,
[string]$BinarySource
)
Write-Banner
Write-Host "Installing kanholec..." -ForegroundColor Yellow
Write-Host "==================" -ForegroundColor Yellow
Write-Host ""
# Create directories
Write-Host " Creating directories..." -NoNewline
New-Item -Path $InstallDir -ItemType Directory -Force | Out-Null
$configDir = "$env:ProgramData\kanholec"
New-Item -Path $configDir -ItemType Directory -Force | Out-Null
Write-Host " OK" -ForegroundColor Green
# Copy binary
Write-Host " Copying kanholec.exe..." -NoNewline
if ($BinarySource -and (Test-Path $BinarySource)) {
Copy-Item -Path $BinarySource -Destination "$InstallDir\kanholec.exe" -Force
} else {
# Download from GitHub
$url = "https://github.com/fatedier/kanhole/releases/download/v$env:KANHOLEC_VERSION/kanhole_${env:KANHOLEC_VERSION}_windows_amd64.zip"
$zipPath = "$env:TEMP\kanholec.zip"
Write-Host ""
Write-Host " Downloading from GitHub..." -NoNewline
Invoke-WebRequest -Uri $url -OutFile $zipPath -UseBasicParsing
Expand-Archive -Path $zipPath -DestinationPath "$env:TEMP\kanholec" -Force
$exePath = Get-ChildItem -Path "$env:TEMP\kanholec" -Recurse -Filter "kanholec.exe" | Select-Object -First 1 -ExpandProperty FullName
if (-not $exePath) { throw "kanholec.exe not found in archive" }
Copy-Item -Path $exePath -Destination "$InstallDir\kanholec.exe" -Force
}
Write-Host " OK" -ForegroundColor Green
# Config file
Write-Host " Creating config..." -NoNewline
$configFile = "$configDir\kanholec.toml"
if (-not (Test-Path $configFile)) {
@"
# kanholec configuration
# Edit this file to configure your kanhole client.
serverAddr = "127.0.0.1"
serverPort = 7000
auth.token = ""
"@ | Out-File -FilePath $configFile -Encoding utf8
}
Write-Host " OK" -ForegroundColor Green
# PATH
if ($Components["Path"]) {
Write-Host " Adding to PATH..." -NoNewline
$currentPath = [Environment]::GetEnvironmentVariable("PATH", "Machine")
if ($currentPath -notlike "*$InstallDir*") {
$newPath = "$currentPath;$InstallDir"
[Environment]::SetEnvironmentVariable("PATH", $newPath, "Machine")
$env:PATH = "$env:PATH;$InstallDir"
}
Write-Host " OK" -ForegroundColor Green
}
# Start Menu
if ($Components["StartMenu"]) {
Write-Host " Creating Start Menu shortcuts..." -NoNewline
$startMenu = "$([Environment]::GetFolderPath('CommonStartMenu'))\Programs\kanholec"
New-Item -Path $startMenu -ItemType Directory -Force | Out-Null
$wshell = New-Object -ComObject WScript.Shell
$shortcut = $wshell.CreateShortcut("$startMenu\kanholec.lnk")
$shortcut.TargetPath = "$InstallDir\kanholec.exe"
$shortcut.Save()
$unlink = $wshell.CreateShortcut("$startMenu\Uninstall kanholec.lnk")
$unlink.TargetPath = "$InstallDir\uninstall.ps1"
$unlink.Save()
Write-Host " OK" -ForegroundColor Green
}
# Desktop
if ($Components["Desktop"]) {
Write-Host " Creating desktop shortcut..." -NoNewline
$desktop = [Environment]::GetFolderPath('Desktop')
$wshell = New-Object -ComObject WScript.Shell
$shortcut = $wshell.CreateShortcut("$desktop\kanholec.lnk")
$shortcut.TargetPath = "$InstallDir\kanholec.exe"
$shortcut.Save()
Write-Host " OK" -ForegroundColor Green
}
# Write uninstall script
Write-Host " Creating uninstaller..." -NoNewline
@"
param([switch]`$Silent)
`$InstallDir = "$InstallDir"
if (-not `$Silent) {
`$choice = `$host.UI.PromptForChoice("Uninstall kanholec", "Remove kanholec from this computer?", @(@{Label="&Yes"; Help=""}, @{Label="&No"; Help=""}), 1)
if (`$choice -ne 0) { exit }
}
# Remove files
Remove-Item -Path "`$InstallDir\kanholec.exe" -Force -ErrorAction SilentlyContinue
Remove-Item -Path "`$InstallDir\uninstall.ps1" -Force -ErrorAction SilentlyContinue
Remove-Item -Path "`$InstallDir" -Force -ErrorAction SilentlyContinue
# Remove shortcuts
Remove-Item -Path "$([Environment]::GetFolderPath('CommonStartMenu'))\Programs\kanholec" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "$([Environment]::GetFolderPath('Desktop'))\kanholec.lnk" -Force -ErrorAction SilentlyContinue
Write-Host "kanholec has been uninstalled."
"@ | Out-File -FilePath "$InstallDir\uninstall.ps1" -Encoding utf8
Write-Host " OK" -ForegroundColor Green
Write-Host ""
Write-Host "Installation complete!" -ForegroundColor Green
Write-Host ""
Write-Host "Quick start:" -ForegroundColor Yellow
Write-Host " kanholec --help"
Write-Host " kanholec --server-config http://your-server:7500/admin/api/kanholec/proxy-config/YOUR_KEY"
Write-Host " kanholec -c $configFile"
Write-Host ""
Write-Host "Auth with provisioning token:" -ForegroundColor Yellow
Write-Host " kanholec auth login --server http://your-server:7500 --client-name myclient"
Write-Host ""
}
# ===== Main =====
$scriptDir = Split-Path -Parent $PSCommandPath
$binarySource = Join-Path $scriptDir "..\bin\kanholec-windows-amd64.exe"
if (-not (Test-Path $binarySource)) {
$binarySource = Join-Path $scriptDir "kanholec-windows-amd64.exe"
}
if (-not (Test-Path $binarySource)) {
$binarySource = $null
}
# Check admin rights
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Host "This installer requires administrator privileges." -ForegroundColor Red
Write-Host "Please run PowerShell as Administrator and try again." -ForegroundColor Yellow
if (-not $Unattended) {
Start-Sleep 2
# Self-elevate
$script = "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`""
Start-Process powershell -Verb RunAs -ArgumentList $script
}
exit 1
}
if ($Unattended) {
Install-Frpc -InstallDir $InstallDir -Components @{
Main=$true; Path=$true; StartMenu=$true; Desktop=$false
} -BinarySource $binarySource
} else {
Show-License -Path (Join-Path $scriptDir "license.txt")
$dir = Select-Directory -DefaultPath $InstallDir
$components = Select-Components
Install-Frpc -InstallDir $dir -Components $components -BinarySource $binarySource
Write-Host ""
$runNow = $host.UI.PromptForChoice(
"Setup Complete",
"Run kanholec now?",
[System.Management.Automation.Host.ChoiceDescription[]]@(
@{Label="&Yes"; Help="Run kanholec"},
@{Label="&No"; Help="Close"}
),
0
)
if ($runNow -eq 0) {
Start-Process "$dir\kanholec.exe"
}
}