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); 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; } } public function loginSSH(): bool { $conn = $this->LoginAuth(); if ($conn) { Log::info('✅ Connected to vCenter via SSH successfully'); return true; } Log::error('❌ Failed to connect to vCenter via SSH'); 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; ' . 'Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false -Scope Session; ' . '$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 ' . '-Command "' . str_replace('"', '\"', $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'; } $esc = fn(string $v) => str_replace("'", "''", $v); $script = strtr( <<<'PS' $ProgressPreference = 'SilentlyContinue' $InformationPreference = 'SilentlyContinue' $WarningPreference = 'SilentlyContinue' $ErrorActionPreference = 'Stop' Import-Module VMware.PowerCLI -ErrorAction Stop Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Scope Session -Confirm:$false | Out-Null Connect-VIServer -Server '' -User '' -Password '' | Out-Null & { } | Out-String PS, [ '' => $esc($this->apiUri ?? ''), '' => $esc($this->username ?? ''), '' => $esc($this->password ?? ''), '' => $cmd, ] ); $encoded = base64_encode(mb_convert_encoding($script, 'UTF-16LE', 'UTF-8')); $action = "powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand $encoded"; 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'; } $esc = fn(string $v) => str_replace("'", "''", $v); $script = strtr( <<<'PS' $ProgressPreference = 'SilentlyContinue' $InformationPreference = 'SilentlyContinue' $WarningPreference = 'SilentlyContinue' $ErrorActionPreference = 'Stop' [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 Import-Module VMware.PowerCLI -ErrorAction Stop Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Scope Session -Confirm:$false | Out-Null Connect-VIServer -Server '' -User '' -Password '' | Out-Null & { } PS, [ '' => $esc($this->apiUri ?? ''), '' => $esc($this->username ?? ''), '' => $esc($this->password ?? ''), '' => $cmd, ] ); $encoded = base64_encode(mb_convert_encoding($script, 'UTF-16LE', 'UTF-8')); $action = "powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand $encoded"; 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(); } } }