Add PowerShell installation script for x-ui with configuration setup

This commit is contained in:
Taha Amin Ghafuri [T@G] 2025-01-08 23:45:00 +03:30
parent 49d3957c07
commit b596713908
2 changed files with 620 additions and 0 deletions

186
install.ps1 Normal file
View file

@ -0,0 +1,186 @@
# Color definitions for PowerShell
$colors = @{
Red = [ConsoleColor]::Red
Green = [ConsoleColor]::Green
Blue = [ConsoleColor]::Blue
Yellow = [ConsoleColor]::Yellow
}
$curDir = Get-Location
# Check admin privileges
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Host -ForegroundColor $colors.Red "Fatal error: Please run this script as Administrator"
exit 1
}
# Get system architecture
function Get-CPUArchitecture {
$arch = [System.Environment]::GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")
switch ($arch) {
"AMD64" { return "amd64" }
"x86" { return "386" }
"ARM64" { return "arm64" }
default {
Write-Host -ForegroundColor $colors.Red "Unsupported CPU architecture!"
exit 1
}
}
}
$arch = Get-CPUArchitecture
Write-Host "arch: $arch"
# Random string generator
function New-RandomString {
param([int]$length)
return -join ((65..90) + (97..122) + (48..57) | Get-Random -Count $length | ForEach-Object { [char]$_ })
}
function Install-BasePackages {
# Check if winget is available
if (Get-Command winget -ErrorAction SilentlyContinue) {
Write-Host "Installing required packages using winget..."
winget install -e --id Git.Git
winget install -e --id Microsoft.PowerShell
} else {
Write-Host -ForegroundColor $colors.Red "Please install winget package manager or install Git manually"
exit 1
}
}
function Configure-AfterInstall {
$configPath = "C:\Program Files\x-ui\config.json"
if (Test-Path $configPath) {
$config = Get-Content $configPath | ConvertFrom-Json
$existingUsername = $config.username
$existingPassword = $config.password
$existingWebBasePath = $config.webBasePath
$existingPort = $config.port
# Get public IP
$serverIP = (Invoke-WebRequest -Uri "https://api.ipify.org" -UseBasicParsing).Content
if ($existingWebBasePath.Length -lt 4) {
if ($existingUsername -eq "admin" -and $existingPassword -eq "admin") {
$configWebBasePath = New-RandomString -length 15
$configUsername = New-RandomString -length 10
$configPassword = New-RandomString -length 10
$response = Read-Host "Would you like to customize the Panel Port settings? (If not, a random port will be applied) [y/n]"
if ($response -eq "y" -or $response -eq "Y") {
$configPort = Read-Host "Please set up the panel port"
} else {
$configPort = Get-Random -Minimum 1024 -Maximum 62000
Write-Host -ForegroundColor $colors.Yellow "Generated random port: $configPort"
}
# Update config file
$config.username = $configUsername
$config.password = $configPassword
$config.port = $configPort
$config.webBasePath = $configWebBasePath
$config | ConvertTo-Json | Set-Content $configPath
Write-Host "New configuration:"
Write-Host "###############################################"
Write-Host -ForegroundColor $colors.Green "Username: $configUsername"
Write-Host -ForegroundColor $colors.Green "Password: $configPassword"
Write-Host -ForegroundColor $colors.Green "Port: $configPort"
Write-Host -ForegroundColor $colors.Green "WebBasePath: $configWebBasePath"
Write-Host -ForegroundColor $colors.Green "Access URL: http://${serverIP}:${configPort}/${configWebBasePath}"
Write-Host "###############################################"
}
}
}
}
function Install-XUI {
param([string]$version)
# Create installation directory
$installDir = "C:\Program Files\x-ui"
New-Item -ItemType Directory -Force -Path $installDir
if (-not $version) {
# Get latest release
$apiUrl = "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest"
$release = Invoke-RestMethod -Uri $apiUrl
$version = $release.tag_name
Write-Host "Got x-ui latest version: $version, beginning the installation..."
}
$downloadUrl = "https://github.com/MHSanaei/3x-ui/releases/download/${version}/x-ui-windows-${arch}.zip"
$zipFile = Join-Path $installDir "x-ui.zip"
# Download and extract
Invoke-WebRequest -Uri $downloadUrl -OutFile $zipFile
Expand-Archive -Path $zipFile -DestinationPath $installDir -Force
Remove-Item $zipFile
# Create service
$servicePath = Join-Path $installDir "x-ui-service.ps1"
@"
# Service script content
`$process = Start-Process -FilePath "C:\Program Files\x-ui\x-ui.exe" -NoNewWindow -PassThru
while (-not `$process.HasExited) {
Start-Sleep -Seconds 1
}
"@ | Set-Content $servicePath
# Register service using nssm
# Note: NSSM needs to be installed separately
if (Get-Command nssm -ErrorAction SilentlyContinue) {
nssm install x-ui powershell
nssm set x-ui Application "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
nssm set x-ui AppParameters "-ExecutionPolicy Bypass -NoProfile -File `"$servicePath`""
nssm start x-ui
} else {
Write-Host -ForegroundColor $colors.Red "NSSM is not installed. Please install it to run x-ui as a service."
}
Configure-AfterInstall
Write-Host -ForegroundColor $colors.Green "x-ui ${version} installation finished"
}
function Register-XUICommand {
# Create a directory for x-ui if it doesn't exist in Program Files
$installDir = "C:\Program Files\x-ui"
if (-not (Test-Path $installDir)) {
New-Item -ItemType Directory -Path $installDir -Force
}
# Copy x-ui.ps1 to the installation directory
Copy-Item "$PSScriptRoot\x-ui.ps1" "$installDir\x-ui.ps1" -Force
# Add the installation directory to PATH if not already present
$currentPath = [Environment]::GetEnvironmentVariable("Path", "Machine")
if ($currentPath -notlike "*$installDir*") {
[Environment]::SetEnvironmentVariable(
"Path",
"$currentPath;$installDir",
"Machine"
)
}
# Create an alias script to run x-ui.ps1 with admin privileges
$aliasScript = @"
@echo off
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File \"%ProgramFiles%\x-ui\x-ui.ps1\" %*' -Verb RunAs"
"@
Set-Content -Path "$installDir\x-ui.cmd" -Value $aliasScript -Force
Write-Host "x-ui command has been registered. You can now use 'x-ui' from any terminal with admin privileges."
}
Write-Host -ForegroundColor $colors.Green "Running..."
Install-BasePackages
Install-XUI $args[0]
# After installing x-ui, register the command
Register-XUICommand

434
x-ui.ps1 Normal file
View file

@ -0,0 +1,434 @@
# Color definitions
$colors = @{
Red = "`e[31m"
Green = "`e[32m"
Yellow = "`e[33m"
Blue = "`e[34m"
Plain = "`e[0m"
}
# Basic logging functions
function Write-Log {
param (
[string]$Level,
[string]$Message
)
$color = switch ($Level) {
"DEG" { $colors.Yellow }
"ERR" { $colors.Red }
"INF" { $colors.Green }
default { $colors.Plain }
}
Write-Host "$($color)[$Level] $Message$($colors.Plain)"
}
function LOGD { param([string]$Message) Write-Log "DEG" $Message }
function LOGE { param([string]$Message) Write-Log "ERR" $Message }
function LOGI { param([string]$Message) Write-Log "INF" $Message }
# Check admin privileges
function Test-Administrator {
$user = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($user)
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}
if (-not (Test-Administrator)) {
LOGE "ERROR: You must run this script as Administrator!"
exit 1
}
# Get Windows version information
$osInfo = Get-WmiObject Win32_OperatingSystem
$osVersion = [Version]$osInfo.Version
# Check minimum Windows version (Windows 10/Server 2016 or higher)
$minVersion = [Version]"10.0.0.0"
if ($osVersion -lt $minVersion) {
LOGE "This script requires Windows 10/Server 2016 or higher"
exit 1
}
# Variables
$scriptPath = $PSScriptRoot
$configPath = Join-Path $scriptPath "config"
$logFolder = $env:XUI_LOG_FOLDER
if (-not $logFolder) {
$logFolder = "C:\ProgramData\3x-ui\logs"
}
$iplimitLogPath = Join-Path $logFolder "3xipl.log"
$iplimitBannedLogPath = Join-Path $logFolder "3xipl-banned.log"
# Function to confirm actions
function Confirm-Action {
param (
[string]$Prompt,
[string]$DefaultChoice = "N"
)
if ($DefaultChoice) {
$prompt = "$Prompt [Default $DefaultChoice]: "
} else {
$prompt = "$Prompt [Y/N]: "
}
$choice = Read-Host -Prompt $prompt
if (-not $choice) { $choice = $DefaultChoice }
return $choice -in @('Y','y')
}
# Function to restart the service
function Restart-XUI {
Stop-Service x-ui -ErrorAction SilentlyContinue
Start-Service x-ui -ErrorAction SilentlyContinue
Start-Sleep -Seconds 2
$service = Get-Service x-ui -ErrorAction SilentlyContinue
if ($service.Status -eq 'Running') {
LOGI "x-ui restarted successfully"
} else {
LOGE "Failed to restart x-ui"
}
}
# Main menu function
function Show-Menu {
Write-Host @"
$($colors.Green)3X-UI Panel Management Script$($colors.Plain)
$($colors.Green)0.$($colors.Plain) Exit Script
$($colors.Green)1.$($colors.Plain) Install
$($colors.Green)2.$($colors.Plain) Update
$($colors.Green)3.$($colors.Plain) Legacy Version
$($colors.Green)4.$($colors.Plain) Uninstall
$($colors.Green)5.$($colors.Plain) Reset Username & Password
$($colors.Green)6.$($colors.Plain) Reset Web Base Path
$($colors.Green)7.$($colors.Plain) Reset Settings
$($colors.Green)8.$($colors.Plain) Change Port
$($colors.Green)9.$($colors.Plain) View Current Settings
$($colors.Green)10.$($colors.Plain) Start
$($colors.Green)11.$($colors.Plain) Stop
$($colors.Green)12.$($colors.Plain) Restart
$($colors.Green)13.$($colors.Plain) Check Status
$($colors.Green)14.$($colors.Plain) View Logs
$($colors.Green)15.$($colors.Plain) Enable Autostart
$($colors.Green)16.$($colors.Plain) Disable Autostart
"@
Show-Status
$choice = Read-Host "`nPlease enter your selection [0-16]"
switch ($choice) {
"0" { exit 0 }
"1" { Install-XUI }
"2" { Update-XUI }
"3" { Install-LegacyVersion }
"4" { Uninstall-XUI }
"5" { Reset-XUICredentials }
"6" { Reset-WebBasePath }
"7" { Reset-Settings }
"8" { Set-XUIPort }
"9" { Show-Settings }
"10" { Start-XUI }
"11" { Stop-XUI }
"12" { Restart-XUI }
"13" { Show-Status }
"14" { Show-Logs }
"15" { Enable-XUIAutostart }
"16" { Disable-XUIAutostart }
default { LOGE "Please enter the correct number [0-16]" }
}
Show-Menu
}
# Show service status
function Show-Status {
$service = Get-Service x-ui -ErrorAction SilentlyContinue
if ($service) {
Write-Host "Panel Status: " -NoNewline
if ($service.Status -eq 'Running') {
Write-Host "$($colors.Green)Running$($colors.Plain)"
} else {
Write-Host "$($colors.Red)Stopped$($colors.Plain)"
}
} else {
Write-Host "Panel Status: $($colors.Red)Not Installed$($colors.Plain)"
}
}
# Main entry point
if ($args.Count -gt 0) {
switch ($args[0]) {
"start" { Start-XUI }
"stop" { Stop-XUI }
"restart" { Restart-XUI }
"status" { Show-Status }
"enable" { Enable-XUIAutostart }
"disable" { Disable-XUIAutostart }
"log" { Show-Logs -LogType "service" }
"banlog" { Show-Logs -LogType "ban" }
"update" { Update-XUI }
"install" { Install-XUI }
"uninstall" { Uninstall-XUI }
"settings" { Show-Settings }
"legacy" { Install-LegacyVersion }
default { Show-Usage }
}
} else {
Show-Menu
}
# Add these functions after the existing logging functions
function Install-BasePackages {
# Check if winget is available
if (Get-Command winget -ErrorAction SilentlyContinue) {
Write-Host "Installing required packages using winget..."
winget install -e --id Git.Git
winget install -e --id Microsoft.PowerShell
winget install -e --id Nssm.Nssm # Add NSSM installation
} else {
Write-Host -ForegroundColor $colors.Red "Please install winget package manager or install Git and NSSM manually"
exit 1
}
}
function Install-XUI {
param([string]$version = "")
$installDir = "C:\Program Files\x-ui"
# Create install directory if it doesn't exist
if (-not (Test-Path $installDir)) {
New-Item -ItemType Directory -Path $installDir -Force
}
# Get latest version if not specified
if (-not $version) {
$version = (Invoke-RestMethod "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest").tag_name
}
$arch = Get-CPUArchitecture
$downloadUrl = "https://github.com/MHSanaei/3x-ui/releases/download/${version}/x-ui-windows-${arch}.zip"
$zipFile = Join-Path $installDir "x-ui.zip"
# Download and extract
Invoke-WebRequest -Uri $downloadUrl -OutFile $zipFile
Expand-Archive -Path $zipFile -DestinationPath $installDir -Force
Remove-Item $zipFile
# Create service script
$servicePath = Join-Path $installDir "x-ui-service.ps1"
@"
# Service script content
`$process = Start-Process -FilePath "C:\Program Files\x-ui\x-ui.exe" -NoNewWindow -PassThru
while (-not `$process.HasExited) {
Start-Sleep -Seconds 1
}
"@ | Set-Content $servicePath
# Register service using nssm
if (Get-Command nssm -ErrorAction SilentlyContinue) {
nssm install x-ui powershell
nssm set x-ui Application "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
nssm set x-ui AppParameters "-ExecutionPolicy Bypass -NoProfile -File `"$servicePath`""
nssm start x-ui
} else {
Write-Host -ForegroundColor $colors.Red "NSSM is not installed. Please install it to run x-ui as a service."
}
Configure-AfterInstall
Write-Host -ForegroundColor $colors.Green "x-ui ${version} installation finished"
}
function Update-XUI {
if (-not (Confirm-Action "This will reinstall the latest version. Continue?" "Y")) {
LOGE "Cancelled"
return
}
Stop-Service x-ui
Install-XUI
Start-Service x-ui
LOGI "Update complete, service restarted"
}
function Uninstall-XUI {
if (-not (Confirm-Action "Are you sure you want to uninstall x-ui?" "N")) {
return
}
Stop-Service x-ui
nssm remove x-ui confirm
Remove-Item "C:\Program Files\x-ui" -Recurse -Force
LOGI "x-ui uninstalled successfully"
}
function Reset-XUICredentials {
if (-not (Confirm-Action "Reset username and password?" "N")) {
return
}
$config = Get-Content "C:\Program Files\x-ui\config.json" | ConvertFrom-Json
$newUsername = Read-Host "Enter new username (leave blank for random)"
if (-not $newUsername) {
$newUsername = -join ((65..90) + (97..122) | Get-Random -Count 8 | ForEach-Object {[char]$_})
}
$newPassword = Read-Host "Enter new password (leave blank for random)"
if (-not $newPassword) {
$newPassword = -join ((65..90) + (97..122) + (48..57) | Get-Random -Count 12 | ForEach-Object {[char]$_})
}
$config.username = $newUsername
$config.password = $newPassword
$config | ConvertTo-Json | Set-Content "C:\Program Files\x-ui\config.json"
LOGI "Credentials updated successfully"
Write-Host "New username: $newUsername"
Write-Host "New password: $newPassword"
Restart-XUI
}
function Show-Usage {
Write-Host @"
Usage: x-ui [command]
Commands:
start - Start x-ui panel
stop - Stop x-ui panel
restart - Restart x-ui panel
status - Check x-ui status
enable - Enable x-ui on system startup
disable - Disable x-ui on system startup
log - Show x-ui logs
banlog - Show ban logs
update - Update x-ui panel
install - Install x-ui panel
uninstall - Uninstall x-ui panel
settings - Show current settings
legacy - Install specific version
"@
}
function Get-CPUArchitecture {
$arch = [System.Environment]::GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")
if ($arch -eq "AMD64") { return "amd64" }
elseif ($arch -eq "X86") { return "386" }
elseif ($arch -eq "ARM64") { return "arm64" }
else { return "amd64" } # Default to amd64
}
function Start-XUI {
$service = Get-Service x-ui -ErrorAction SilentlyContinue
if ($service.Status -eq 'Running') {
LOGI "Panel is already running"
return
}
Start-Service x-ui
Start-Sleep -Seconds 2
if ((Get-Service x-ui).Status -eq 'Running') {
LOGI "x-ui Started Successfully"
} else {
LOGE "Failed to start x-ui"
}
}
function Stop-XUI {
Stop-Service x-ui -ErrorAction SilentlyContinue
if ((Get-Service x-ui).Status -eq 'Stopped') {
LOGI "x-ui Stopped Successfully"
} else {
LOGE "Failed to stop x-ui"
}
}
function Enable-XUIAutostart {
Set-Service x-ui -StartupType Automatic
LOGI "x-ui has been enabled to start on system boot"
}
function Disable-XUIAutostart {
Set-Service x-ui -StartupType Manual
LOGI "x-ui has been disabled from starting on system boot"
}
function Show-Logs {
param (
[string]$LogType = "service"
)
switch ($LogType) {
"service" {
$logPath = Join-Path $logFolder "x-ui.log"
if (Test-Path $logPath) {
Get-Content $logPath -Tail 50
} else {
LOGE "Log file not found"
}
}
"ban" {
if (Test-Path $iplimitBannedLogPath) {
Get-Content $iplimitBannedLogPath -Tail 50
} else {
LOGE "Ban log file not found"
}
}
}
}
function Show-Settings {
$configFile = Join-Path $installDir "config.json"
if (Test-Path $configFile) {
$config = Get-Content $configFile | ConvertFrom-Json
$serverIP = (Invoke-WebRequest -Uri "https://api.ipify.org" -UseBasicParsing).Content
Write-Host "Current Settings:"
Write-Host "----------------------------------------"
Write-Host "Username: $($config.username)"
Write-Host "Port: $($config.port)"
Write-Host "Base Path: $($config.webBasePath)"
Write-Host "Panel URL: http://${serverIP}:$($config.port)$($config.webBasePath)"
Write-Host "----------------------------------------"
} else {
LOGE "Configuration file not found"
}
}
function Set-XUIPort {
$port = Read-Host "Enter new port number [1-65535]"
if ($port -match '^\d+$' -and [int]$port -ge 1 -and [int]$port -le 65535) {
$configFile = Join-Path $installDir "config.json"
$config = Get-Content $configFile | ConvertFrom-Json
$config.port = [int]$port
$config | ConvertTo-Json | Set-Content $configFile
LOGI "Port updated successfully. Restarting service..."
Restart-XUI
} else {
LOGE "Invalid port number"
}
}
function Install-LegacyVersion {
$version = Read-Host "Enter the panel version (like 2.4.0)"
if (-not $version) {
LOGE "Version cannot be empty"
return
}
Install-XUI -version "v$version"
}