more linux via wsl compat

This commit is contained in:
lda
2026-04-09 01:05:54 +07:00 Unverified
parent ba408af95c
commit fc2243ed8f
3 changed files with 199 additions and 16 deletions
+164 -4
View File
@@ -1,5 +1,73 @@
# Shared functions for wakey scripts
# Platform detection globals
$script:IsWsl = $null
$script:IsWindows = $null
$script:WarnedNoSshpass = $false
function Test-IsWindows {
if ($null -ne $script:IsWindows) {
return $script:IsWindows
}
$script:IsWindows = $false
try {
$osInfo = [System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform([System.Runtime.InteropServices.OSPlatform]::Windows)
$script:IsWindows = $osInfo
}
catch {
# Fallback for older PowerShell versions
$script:IsWindows = $PSVersionTable.OS -like '*Windows*'
}
return $script:IsWindows
}
function Test-IsWsl {
if ($null -ne $script:IsWsl) {
return $script:IsWsl
}
$script:IsWsl = $false
# Check for WSL environment variables
if ($env:WSL_DISTRO_NAME -or $env:WSL_INTEROP) {
$script:IsWsl = $true
return $true
}
# Check for /proc/version containing "microsoft" or "wsl"
if ((Test-Path '/proc/version' -ErrorAction SilentlyContinue) -and
(Select-String -Path '/proc/version' -Pattern 'microsoft|wsl' -Quiet -ErrorAction SilentlyContinue)) {
$script:IsWsl = $true
return $true
}
return $false
}
function ConvertTo-WslPath {
param([string]$WindowsPath)
if ([string]::IsNullOrWhiteSpace($WindowsPath)) {
return $WindowsPath
}
# If already a POSIX path, return as-is
if ($WindowsPath -match '^/') {
return $WindowsPath
}
# Handle Windows path (e.g., C:\path\to\file -> /mnt/c/path/to/file)
if ($WindowsPath -match '^([A-Z]):(.*)$') {
$drive = $matches[1].ToLower()
$path = $matches[2] -replace '\\', '/'
return "/mnt/$drive$path"
}
return $WindowsPath
}
function Get-DefaultPassword {
param([string]$Password)
@@ -65,6 +133,45 @@ function Join-PosixPath {
return "$leftTrim/$rightTrim"
}
function Split-HostPort {
param(
[string]$Host,
[int]$DefaultPort = 22
)
$result = [ordered]@{
Host = $Host
Port = $DefaultPort
}
if ([string]::IsNullOrWhiteSpace($Host)) {
return [PSCustomObject]$result
}
# IPv6 with brackets: [2001:db8::1]:2222
if ($Host -match '^\[(.+)\]:(\d+)$') {
$result.Host = $matches[1]
$result.Port = [int]$matches[2]
return [PSCustomObject]$result
}
# host:port (single colon only, avoids plain IPv6 addresses)
if ($Host -match '^([^:]+):(\d+)$') {
$result.Host = $matches[1]
$result.Port = [int]$matches[2]
return [PSCustomObject]$result
}
return [PSCustomObject]$result
}
function Get-SshpassCommand {
if ($cmd = Get-Command sshpass -ErrorAction SilentlyContinue) {
return $cmd.Path
}
return $null
}
function Invoke-Ext {
param($Exe, $Arguments, $Label)
$displayArgs = $Arguments.Clone()
@@ -72,6 +179,9 @@ function Invoke-Ext {
if ($displayArgs[$i] -eq '-pw' -and ($i + 1) -lt $displayArgs.Count) {
$displayArgs[$i + 1] = '****'
}
if ($displayArgs[$i] -eq '-p' -and ($i + 1) -lt $displayArgs.Count -and $Exe -like '*sshpass*') {
$displayArgs[$i + 1] = '****'
}
}
Write-Host ("[{0}] {1} {2}" -f $Label, $Exe, ($displayArgs -join ' ')) -ForegroundColor Cyan
@@ -84,11 +194,17 @@ function Invoke-Ext {
}
function Invoke-Scp {
param($Local, $Dest, $Pass, $HostKey, [switch]$Quiet, [switch]$Recurse)
if ($pscp = Get-Command pscp.exe -ErrorAction SilentlyContinue) {
param($Local, $Dest, $Pass, $HostKey, [int]$Port = 22, [switch]$Quiet, [switch]$Recurse)
$isWindows = Test-IsWindows
$isWsl = Test-IsWsl
# Only use PuTTY on Windows (not in WSL)
if ($isWindows -and -not $isWsl -and ($pscp = Get-Command pscp.exe -ErrorAction SilentlyContinue)) {
$arguments = @('-scp')
if ($Quiet) { $arguments += '-q' }
if ($Recurse) { $arguments += '-r' }
if ($Port -gt 0) { $arguments += @('-P', $Port) }
if ($HostKey) { $arguments += @('-batch', '-hostkey', $HostKey) }
if ($Pass) { $arguments += @('-pw', $Pass) }
$arguments += @($Local)
@@ -96,20 +212,48 @@ function Invoke-Scp {
Invoke-Ext -Exe $pscp.Path -Arguments $arguments -Label 'scp'
}
else {
# Convert Windows paths to WSL paths if needed
if ($isWsl) {
$Local = @($Local | ForEach-Object { ConvertTo-WslPath $_ })
$Dest = ConvertTo-WslPath $Dest
}
$arguments = @('-O')
if ($Quiet) { $arguments += '-q' }
if ($Recurse) { $arguments += '-r' }
if ($Port -gt 0) { $arguments += @('-P', $Port) }
$arguments += @($Local)
$arguments += $Dest
if ($Pass) {
$sshpassExe = Get-SshpassCommand
if ($sshpassExe) {
$wrapped = @('-p', $Pass, 'scp') + $arguments
Invoke-Ext -Exe $sshpassExe -Arguments $wrapped -Label 'scp'
return
}
if (-not $script:WarnedNoSshpass) {
Write-Warning 'Password was provided but sshpass is not installed; falling back to plain scp (key/agent auth expected).'
$script:WarnedNoSshpass = $true
}
}
Invoke-Ext -Exe 'scp' -Arguments $arguments -Label 'scp'
}
}
function Invoke-Ssh {
param($Cmd, $User, $Remote, $Pass, [switch]$Quiet)
param($Cmd, $User, $Remote, $Pass, [int]$Port = 22, [switch]$Quiet)
$Cmd = Normalize-LineEndings $Cmd
if ($plink = Get-Command plink.exe -ErrorAction SilentlyContinue) {
$isWindows = Test-IsWindows
$isWsl = Test-IsWsl
# Only use PuTTY on Windows (not in WSL)
if ($isWindows -and -not $isWsl -and ($plink = Get-Command plink.exe -ErrorAction SilentlyContinue)) {
$arguments = @('-batch', '-ssh')
if ($Port -gt 0) { $arguments += @('-P', $Port) }
if ($Pass) { $arguments += @('-pw', $Pass) }
$dest = if ($User) { "$User@$Remote" } else { $Remote }
$arguments += $dest, $Cmd
@@ -118,8 +262,24 @@ function Invoke-Ssh {
else {
$arguments = @()
if ($Quiet) { $arguments += '-q' }
if ($Port -gt 0) { $arguments += @('-p', $Port) }
$dest = if ($User) { "$User@$Remote" } else { $Remote }
$arguments += $dest, $Cmd
if ($Pass) {
$sshpassExe = Get-SshpassCommand
if ($sshpassExe) {
$wrapped = @('-p', $Pass, 'ssh') + $arguments
Invoke-Ext -Exe $sshpassExe -Arguments $wrapped -Label 'ssh'
return
}
if (-not $script:WarnedNoSshpass) {
Write-Warning 'Password was provided but sshpass is not installed; falling back to plain ssh (key/agent auth expected).'
$script:WarnedNoSshpass = $true
}
}
Invoke-Ext -Exe 'ssh' -Arguments $arguments -Label 'ssh'
}
}