diff --git a/pkg/crc/preflight/preflight_daemon_task_check_windows.go b/pkg/crc/preflight/preflight_daemon_task_check_windows.go index 3108d31319..5b74c79bff 100644 --- a/pkg/crc/preflight/preflight_daemon_task_check_windows.go +++ b/pkg/crc/preflight/preflight_daemon_task_check_windows.go @@ -7,11 +7,13 @@ import ( "fmt" "os" "os/user" + "path/filepath" "strings" "github.com/crc-org/crc/pkg/crc/constants" "github.com/crc-org/crc/pkg/crc/logging" "github.com/crc-org/crc/pkg/crc/version" + crcos "github.com/crc-org/crc/pkg/os" "github.com/crc-org/crc/pkg/os/windows/powershell" ) @@ -51,6 +53,43 @@ var ( ` errOlderVersion = fmt.Errorf("expected %s task to be on version '%s'", constants.DaemonTaskName, version.GetCRCVersion()) + + daemonPoshScriptTemplate = `# Following script is from https://stackoverflow.com/a/74976541 +function Hide-ConsoleWindow() { + $ShowWindowAsyncCode = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);' + $ShowWindowAsync = Add-Type -MemberDefinition $ShowWindowAsyncCode -name Win32ShowWindowAsync -namespace Win32Functions -PassThru + + $hwnd = (Get-Process -PID $pid).MainWindowHandle + if ($hwnd -ne [System.IntPtr]::Zero) { + # When you got HWND of the console window: + # (It would appear that Windows Console Host is the default terminal application) + $ShowWindowAsync::ShowWindowAsync($hwnd, 0) + } else { + # When you failed to get HWND of the console window: + # (It would appear that Windows Terminal is the default terminal application) + + # Mark the current console window with a unique string. + $UniqueWindowTitle = New-Guid + $Host.UI.RawUI.WindowTitle = $UniqueWindowTitle + $StringBuilder = New-Object System.Text.StringBuilder 1024 + + # Search the process that has the window title generated above. + $TerminalProcess = (Get-Process | Where-Object { $_.MainWindowTitle -eq $UniqueWindowTitle }) + # Get the window handle of the terminal process. + # Note that GetConsoleWindow() in Win32 API returns the HWND of + # powershell.exe itself rather than the terminal process. + # When you call ShowWindowAsync(HWND, 0) with the HWND from GetConsoleWindow(), + # the Windows Terminal window will be just minimized rather than hidden. + $hwnd = $TerminalProcess.MainWindowHandle + if ($hwnd -ne [System.IntPtr]::Zero) { + $ShowWindowAsync::ShowWindowAsync($hwnd, 0) + } else { + Write-Host "Failed to hide the console window." + } + } +} +Hide-ConsoleWindow +%s` ) func genDaemonTaskInstallTemplate(crcVersion, userName, daemonCommand string) (string, error) { @@ -83,12 +122,7 @@ func fixDaemonTaskInstalled() error { if err := removeDaemonTask(); err != nil { return err } - // prepare the task script - binPath, err := os.Executable() - if err != nil { - return fmt.Errorf("unable to find the current executable location: %v", err) - } - binPathWithArgs := fmt.Sprintf("& '%s' daemon", binPath) + binPathWithArgs := fmt.Sprintf("& '%s'", daemonPoshScriptPath) // Get current user along with domain u, err := user.Current() if err != nil { @@ -170,3 +204,28 @@ func checkIfOlderTask() error { } return nil } + +var daemonPoshScriptPath = filepath.Join(constants.CrcBinDir, "hidden_daemon.ps1") + +func getDaemonPoshScriptContent() []byte { + binPath, err := os.Executable() + if err != nil { + return []byte{} + } + daemonCmd := fmt.Sprintf("%s daemon --log-level debug", binPath) + return []byte(fmt.Sprintf(daemonPoshScriptTemplate, daemonCmd)) +} + +func checkDaemonPoshScript() error { + if exists := crcos.FileExists(daemonPoshScriptPath); exists { + // check the script contains the path to the current executable + if err := crcos.FileContentMatches(daemonPoshScriptPath, getDaemonPoshScriptContent()); err == nil { + return nil + } + } + return fmt.Errorf("Powershell script for running the daemon does not exist") +} + +func fixDaemonPoshScript() error { + return os.WriteFile(daemonPoshScriptPath, getDaemonPoshScriptContent(), 0600) +} diff --git a/pkg/crc/preflight/preflight_windows.go b/pkg/crc/preflight/preflight_windows.go index 1770fc57c2..bcfa9523f1 100644 --- a/pkg/crc/preflight/preflight_windows.go +++ b/pkg/crc/preflight/preflight_windows.go @@ -92,6 +92,17 @@ var vsockChecks = []Check{ } var daemonTaskChecks = []Check{ + { + configKeySuffix: "check-daemon-task-posh-script-present", + checkDescription: "Checking if the daemon task powershell script is present", + check: checkDaemonPoshScript, + fixDescription: "Creating the daemon task powershell script", + fix: fixDaemonPoshScript, + cleanupDescription: "Removing the daemon task powershell script", + cleanup: func() error { return os.Remove(daemonPoshScriptPath) }, + + labels: labels{Os: Windows}, + }, { configKeySuffix: "check-daemon-task-install", checkDescription: "Checking if the daemon task is installed", diff --git a/pkg/crc/preflight/preflight_windows_test.go b/pkg/crc/preflight/preflight_windows_test.go index 0fb97f01e1..8e78aa0352 100644 --- a/pkg/crc/preflight/preflight_windows_test.go +++ b/pkg/crc/preflight/preflight_windows_test.go @@ -13,13 +13,13 @@ import ( func TestCountConfigurationOptions(t *testing.T) { cfg := config.New(config.NewEmptyInMemoryStorage(), config.NewEmptyInMemorySecretStorage()) RegisterSettings(cfg) - assert.Len(t, cfg.AllConfigs(), 13) + assert.Len(t, cfg.AllConfigs(), 14) } func TestCountPreflights(t *testing.T) { - assert.Len(t, getPreflightChecks(false, network.SystemNetworkingMode, constants.GetDefaultBundlePath(preset.OpenShift), preset.OpenShift), 20) - assert.Len(t, getPreflightChecks(true, network.SystemNetworkingMode, constants.GetDefaultBundlePath(preset.OpenShift), preset.OpenShift), 20) + assert.Len(t, getPreflightChecks(false, network.SystemNetworkingMode, constants.GetDefaultBundlePath(preset.OpenShift), preset.OpenShift), 21) + assert.Len(t, getPreflightChecks(true, network.SystemNetworkingMode, constants.GetDefaultBundlePath(preset.OpenShift), preset.OpenShift), 21) - assert.Len(t, getPreflightChecks(false, network.UserNetworkingMode, constants.GetDefaultBundlePath(preset.OpenShift), preset.OpenShift), 19) - assert.Len(t, getPreflightChecks(true, network.UserNetworkingMode, constants.GetDefaultBundlePath(preset.OpenShift), preset.OpenShift), 19) + assert.Len(t, getPreflightChecks(false, network.UserNetworkingMode, constants.GetDefaultBundlePath(preset.OpenShift), preset.OpenShift), 20) + assert.Len(t, getPreflightChecks(true, network.UserNetworkingMode, constants.GetDefaultBundlePath(preset.OpenShift), preset.OpenShift), 20) }