where('status', true) ->first(); if (!$infra) { Log::error('SSH Login Failed: No active jumphost configuration found in InfraManagement.'); return false; } $sshHost = $infra->host; $sshPort = 22; if (isset($infra->meta_data['port'])) { $sshPort = (int) $infra->meta_data['port']; } $connection = new SSH2($sshHost, $sshPort); SshHostKeyVerifier::verify($connection, $sshHost); if ($connection->login($infra->username, SignRSA::DecryptFunc($infra->password))) { $connection->setTimeout(0); return $connection; } Log::error('SSH Login Failed: Invalid credentials for jumphost.'); return false; } catch (Exception $error) { Log::error('SSH Login Failed: ' . $error->getMessage()); return false; } } // ─── Command variants ──────────────────────────────────────────────────── /** * Run a PowerShell command using a stored credential file on the jumphost. * Uses C:\secure\vcenter.cred for vCenter auth — no plain-text password in command. */ protected function Command($cmd): string { $auth = $this->LoginAuth(); if (!$auth) { return 'Login_Fail'; } try { $psCommand = 'powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "' . 'Import-Module VMware.PowerCLI; ' . $this->powerCliCertificateLine() . '; ' . '$cred = Import-Clixml -Path \'C:\secure\vcenter.cred\'; ' . 'Connect-VIServer -Server \'' . $this->apiUri . '\' -Credential $cred; ' . $cmd . '; ' . 'Disconnect-VIServer -Confirm:$false" 2>&1'; Log::channel('Custom')->info('PowerShell Command: ' . substr($psCommand, 0, 200) . '...'); $out = $auth->exec($psCommand); $errOut = $auth->getStdError(); Log::channel('Custom')->info('PowerShell Output length: ' . strlen($out)); return $out . ($errOut ? "\n[STDERR]\n" . $errOut : ''); } catch (\Exception $e) { Log::channel('Custom')->error('Command Exception: ' . $e->getMessage()); return $e->getMessage(); } } /** * Run a raw PowerShell command directly — no vCenter connect wrapper. */ public function runPsCommand(string $psCommand): string { $auth = $this->LoginAuth(); if (!$auth) { return 'Login_Fail'; } $action = 'powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand ' . PowerShellEscaper::encodedCommand($psCommand); try { $out = $auth->exec($action); $errOut = $auth->getStdError(); return $out . ($errOut ? "\n[STDERR]\n" . $errOut : ''); } catch (\Throwable $e) { return 'Error: ' . $e->getMessage(); } } /** * Run a command using EncodedCommand — connects to vCenter with plain credentials. * Safer for complex scripts that would break with inline quoting. */ protected function CommandRSP(string $cmd): string { $auth = $this->LoginAuth(); if (!$auth) { return 'Login_Fail'; } $script = strtr( <<<'PS' $ProgressPreference = 'SilentlyContinue' $InformationPreference = 'SilentlyContinue' $WarningPreference = 'SilentlyContinue' $ErrorActionPreference = 'Stop' Import-Module VMware.PowerCLI -ErrorAction Stop Connect-VIServer -Server -User -Password | Out-Null & { } | Out-String PS, [ '' => $this->powerCliCertificateLine(), '' => PowerShellEscaper::singleQuote($this->apiUri ?? ''), '' => PowerShellEscaper::singleQuote($this->username ?? ''), '' => PowerShellEscaper::singleQuote($this->password ?? ''), '' => $cmd, ] ); $action = 'powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand ' . PowerShellEscaper::encodedCommand($script); try { $out = $auth->exec($action); $errOut = $auth->getStdError(); return $out . ($errOut ? "\n[STDERR]\n" . $errOut : ''); } catch (\Throwable $e) { return 'Error: ' . $e->getMessage(); } } /** * Run a command using EncodedCommand — variant used for RDP port changes. * Optionally strips raw output down to the first JSON block found. */ protected function CommandChangePort(string $cmd, bool $expectJson = false): string { $auth = $this->LoginAuth(); if (!$auth) { return 'Login_Fail'; } $script = strtr( <<<'PS' $ProgressPreference = 'SilentlyContinue' $InformationPreference = 'SilentlyContinue' $WarningPreference = 'SilentlyContinue' $ErrorActionPreference = 'Stop' [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 Import-Module VMware.PowerCLI -ErrorAction Stop Connect-VIServer -Server -User -Password | Out-Null & { } PS, [ '' => $this->powerCliCertificateLine(), '' => PowerShellEscaper::singleQuote($this->apiUri ?? ''), '' => PowerShellEscaper::singleQuote($this->username ?? ''), '' => PowerShellEscaper::singleQuote($this->password ?? ''), '' => $cmd, ] ); $action = 'powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand ' . PowerShellEscaper::encodedCommand($script); try { $out = $auth->exec($action); $errOut = $auth->getStdError(); if ($expectJson) { $trimmed = trim($out); if (preg_match('~(\{.*\}|\[.*\])\s*$~s', $trimmed, $m)) { return $m[1]; } return $trimmed; } return $out . ($errOut ? "\n[STDERR]\n" . $errOut : ''); } catch (\Throwable $e) { return 'Error: ' . $e->getMessage(); } } }