503 lines
22 KiB
PowerShell
503 lines
22 KiB
PowerShell
<#
|
|
LXS - Windows multi-tool
|
|
Description: Centralized workstation management and deployment toolkit
|
|
Repo: https://git.hyko.cx/hykocx/lxs
|
|
License: MIT
|
|
|
|
Mirrors linux/lxs.sh: same verbs, same menu, same update flow.
|
|
Compatible with Windows PowerShell 5.1 and PowerShell 7+.
|
|
#>
|
|
|
|
# Raw $args pass-through: sub-scripts get their own flags verbatim
|
|
# (e.g. `lxs tool harden -Yes`) without this script trying to bind them.
|
|
$LxsArgs = @($args)
|
|
$LxsCommand = if ($LxsArgs.Count -gt 0) { [string]$LxsArgs[0] } else { '' }
|
|
$LxsRest = if ($LxsArgs.Count -gt 1) { $LxsArgs[1..($LxsArgs.Count - 1)] } else { @() }
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Configuration
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
$LxsScriptDir = $PSScriptRoot
|
|
if (-not $LxsScriptDir) { $LxsScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path }
|
|
|
|
$LxsVersion = 'dev'
|
|
if ($LxsScriptDir) {
|
|
$versionFile = Join-Path $LxsScriptDir '..\VERSION'
|
|
if (Test-Path $versionFile) {
|
|
$raw = (Get-Content $versionFile -TotalCount 1 -ErrorAction SilentlyContinue)
|
|
if ($raw) { $LxsVersion = $raw.Trim() }
|
|
}
|
|
}
|
|
|
|
$LxsRepoUrl = 'https://git.hyko.cx/hykocx/lxs'
|
|
$LxsBranch = if ($env:LXS_BRANCH) { $env:LXS_BRANCH } else { 'main' }
|
|
$LxsRawBase = if ($env:LXS_RAW_BASE) { $env:LXS_RAW_BASE } else { "$LxsRepoUrl/raw/branch/$LxsBranch" }
|
|
|
|
# Platform sub-tree: every apps\ and tools\ path resolves under it.
|
|
$LxsPlatformDir = 'windows'
|
|
$env:LXS_RAW_BASE = $LxsRawBase
|
|
$env:LXS_RAW_PLATFORM_BASE = "$LxsRawBase/$LxsPlatformDir"
|
|
|
|
$LxsZipUrl = if ($env:LXS_ZIP_URL) { $env:LXS_ZIP_URL } else { "$LxsRepoUrl/archive/$LxsBranch.zip" }
|
|
# LOCALAPPDATA is normally set; fall back so a service/SYSTEM context that
|
|
# lacks it still resolves to a writable directory instead of erroring out.
|
|
$LxsLocalAppData = $env:LOCALAPPDATA
|
|
if (-not $LxsLocalAppData) {
|
|
$LxsLocalAppData = if ($env:USERPROFILE) { Join-Path $env:USERPROFILE 'AppData\Local' } else { [IO.Path]::GetTempPath() }
|
|
}
|
|
$LxsInstallDir = if ($env:LXS_INSTALL_DIR) { $env:LXS_INSTALL_DIR } else { Join-Path $LxsLocalAppData 'lxs' }
|
|
$LxsBinDir = Join-Path $LxsInstallDir 'bin'
|
|
$LxsShimPath = Join-Path $LxsBinDir 'lxs.cmd'
|
|
$LxsCacheDir = Join-Path $LxsInstallDir 'cache'
|
|
$LxsVersionCache = Join-Path $LxsCacheDir 'remote_version'
|
|
$LxsVersionTtl = 86400
|
|
|
|
$script:LxsUpdateAvailable = $false
|
|
$script:LxsRemoteVersion = ''
|
|
$script:LxsPublicIpCache = $null
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Load common library
|
|
# Prefers a sibling lib\common.ps1 (installed or repo checkout); falls back to
|
|
# fetching it from the remote when run via `irm ... | iex`.
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
$libPath = if ($LxsScriptDir) { Join-Path $LxsScriptDir 'lib\common.ps1' } else { $null }
|
|
if ($libPath -and (Test-Path $libPath)) {
|
|
. $libPath
|
|
} else {
|
|
try {
|
|
$libSource = Invoke-RestMethod -Uri "$env:LXS_RAW_PLATFORM_BASE/lib/common.ps1" -UseBasicParsing -ErrorAction Stop
|
|
} catch {
|
|
Write-Error 'Failed to fetch lib/common.ps1'
|
|
exit 1
|
|
}
|
|
. ([scriptblock]::Create($libSource))
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Core helpers
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
function Get-LxsCachedPublicIP {
|
|
if ($null -eq $script:LxsPublicIpCache) {
|
|
$script:LxsPublicIpCache = Get-LxsPublicIP
|
|
}
|
|
return $script:LxsPublicIpCache
|
|
}
|
|
|
|
# Compare two dotted versions. Returns $true when $Candidate is newer.
|
|
function Test-LxsNewerVersion {
|
|
param([string]$Current, [string]$Candidate)
|
|
try {
|
|
return ([version]$Candidate -gt [version]$Current)
|
|
} catch {
|
|
return ($Candidate -ne $Current)
|
|
}
|
|
}
|
|
|
|
function Test-LxsRemoteVersion {
|
|
$script:LxsUpdateAvailable = $false
|
|
$script:LxsRemoteVersion = ''
|
|
|
|
try {
|
|
if (-not (Test-Path $LxsCacheDir)) { New-Item -ItemType Directory -Path $LxsCacheDir -Force | Out-Null }
|
|
} catch {
|
|
return
|
|
}
|
|
|
|
$age = [double]::MaxValue
|
|
if (Test-Path $LxsVersionCache) {
|
|
$age = ((Get-Date) - (Get-Item $LxsVersionCache).LastWriteTime).TotalSeconds
|
|
}
|
|
|
|
if ($age -ge $LxsVersionTtl) {
|
|
# Refresh inline but on a short leash — a slow repo must not stall the menu.
|
|
try {
|
|
$remote = Invoke-RestMethod -Uri "$LxsRawBase/VERSION" -TimeoutSec 3 `
|
|
-Headers @{ 'Cache-Control' = 'no-cache' } -UseBasicParsing -ErrorAction Stop
|
|
("$remote").Trim() | Set-Content -Path $LxsVersionCache -Encoding ASCII
|
|
} catch {
|
|
# Offline or unreachable: fall through to whatever is cached.
|
|
}
|
|
}
|
|
|
|
if (-not (Test-Path $LxsVersionCache)) { return }
|
|
$cached = (Get-Content $LxsVersionCache -TotalCount 1 -ErrorAction SilentlyContinue)
|
|
if (-not $cached) { return }
|
|
$cached = $cached.Trim()
|
|
|
|
if (Test-LxsNewerVersion -Current $LxsVersion -Candidate $cached) {
|
|
$script:LxsUpdateAvailable = $true
|
|
$script:LxsRemoteVersion = $cached
|
|
}
|
|
}
|
|
|
|
function Show-LxsLogo {
|
|
Show-LxsBoxTop -Title "LXS // v$LxsVersion" -Right 'WINDOWS'
|
|
}
|
|
|
|
function Show-LxsHeader {
|
|
Clear-Host
|
|
Show-LxsLogo
|
|
|
|
if ($script:LxsUpdateAvailable) {
|
|
Write-Host ''
|
|
Write-Host " $($script:Cyan)[!!] UPDATE_AVAILABLE$($script:NC) $($script:White)v$($script:LxsRemoteVersion)$($script:NC) $($script:Gray)// run ``lxs update``$($script:NC)"
|
|
}
|
|
|
|
$hostname = $env:COMPUTERNAME
|
|
$osName = 'Windows'
|
|
$build = ''
|
|
$uptime = 'unknown'
|
|
$totalMem = 0.0
|
|
$usedMem = 0.0
|
|
try {
|
|
$os = Get-CimInstance Win32_OperatingSystem -ErrorAction Stop
|
|
$osName = ($os.Caption -replace '^Microsoft ', '').Trim()
|
|
$build = "$($os.Version) ($($os.BuildNumber))"
|
|
$span = (Get-Date) - $os.LastBootUpTime
|
|
$uptime = "{0}d {1}h {2}m" -f $span.Days, $span.Hours, $span.Minutes
|
|
$totalMem = [math]::Round($os.TotalVisibleMemorySize / 1MB, 1)
|
|
$usedMem = [math]::Round(($os.TotalVisibleMemorySize - $os.FreePhysicalMemory) / 1MB, 1)
|
|
} catch {
|
|
# CIM unavailable — the header degrades but the menu still works.
|
|
}
|
|
|
|
$cores = $env:NUMBER_OF_PROCESSORS
|
|
$ip = Get-LxsCachedPublicIP
|
|
|
|
$disk = 'unknown'
|
|
try {
|
|
$sys = New-Object System.IO.DriveInfo "$env:SystemDrive\"
|
|
$totalGB = [math]::Round($sys.TotalSize / 1GB, 1)
|
|
$usedGB = [math]::Round(($sys.TotalSize - $sys.AvailableFreeSpace) / 1GB, 1)
|
|
$pct = if ($sys.TotalSize -gt 0) { [math]::Round(100 * ($sys.TotalSize - $sys.AvailableFreeSpace) / $sys.TotalSize) } else { 0 }
|
|
$disk = "${usedGB}G/${totalGB}G (${pct}%)"
|
|
} catch {
|
|
# No access to the system drive info.
|
|
}
|
|
|
|
Write-Host ''
|
|
Write-Host (" $($script:Cyan)NODE$($script:NC) $($script:White){0,-26}$($script:NC) $($script:Cyan)BUILD$($script:NC) $($script:White){1}$($script:NC)" -f $hostname, $build)
|
|
Write-Host (" $($script:Cyan)ADDR$($script:NC) $($script:White){0,-26}$($script:NC) $($script:Cyan)UP$($script:NC) $($script:White){1}$($script:NC)" -f $ip, $uptime)
|
|
Write-Host (" $($script:Cyan)OS$($script:NC) $($script:White){0,-26}$($script:NC) $($script:Cyan)CPU$($script:NC) $($script:White){1} cores$($script:NC)" -f $osName, $cores)
|
|
Write-Host (" $($script:Cyan)DISK$($script:NC) $($script:White){0,-26}$($script:NC) $($script:Cyan)MEM$($script:NC) $($script:White){1} / {2} GB$($script:NC)" -f $disk, $usedMem, $totalMem)
|
|
Write-Host ''
|
|
}
|
|
|
|
# Run a sub-script (tools\... or apps\...). Prefers the installed copy;
|
|
# falls back to fetching it. Mirrors download_and_run() in linux/lxs.sh.
|
|
function Invoke-LxsScript {
|
|
param(
|
|
[Parameter(Mandatory = $true)][string]$RelativePath,
|
|
[string[]]$Arguments = @()
|
|
)
|
|
$name = Split-Path $RelativePath -Leaf
|
|
$localPath = $null
|
|
if ($LxsScriptDir) { $localPath = Join-Path $LxsScriptDir $RelativePath }
|
|
|
|
$target = $null
|
|
$temp = $null
|
|
if ($localPath -and (Test-Path $localPath)) {
|
|
$target = $localPath
|
|
} else {
|
|
$url = "$env:LXS_RAW_PLATFORM_BASE/$($RelativePath -replace '\\', '/')"
|
|
$temp = Join-Path (Get-LxsTempDir) ("lxs.{0}.{1}.ps1" -f [IO.Path]::GetFileNameWithoutExtension($name), [guid]::NewGuid().ToString('N').Substring(0, 8))
|
|
Write-Host ''
|
|
Write-LxsInfo "Fetching $($script:Bold)$name$($script:NC)..."
|
|
try {
|
|
Invoke-WebRequest -Uri $url -OutFile $temp -UseBasicParsing `
|
|
-Headers @{ 'Cache-Control' = 'no-cache' } -ErrorAction Stop
|
|
} catch {
|
|
Write-LxsErr "Failed to download $RelativePath"
|
|
Write-Host "$($script:Gray) URL: $url$($script:NC)"
|
|
return 1
|
|
}
|
|
Write-LxsOk 'Payload acquired'
|
|
$target = $temp
|
|
}
|
|
|
|
Write-Host ''
|
|
Show-LxsSeparator
|
|
Write-Host ''
|
|
|
|
$global:LASTEXITCODE = 0
|
|
try {
|
|
& $target @Arguments
|
|
$code = $LASTEXITCODE
|
|
} finally {
|
|
if ($temp) { Remove-Item $temp -Force -ErrorAction SilentlyContinue }
|
|
}
|
|
if ($null -eq $code) { $code = 0 }
|
|
|
|
Write-Host ''
|
|
Show-LxsSeparator
|
|
if ($code -eq 0 -or $code -eq 75) {
|
|
Write-LxsOk 'Script completed successfully'
|
|
} else {
|
|
Write-LxsWarn "Script exited with code: $code"
|
|
}
|
|
return $code
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# CLI commands
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
function Invoke-LxsCmdVersion { Write-Host "lxs $LxsVersion" }
|
|
|
|
function Invoke-LxsCmdHelp {
|
|
Write-Host @"
|
|
LXS - Windows multi-tool (v$LxsVersion)
|
|
|
|
Usage:
|
|
lxs Interactive menu (browse apps and tools)
|
|
lxs setup Install lxs to $LxsInstallDir and add it to PATH
|
|
lxs update Update all installed files to latest
|
|
lxs install <app> Install an application bundle
|
|
lxs tool <name> [args] Run a system tool
|
|
lxs info Show system info
|
|
lxs version Show version
|
|
lxs help Show this help
|
|
|
|
Applications:
|
|
dev Git, VS Code, Node.js, Python, PowerShell 7, Windows Terminal
|
|
utilities 7-Zip, Notepad++, PowerToys, Sysinternals, Everything, ShareX
|
|
browsers Firefox, LibreWolf, Chrome, Brave, VLC, OBS Studio
|
|
containers WSL2, Hyper-V, Docker Desktop, VirtualBox
|
|
claude-code Claude Code CLI (+ Git for Windows)
|
|
|
|
Tools:
|
|
system System information and diagnostics
|
|
network Network diagnostics and repair
|
|
cleanup Free disk space (temp, update cache, recycle bin, WinSxS)
|
|
repair SFC / DISM / chkdsk integrity repair
|
|
restore-point Create, list or roll back to a System Restore point
|
|
update Windows Update + winget upgrade
|
|
harden Baseline security hardening
|
|
remote-access Remote Desktop and OpenSSH server
|
|
debloat Remove preinstalled apps and disable telemetry
|
|
|
|
Source: $LxsRepoUrl
|
|
"@
|
|
}
|
|
|
|
function Invoke-LxsCmdInstall {
|
|
param([string]$App, [string[]]$Arguments = @())
|
|
switch ($App) {
|
|
'dev' { return (Invoke-LxsScript 'apps\dev-pack.ps1' $Arguments) }
|
|
'utilities' { return (Invoke-LxsScript 'apps\utilities.ps1' $Arguments) }
|
|
'browsers' { return (Invoke-LxsScript 'apps\browsers-media.ps1' $Arguments) }
|
|
'containers' { return (Invoke-LxsScript 'apps\containers.ps1' $Arguments) }
|
|
'claude-code' { return (Invoke-LxsScript 'apps\claude-code.ps1' $Arguments) }
|
|
'' { Write-LxsErr 'Missing app name. Try: lxs help'; return 1 }
|
|
default { Write-LxsErr "Unknown app: $App. Try: lxs help"; return 1 }
|
|
}
|
|
}
|
|
|
|
function Invoke-LxsCmdTool {
|
|
param([string]$Tool, [string[]]$Arguments = @())
|
|
switch ($Tool) {
|
|
'system' { return (Invoke-LxsScript 'tools\system-info.ps1' $Arguments) }
|
|
'network' { return (Invoke-LxsScript 'tools\net-diag.ps1' $Arguments) }
|
|
'cleanup' { return (Invoke-LxsScript 'tools\cleanup.ps1' $Arguments) }
|
|
'repair' { return (Invoke-LxsScript 'tools\repair.ps1' $Arguments) }
|
|
'restore-point' { return (Invoke-LxsScript 'tools\restore-point.ps1' $Arguments) }
|
|
'update' { return (Invoke-LxsScript 'tools\update-windows.ps1' $Arguments) }
|
|
'harden' { return (Invoke-LxsScript 'tools\harden.ps1' $Arguments) }
|
|
'remote-access' { return (Invoke-LxsScript 'tools\remote-access.ps1' $Arguments) }
|
|
'debloat' { return (Invoke-LxsScript 'tools\debloat.ps1' $Arguments) }
|
|
'' { Write-LxsErr 'Missing tool name. Try: lxs help'; return 1 }
|
|
default { Write-LxsErr "Unknown tool: $Tool. Try: lxs help"; return 1 }
|
|
}
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# setup / update — download the repo zip and mirror it into $LxsInstallDir.
|
|
# Everything lands under %LOCALAPPDATA%, so no elevation is needed here;
|
|
# individual tools elevate themselves when they touch the machine.
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
function Invoke-LxsSync {
|
|
param([ValidateSet('setup', 'update')][string]$Action = 'update')
|
|
|
|
$work = Join-Path (Get-LxsTempDir) ("lxs.install.{0}" -f [guid]::NewGuid().ToString('N').Substring(0, 8))
|
|
try {
|
|
New-Item -ItemType Directory -Path $work -Force | Out-Null
|
|
} catch {
|
|
Write-LxsErr 'Failed to create temp dir'
|
|
return 1
|
|
}
|
|
|
|
try {
|
|
$zip = Join-Path $work 'lxs.zip'
|
|
Write-LxsInfo "Fetching $LxsZipUrl..."
|
|
try {
|
|
$progressBackup = $ProgressPreference
|
|
$ProgressPreference = 'SilentlyContinue'
|
|
Invoke-WebRequest -Uri $LxsZipUrl -OutFile $zip -UseBasicParsing `
|
|
-Headers @{ 'Cache-Control' = 'no-cache' } -ErrorAction Stop
|
|
$ProgressPreference = $progressBackup
|
|
} catch {
|
|
Write-LxsErr "Download failed: $($_.Exception.Message)"
|
|
return 1
|
|
}
|
|
|
|
$extracted = Join-Path $work 'extracted'
|
|
try {
|
|
Expand-Archive -Path $zip -DestinationPath $extracted -Force -ErrorAction Stop
|
|
} catch {
|
|
Write-LxsErr "Extraction failed: $($_.Exception.Message)"
|
|
return 1
|
|
}
|
|
|
|
# Gitea wraps the tree in a single <repo>/ directory: strip it.
|
|
$root = $extracted
|
|
$entries = @(Get-ChildItem -Path $extracted -Force)
|
|
if ($entries.Count -eq 1 -and $entries[0].PSIsContainer) { $root = $entries[0].FullName }
|
|
|
|
if (-not (Test-Path (Join-Path $root "$LxsPlatformDir\lxs.ps1")) -or
|
|
-not (Test-Path (Join-Path $root 'VERSION'))) {
|
|
Write-LxsErr "Archive is missing $LxsPlatformDir\lxs.ps1 or VERSION"
|
|
return 1
|
|
}
|
|
|
|
# Replace the payload directories wholesale (so files deleted upstream
|
|
# really disappear) but keep bin\ and cache\, so the shim on PATH and
|
|
# the version cache survive an update. The old tree is moved aside
|
|
# rather than deleted, and put back if the copy fails.
|
|
if (-not (Test-Path $LxsInstallDir)) { New-Item -ItemType Directory -Path $LxsInstallDir -Force | Out-Null }
|
|
$backup = Join-Path $work 'previous'
|
|
New-Item -ItemType Directory -Path $backup -Force | Out-Null
|
|
foreach ($dir in @('linux', 'windows')) {
|
|
$dest = Join-Path $LxsInstallDir $dir
|
|
if (Test-Path $dest) { Move-Item -Path $dest -Destination (Join-Path $backup $dir) -Force -ErrorAction SilentlyContinue }
|
|
}
|
|
try {
|
|
Copy-Item -Path (Join-Path $root '*') -Destination $LxsInstallDir -Recurse -Force -ErrorAction Stop
|
|
} catch {
|
|
Write-LxsErr "Copy failed: $($_.Exception.Message)"
|
|
Write-LxsInfo 'Restoring the previous install...'
|
|
foreach ($dir in @('linux', 'windows')) {
|
|
$saved = Join-Path $backup $dir
|
|
if (Test-Path $saved) {
|
|
$dest = Join-Path $LxsInstallDir $dir
|
|
if (Test-Path $dest) { Remove-Item $dest -Recurse -Force -ErrorAction SilentlyContinue }
|
|
Move-Item -Path $saved -Destination $dest -Force -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
return 1
|
|
}
|
|
|
|
# Command shim on PATH. -ExecutionPolicy Bypass so a restricted policy
|
|
# (the default on desktop SKUs) does not block the installed scripts.
|
|
if (-not (Test-Path $LxsBinDir)) { New-Item -ItemType Directory -Path $LxsBinDir -Force | Out-Null }
|
|
$shim = @"
|
|
@echo off
|
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0..\$LxsPlatformDir\lxs.ps1" %*
|
|
exit /b %ERRORLEVEL%
|
|
"@
|
|
Set-Content -Path $LxsShimPath -Value $shim -Encoding ASCII -Force
|
|
|
|
try {
|
|
if (Add-LxsUserPath -Directory $LxsBinDir) {
|
|
Write-LxsOk "Added $LxsBinDir to your user PATH (open a new terminal to use ``lxs``)"
|
|
}
|
|
} catch {
|
|
# A blocked registry write must not fail an otherwise good install.
|
|
Write-LxsWarn "Could not update your user PATH: $($_.Exception.Message)"
|
|
Write-Host "$($script:Gray) Run lxs directly: $LxsShimPath$($script:NC)"
|
|
}
|
|
|
|
Remove-Item $LxsVersionCache -Force -ErrorAction SilentlyContinue
|
|
|
|
$newVersion = (Get-Content (Join-Path $LxsInstallDir 'VERSION') -TotalCount 1 -ErrorAction SilentlyContinue)
|
|
if ($newVersion) { $newVersion = $newVersion.Trim() }
|
|
Write-LxsOk "lxs $newVersion installed in $LxsInstallDir"
|
|
Write-LxsOk "Command: $LxsShimPath"
|
|
return 0
|
|
} finally {
|
|
Remove-Item $work -Recurse -Force -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Interactive menu
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
function Invoke-LxsMainMenu {
|
|
if (-not (Assert-LxsWindows)) { exit 1 }
|
|
Test-LxsRemoteVersion
|
|
|
|
while ($true) {
|
|
Show-LxsHeader
|
|
Show-LxsBoxMid 'SELECT'
|
|
Write-Host ''
|
|
Show-LxsMenuItem '01' 'APPLICATIONS' 'deploy stacks'
|
|
Show-LxsMenuItem '02' 'TOOLS' 'windows toolbox'
|
|
Show-LxsMenuItem 'UU' 'FETCH_UPDATE' 'sync remote'
|
|
Show-LxsMenuItem '00' 'JACK_OUT' 'exit shell' -Exit
|
|
Write-Host ''
|
|
Show-LxsBoxBottom
|
|
Write-Host ''
|
|
$choice = Read-LxsChoice
|
|
|
|
switch -Regex ($choice) {
|
|
'^0?1$' { Invoke-LxsScript 'apps\index.ps1' | Out-Null; continue }
|
|
'^0?2$' { Invoke-LxsScript 'tools\index.ps1' | Out-Null; continue }
|
|
'^[uU]{1,2}$' {
|
|
if ((Invoke-LxsSync -Action update) -eq 0) {
|
|
$reinstalled = Join-Path $LxsInstallDir "$LxsPlatformDir\lxs.ps1"
|
|
if (Test-Path $reinstalled) {
|
|
Read-LxsEnter 'Press Enter to reload with the new version...'
|
|
& $reinstalled
|
|
exit 0
|
|
}
|
|
}
|
|
Read-LxsEnter
|
|
continue
|
|
}
|
|
'^0?0$' {
|
|
Clear-Host
|
|
Show-LxsLogo
|
|
Write-Host "$($script:Cyan)JACK_OUT$($script:NC) $($script:Gray)// session terminated$($script:NC)"
|
|
Write-Host ''
|
|
exit 0
|
|
}
|
|
default {
|
|
Write-LxsErr 'Invalid protocol.'
|
|
Start-Sleep -Seconds 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Entrypoint
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
$exitCode = 0
|
|
switch ($LxsCommand) {
|
|
'install' { $exitCode = Invoke-LxsCmdInstall -App ([string]($LxsRest | Select-Object -First 1)) -Arguments @($LxsRest | Select-Object -Skip 1) }
|
|
'tool' { $exitCode = Invoke-LxsCmdTool -Tool ([string]($LxsRest | Select-Object -First 1)) -Arguments @($LxsRest | Select-Object -Skip 1) }
|
|
'info' { Show-LxsHeader }
|
|
'update' { $exitCode = Invoke-LxsSync -Action update }
|
|
'setup' { $exitCode = Invoke-LxsSync -Action setup }
|
|
'install-self' { $exitCode = Invoke-LxsSync -Action setup }
|
|
'version' { Invoke-LxsCmdVersion }
|
|
'-v' { Invoke-LxsCmdVersion }
|
|
'--version' { Invoke-LxsCmdVersion }
|
|
'help' { Invoke-LxsCmdHelp }
|
|
'-h' { Invoke-LxsCmdHelp }
|
|
'--help' { Invoke-LxsCmdHelp }
|
|
'' { Invoke-LxsMainMenu }
|
|
default {
|
|
Write-LxsErr "Unknown command: $LxsCommand"
|
|
Invoke-LxsCmdHelp
|
|
$exitCode = 1
|
|
}
|
|
}
|
|
exit $exitCode
|