# Gemeinsame Homelab-Hilfen (credentials + Posh-SSH) function Read-HomelabKeyValueFile { param([string]$Path) $map = @{} if (-not (Test-Path $Path)) { return $map } Get-Content $Path | ForEach-Object { $line = $_.Trim() if ($line -eq "" -or $line.StartsWith("#")) { return } if ($line -match '^([^=]+)=(.*)$') { $map[$Matches[1].Trim()] = $Matches[2].Trim() } } return $map } function Ensure-PoshSshModule { if (-not (Get-Module -ListAvailable -Name Posh-SSH)) { Install-Module -Name Posh-SSH -Scope CurrentUser -Force -AllowClobber } Import-Module Posh-SSH -ErrorAction Stop } function Get-HomelabConfig { $deployDir = $PSScriptRoot $credFile = Join-Path $deployDir "homelab.credentials" if (-not (Test-Path $credFile)) { throw "deploy/homelab.credentials fehlt." } $cred = Read-HomelabKeyValueFile $credFile $envFile = Read-HomelabKeyValueFile (Join-Path $deployDir "env.homelab") $hostName = $cred["HOMELAB_HOST"] $user = $cred["HOMELAB_USER"] $password = $cred["HOMELAB_PASSWORD"] $sudoPassword = if ($cred["HOMELAB_SUDO_PASSWORD"]) { $cred["HOMELAB_SUDO_PASSWORD"] } else { $password } if ([string]::IsNullOrWhiteSpace($hostName)) { $hostName = "192.168.178.49" } if ([string]::IsNullOrWhiteSpace($user)) { $user = "gizzler" } if ([string]::IsNullOrWhiteSpace($password)) { throw "HOMELAB_PASSWORD in deploy/homelab.credentials ist leer." } $appDir = if ($cred["HOMELAB_APP_DIR"]) { $cred["HOMELAB_APP_DIR"] } elseif ($envFile["APP_DIR"]) { $envFile["APP_DIR"] } else { "/home/gizzler/bestewebsite/bestewebsite" } $sec = ConvertTo-SecureString $password -AsPlainText -Force $psCred = New-Object System.Management.Automation.PSCredential ($user, $sec) return [PSCustomObject]@{ HostName = $hostName User = $user Password = $password SudoPassword = $sudoPassword AppDir = $appDir Credential = $psCred SshTarget = "${user}@${hostName}" } } function Resolve-HomelabIPv4 { param([string]$HostName) if ($HostName -match '^\d+\.\d+\.\d+\.\d+$') { return $HostName } try { $v4 = [System.Net.Dns]::GetHostAddresses($HostName) | Where-Object { $_.AddressFamily -eq [System.Net.Sockets.AddressFamily]::InterNetwork } | Select-Object -First 1 if ($v4) { return $v4.ToString() } } catch { } return $HostName } function New-HomelabSession { param($Config) Ensure-PoshSshModule $target = Resolve-HomelabIPv4 $Config.HostName $session = New-SSHSession -ComputerName $target -Credential $Config.Credential -AcceptKey -ConnectionTimeout 30 if (-not $session) { throw "SSH-Verbindung zu $($Config.User)@${target} fehlgeschlagen." } return $session } function Invoke-HomelabRemote { param( $Config, [string]$Command, [switch]$Sudo, [string]$WorkDir = "", [int]$TimeoutSeconds = 120 ) if ([string]::IsNullOrWhiteSpace($WorkDir)) { $WorkDir = $Config.AppDir } $remoteCmd = $Command if ($Sudo) { $inner = if ($WorkDir) { "cd '$WorkDir' && $Command" } else { $Command } $escaped = $inner.Replace("'", "'\''") $remoteCmd = "echo '$($Config.SudoPassword)' | sudo -S bash -lc '$escaped'" } elseif ($WorkDir) { $remoteCmd = "cd '$WorkDir' && $Command" } $session = New-HomelabSession $Config try { $result = Invoke-SSHCommand -SessionId $session.SessionId -Command $remoteCmd -TimeOut $TimeoutSeconds return $result } finally { Remove-SSHSession -SessionId $session.SessionId | Out-Null } } function Send-HomelabPath { param( $Config, [string]$LocalPath, [string]$RemoteDir ) Ensure-PoshSshModule $target = Resolve-HomelabIPv4 $Config.HostName $remoteDir = ($RemoteDir.TrimEnd('/') + '/') $sftp = New-SFTPSession -ComputerName $target -Credential $Config.Credential -AcceptKey if (-not $sftp) { throw "SFTP-Verbindung zu ${target} fehlgeschlagen." } try { Set-SFTPItem -SessionId $sftp.SessionId -Path $LocalPath -Destination $remoteDir -Force } finally { Remove-SFTPSession -SessionId $sftp.SessionId | Out-Null } }