Functions/GenXdev.Webbrowser/Open-Webbrowser.ps1
################################################################################ <# .SYNOPSIS Opens one or more webbrowser instances. .DESCRIPTION Opens one or more webbrowsers in a configurable manner, using commandline switches to control window position, size, and browser-specific features. .PARAMETER Url The URL or URLs to open in the browser. Can be provided via pipeline. .PARAMETER Monitor The monitor to use (0=default, -1=discard, -2=configured secondary). .PARAMETER FullScreen Opens browser in fullscreen mode. .PARAMETER Width Initial width of browser window. .PARAMETER Height Initial height of browser window. .PARAMETER X Initial X position of browser window. .PARAMETER Y Initial Y position of browser window. .PARAMETER AcceptLang Sets browser accept-lang HTTP header. .PARAMETER Private Opens in incognito/private browsing mode. .PARAMETER Force Force enable debugging port, stopping existing browsers if needed. .PARAMETER Edge Opens URLs in Microsoft Edge. .PARAMETER Chrome Opens URLs in Google Chrome. .PARAMETER Chromium Opens URLs in Microsoft Edge or Google Chrome, depending on default browser. .PARAMETER Firefox Opens URLs in Firefox. .PARAMETER All Opens URLs in all registered modern browsers. .PARAMETER Left Places browser window on left side of screen. .PARAMETER Right Places browser window on right side of screen. .PARAMETER Top Places browser window on top of screen. .PARAMETER Bottom Places browser window on bottom of screen. .PARAMETER Centered Places browser window in center of screen. .PARAMETER ApplicationMode Hides browser controls. .PARAMETER NoBrowserExtensions Prevents loading of browser extensions. .PARAMETER DisablePopupBlocker Disable the popup blocker. .PARAMETER RestoreFocus Restores PowerShell window focus after opening browser. .PARAMETER NewWindow Creates new browser window instead of reusing existing one. .PARAMETER PassThru Returns browser process object. .EXAMPLE url from parameter PS> Open-Webbrowser -Chrome -Left -Top -Url "https://genxdev.net/" urls from pipeline PS> @("https://genxdev.net/", "https://github.com/genXdev/") | Open-Webbrowser re-position already open window to primary monitor on right side PS> Open-Webbrowser -Monitor 0 -right re-position already open window to secondary monitor, full screen PS> Open-Webbrowser -Monitor 0 re-position already open window to secondary monitor, left top PS> Open-Webbrowser -Monitor 0 -Left -Top PS> wb -m 0 -left -top .NOTES Requires the Windows 10+ Operating System This cmdlet was mend to be used, interactively. It performs some strange tricks to position windows, including invoking alt-tab keystrokes. It's best not to touch the keyboard or mouse, while it is doing that. For fast launches of multple urls: SET : -Monitor -1 AND : DO NOT use any of these switches: -X, -Y, -Left, -Right, -Top, -Bottom or -RestoreFocus For browsers that are not installed on the system, no actions may be performed or errors occur - at all. #> function Open-Webbrowser { [CmdletBinding()] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidGlobalVars", "")] [Alias("wb")] param( ############################################################################### [parameter( Mandatory = $false, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $false, HelpMessage = "The URLs to open in the browser" )] [Alias("Value", "Uri", "FullName", "Website", "WebsiteUrl")] [string[]] $Url, ############################################################################### [Alias("m", "mon")] [Parameter( Mandatory = $false, Position = 1, HelpMessage = ("The monitor to use, 0 = default, -1 is discard, " + "-2 = Configured secondary monitor, defaults to " + "`Global:DefaultSecondaryMonitor or 2 if not found") )] [int] $Monitor = -2, ############################################################################### [Alias("fs", "f")] [Parameter( Mandatory = $false, Position = 2, HelpMessage = "Opens in fullscreen mode" )] [switch] $FullScreen, ############################################################################### [Parameter( Mandatory = $false, Position = 3, HelpMessage = "The initial width of the webbrowser window" )] [int] $Width = -1, ############################################################################### [Parameter( Mandatory = $false, Position = 4, HelpMessage = "The initial height of the webbrowser window" )] [int] $Height = -1, ############################################################################### [Parameter( Mandatory = $false, Position = 5, HelpMessage = "The initial X position of the webbrowser window" )] [int] $X = -999999, ############################################################################### [Parameter( Mandatory = $false, Position = 6, HelpMessage = "The initial Y position of the webbrowser window" )] [int] $Y = -999999, ############################################################################### [Alias("lang", "locale")] [Parameter( Mandatory = $false, Position = 7, HelpMessage = "Set the browser accept-lang http header" )] [string] $AcceptLang = $null, ############################################################################### [Alias("incognito", "inprivate")] [Parameter( Mandatory = $false, HelpMessage = "Opens in incognito/private browsing mode" )] [switch] $Private, ############################################################################### [Parameter( Mandatory = $false, HelpMessage = ("Force enable debugging port, stopping existing " + "browsers if needed") )] [switch] $Force, ############################################################################### [Alias("e")] [Parameter( Mandatory = $false, HelpMessage = "Opens in Microsoft Edge" )] [switch] $Edge, ############################################################################### [Alias("ch")] [Parameter( Mandatory = $false, HelpMessage = "Opens in Google Chrome" )] [switch] $Chrome, ############################################################################### [Alias("c")] [Parameter( Mandatory = $false, HelpMessage = ("Opens in Microsoft Edge or Google Chrome, depending " + "on what the default browser is") )] [switch] $Chromium, ############################################################################### [Alias("ff")] [Parameter( Mandatory = $false, HelpMessage = "Opens in Firefox" )] [switch] $Firefox, ############################################################################### [Parameter( Mandatory = $false, HelpMessage = "Opens in all registered modern browsers" )] [switch] $All, ############################################################################### [Parameter( Mandatory = $false, HelpMessage = "Place browser window on the left side of the screen" )] [switch] $Left, ############################################################################### [Parameter( Mandatory = $false, HelpMessage = "Place browser window on the right side of the screen" )] [switch] $Right, ############################################################################### [Parameter( Mandatory = $false, HelpMessage = "Place browser window on the top side of the screen" )] [switch] $Top, ############################################################################### [Parameter( Mandatory = $false, HelpMessage = "Place browser window on the bottom side of the screen" )] [switch] $Bottom, ############################################################################### [Parameter( Mandatory = $false, HelpMessage = "Place browser window in the center of the screen" )] [switch] $Centered, ############################################################################### [Alias("a", "app", "appmode")] [Parameter( Mandatory = $false, HelpMessage = "Hide the browser controls" )] [switch] $ApplicationMode, ############################################################################### [Alias("de", "ne", "NoExtensions")] [Parameter( Mandatory = $false, HelpMessage = "Prevent loading of browser extensions" )] [switch] $NoBrowserExtensions, ############################################################################### [Alias("allowpopups")] [Parameter( Mandatory = $false, HelpMessage = "Disable the popup blocker" )] [switch] $DisablePopupBlocker, ############################################################################### [Alias("bg")] [Parameter( Mandatory = $false, HelpMessage = "Restore PowerShell window focus" )] [switch] $RestoreFocus, ############################################################################### [Alias("nw", "new")] [Parameter( Mandatory = $false, HelpMessage = ("Don't re-use existing browser window, instead, " + "create a new one") )] [switch] $NewWindow, ############################################################################### [Parameter( Mandatory = $false, HelpMessage = ("Returns a [System.Diagnostics.Process] object of " + "the browserprocess") )] [switch] $PassThru ) begin { # get all available screens/monitors on the system $allScreens = @([WpfScreenHelper.Screen]::AllScreens | Microsoft.PowerShell.Core\ForEach-Object { $PSItem }) # output diagnostic information about the function call Microsoft.PowerShell.Utility\Write-Verbose ("Open-Webbrowser monitor = $Monitor, " + "urls=$($Url | Microsoft.PowerShell.Utility\ConvertTo-Json)") # track if url parameter was explicitly provided by user [bool] $urlSpecified = $true # check if no url was specified by the user if (($null -eq $Url) -or ($Url.Length -lt 1)) { $urlSpecified = $false # show the default help page from github when no url provided $Url = @("https://powershell.genxdev.net/") } else { # process and normalize each url provided $Url = $($Url | Microsoft.PowerShell.Core\ForEach-Object { # clean up url by trimming quotes and spaces $newUrl = $PSItem.Trim(" `"'".ToCharArray()) $filePath = $newUrl try { # try to expand the path in case it's a relative file path $filePath = (GenXdev.FileSystem\Expand-Path $newUrl) } catch { # ignore expansion errors for urls that aren't file paths } # check if the url refers to an existing local file if ([IO.File]::Exists($filePath)) { # convert local file path to file:// url format $newUrl = ("file://" + [Uri]::EscapeUriString($filePath.Replace("\", "/"))) } $newUrl } ) } # get reference to the powershell main window for focus restoration $powerShellWindow = GenXdev.Windows\Get-PowershellMainWindow # retrieve list of all available/installed modern webbrowsers $browsers = GenXdev.Webbrowser\Get-Webbrowser # get the system's configured default webbrowser $defaultBrowser = GenXdev.Webbrowser\Get-DefaultWebbrowser # set primary monitor as the initial screen reference $screen = [WpfScreenHelper.Screen]::PrimaryScreen $allScreens = @([WpfScreenHelper.Screen]::AllScreens | Microsoft.PowerShell.Core\ForEach-Object { $PSItem }) # determine which monitor to use based on monitor parameter if ($Monitor -eq 0) { Microsoft.PowerShell.Utility\Write-Verbose ("Choosing primary monitor, " + "because default monitor requested using -Monitor 0") } else { # check if secondary monitor was requested and global variable is set if ($Monitor -eq -2 -and $Global:DefaultSecondaryMonitor -is [int] -and $Global:DefaultSecondaryMonitor -ge 0) { Microsoft.PowerShell.Utility\Write-Verbose ("Picking monitor " + "#$((($Global:DefaultSecondaryMonitor-1) % $allScreens.Length)) " + "as secondary (requested with -monitor -2) set by " + "`$Global:DefaultSecondaryMonitor") $screen = $allScreens[($Global:DefaultSecondaryMonitor - 1) % $allScreens.Length] } # check if secondary monitor requested but no global variable set elseif ($Monitor -eq -2 -and (-not ($Global:DefaultSecondaryMonitor -is [int] -and $Global:DefaultSecondaryMonitor -ge 0)) -and ((GenXdev.Windows\Get-MonitorCount) -gt 1)) { Microsoft.PowerShell.Utility\Write-Verbose ("Picking monitor #1 " + "as default secondary (requested with -monitor -2), because " + "`$Global:DefaultSecondaryMonitor not set") $screen = $allScreens[1] } # check if specific monitor number was requested elseif ($Monitor -ge 1) { Microsoft.PowerShell.Utility\Write-Verbose ("Picking monitor " + "#$(($Monitor - 1) % $allScreens.Length) as requested by " + "the -Monitor parameter") $screen = $allScreens[($Monitor - 1) % $allScreens.Length] } else { Microsoft.PowerShell.Utility\Write-Verbose ("Picking monitor #1 " + "(same as PowerShell), because no monitor specified") $screen = [WpfScreenHelper.Screen]::FromPoint(@{ X = $powerShellWindow[0].Position().X Y = $powerShellWindow[0].Position().Y }) } } # determine if any window positioning parameters were provided [bool] $havePositioning = (($Monitor -ge 0 -or $Monitor -eq -2) -or ($Left -or $Right -or $Top -or $Bottom -or $Centered -or (($X -is [int]) -and ($X -gt -999999)) -or (($Y -is [int]) -and ($Y -gt -999999)))) -and -not $FullScreen # initialize window x position based on parameters or screen defaults if (($X -le -999999) -or ($X -isnot [int])) { $X = $screen.WorkingArea.X } else { # adjust x position relative to selected monitor if monitor specified if ($Monitor -ge 0) { $X = $screen.WorkingArea.X + $X } } # initialize window y position based on parameters or screen defaults if (($Y -le -999999) -or ($Y -isnot [int])) { $Y = $screen.WorkingArea.Y } else { # adjust y position relative to selected monitor if monitor specified if ($Monitor -ge 0) { $Y = $screen.WorkingArea.Y + $Y } } # create state object to track browser window positioning and processes $state = @{ existingWindow = $false hadVisibleBrowser = $false Browser = $null IsDefaultBrowser = ((-not $All) -and ((-not $Chromium) -or ($defaultBrowser.Name -like "*chrome*") -or ($defaultBrowser.Name -like "*edge*")) -and ((-not $Chrome) -or ($defaultBrowser.Name -like "*chrome*")) -and ((-not $Edge) -or ($defaultBrowser.Name -like "*edge*")) -and ((-not $Firefox) -or ($defaultBrowser.Name -like "*firefox*"))) FirstProcess = $null PositioningDone = $false BrowserWindow = $null } # determine if we can use simple start-process instead of complex positioning $useStartProcess = (-not ($havePositioning -or $FullScreen)) -and $state.IsDefaultBrowser # configure window dimensions and positioning if positioning is required if ($havePositioning -or $FullScreen) { # check if width parameter was explicitly provided $widthProvided = ($Width -gt 0) -and ($Width -is [int]) # check if height parameter was explicitly provided $heightProvided = ($Height -gt 0) -and ($Height -is [int]) # set default width if not provided by user if ($widthProvided -eq $false) { $Width = $screen.WorkingArea.Width } # set default height if not provided by user if ($heightProvided -eq $false) { $Height = $screen.WorkingArea.Height } # configure window position and size for left side placement if ($Left -eq $true) { $X = $screen.WorkingArea.X # use half screen width if width not explicitly provided if ($widthProvided -eq $false) { $Width = [Math]::Min($screen.WorkingArea.Width / 2, $Width) } # use full screen height if height not explicitly provided if ($heightProvided -eq $false) { $Height = [Math]::Min($screen.WorkingArea.Height, $Height) } $Y = $screen.WorkingArea.Y return } # configure window position and size for right side placement if ($Right -eq $true) { # use half screen width if width not explicitly provided if ($widthProvided -eq $false) { $Width = [Math]::Min($screen.WorkingArea.Width / 2, $Width) } # position window on right side of screen $X = $screen.WorkingArea.X + $screen.WorkingArea.Width - $Width $Y = ($screen.WorkingArea.Y + [Math]::Round(($screen.WorkingArea.Height - $Height) / 2, 0)) # use full screen height if height not explicitly provided if ($heightProvided -eq $false) { $Height = [Math]::Min($screen.WorkingArea.Height, $Height) } $Y = $screen.WorkingArea.Y return } # configure window position and size for top placement if ($Top -eq $true) { $Y = $screen.WorkingArea.Y # use half screen height if height not explicitly provided if ($heightProvided -eq $false) { $Height = [Math]::Min($screen.WorkingArea.Height / 2, $Height) $X = $screen.WorkingArea.X } $Width = $screen.WorkingArea.Width $X = $screen.WorkingArea.X return } # configure window position and size for bottom placement if ($Bottom -eq $true) { # use half screen height if height not explicitly provided if ($heightProvided -eq $false) { $Height = [Math]::Min($screen.WorkingArea.Height / 2, $Height) } $Width = $screen.WorkingArea.Width # position window at bottom of screen $Y = $screen.WorkingArea.Y + $screen.WorkingArea.Height - $Height $X = $screen.WorkingArea.X return } # configure window position and size for centered placement if ($Centered -eq $true) { # use 80% of screen height if height not explicitly provided if ($heightProvided -eq $false) { $Height = [Math]::Round([Math]::Min( $screen.WorkingArea.Height * 0.8, $Height), 0) } # use 80% of screen width if width not explicitly provided if ($widthProvided -eq $false) { $Width = [Math]::Round([Math]::Min( $screen.WorkingArea.Width * 0.8, $Width), 0) } # center window on screen $X = ($screen.WorkingArea.X + [Math]::Round(($screen.WorkingArea.Width - $Width) / 2, 0)) $Y = ($screen.WorkingArea.Y + [Math]::Round(($screen.WorkingArea.Height - $Height) / 2, 0)) return } } } ########################################################################### process { ########################################################################### <# .SYNOPSIS Ensures minimum delay between browser window close and open operations. .DESCRIPTION This helper function prevents timing issues when repositioning browser windows by enforcing a minimum delay since the last browser close. .PARAMETER browser The browser object to check timing delays for. #> function enforceMinimumDelays($browser) { # skip delay enforcement if no positioning is required if ($havePositioning -eq $false) { return } # get the last close time for this specific browser $last = (Microsoft.PowerShell.Utility\Get-Variable -Scope Global ` -Name "_LastClose$($browser.Name)" -ErrorAction SilentlyContinue) # check if we have a valid last close timestamp if (($null -ne $last) -and ($last.Value -is [DateTime])) { $now = [DateTime]::UtcNow # enforce minimum 1 second delay since last close if ($now - $last.Value -lt [System.TimeSpan]::FromSeconds(1)) { $null = [System.Threading.Thread]::Sleep(200) } } } ########################################################################### <# .SYNOPSIS Constructs browser-specific command line arguments. .DESCRIPTION Builds the appropriate command line argument list based on the browser type and user-specified parameters for launching the browser process. .PARAMETER browser The browser object containing executable path and type information. .PARAMETER currentUrl The URL to open in the browser. .PARAMETER state The state object tracking browser window positioning and process info. #> function constructArgumentList($browser, $currentUrl, $state) { # initialize empty argument list for browser command line $argumentList = @() ################################################################### # handle firefox-specific command line arguments if ($browser.Name -like "*Firefox*") { # set default firefox command line parameters $argumentList = @() # add window size parameters if both width and height specified if (($Width -is [int]) -and ($Width -gt 0) -and ($Height -is [int]) -and ($Height -gt 0)) { $argumentList = $argumentList + @("-width", $Width, "-height", $Height) } # set foreground mode unless restore focus is requested if ($RestoreFocus -ne $true) { # set firefox to foreground on startup $argumentList = $argumentList + @("-foreground") } # disable browser extensions if requested if ($NoBrowserExtensions -eq $true) { $argumentList = $argumentList + @("-safe-mode") } # disable popup blocker if requested if ($DisablePopupBlocker -eq $true) { $argumentList = $argumentList + @("-disable-popup-blocking") } # set accept language header if provided if ($null -ne $AcceptLang) { $argumentList = $argumentList + @("--lang", $AcceptLang) } # handle private browsing mode for firefox if ($Private -eq $true) { # open url in firefox private window $argumentList = $argumentList + @("-private-window", $currentUrl) } else { # handle application mode for firefox if ($ApplicationMode -eq $true) { Microsoft.PowerShell.Utility\Write-Warning ("Firefox " + "does not support -ApplicationMode at this time") GenXdev.Webbrowser\Approve-FirefoxDebugging # use single site browser mode for firefox app mode $argumentList = $argumentList + @("--ssb", $currentUrl) } else { # handle new window creation for firefox if ((-not $state.PositioningDone) -and ($NewWindow -eq $true)) { # create new firefox window with url $argumentList = $argumentList + @("--new-window", $currentUrl) } else { # open url in existing or new firefox tab $argumentList = $argumentList + @("-url", $currentUrl) } } } } else { ############################################################### # handle chromium-based browsers (edge and chrome) if ($browser.Name -like "*Edge*" -or $browser.Name -like "*Chrome*") { # get the appropriate debugging port for this browser type $port = GenXdev.Webbrowser\Get-ChromiumRemoteDebuggingPort ` -Chrome:$Chrome -Edge:$Edge # set default chromium command line parameters # reference: https://peter.sh/experiments/chromium-command-line-switches/ $argumentList = $argumentList + @( "--disable-infobars", "--hide-crash-restore-bubble", "--no-first-run", "--disable-session-crashed-bubble", "--disable-crash-reporter", "--no-default-browser-check", "--disable-restore-tabs", "--remote-allow-origins=*", "--remote-debugging-port=$port" ) # add window size if both dimensions are specified if (($Width -is [int]) -and ($Width -gt 0) -and ($Height -is [int]) -and ($Height -gt 0)) { $argumentList = $argumentList + @("--window-size=$Width,$Height") } # set initial window position $argumentList = $argumentList + @("--window-position=$X,$Y") # disable browser extensions if requested if ($NoBrowserExtensions -eq $true) { $argumentList = $argumentList + @("--disable-extensions") } # disable popup blocker if requested if ($DisablePopupBlocker -eq $true) { $argumentList = $argumentList + @("--disable-popup-blocking") } # set accept language header if provided if ($null -ne $AcceptLang) { $argumentList = $argumentList + @("--accept-lang=$AcceptLang") } # handle private browsing mode for chromium browsers if ($Private -eq $true) { # force new window for private mode $NewWindow = $true # set appropriate private browsing flag if ($browser.Name -like "*Edge*") { # use edge inprivate mode $argumentList = $argumentList + @("-InPrivate") } else { # use chrome incognito mode $argumentList = $argumentList + @("--incognito") } } # force new window creation if requested and not positioned yet if ((-not $state.PositioningDone) -and ($NewWindow -eq $true)) { # force creation of new browser window $argumentList = $argumentList + @("--new-window") + @("--force-launch-browser") } # set window to start maximized by default $argumentList = $argumentList + @("--start-maximized") # handle application mode for chromium browsers if ($ApplicationMode -eq $true) { # run browser in application mode with specific url $argumentList = $argumentList + @("--app=$currentUrl") } else { # add url to standard command line arguments $argumentList = $argumentList + @($currentUrl) } } else { ########################################################### # handle default/other browsers if ($Private -eq $true) { # private mode not supported for default browser return } # add url as only argument for default browser $argumentList = @($currentUrl) } } $argumentList } ########################################################################### <# .SYNOPSIS Finds and returns the browser process and main window. .DESCRIPTION Locates the browser process after launch and gets a reference to its main window handle for positioning and management operations. .PARAMETER browser The browser object containing executable information. .PARAMETER process The initial process object from browser launch. .PARAMETER state The state object tracking browser window and process information. #> function findProcess($browser, $process, $state) { # initialize window tracking variables $state.existingWindow = $false $window = @() # retry loop to find the browser process and window do { try { # wait briefly for process to initialize $null = [System.Threading.Thread]::Sleep(100) # find the most recent browser process with main window $processesNew = @(Microsoft.PowerShell.Management\Get-Process ` ([IO.Path]::GetFileNameWithoutExtension($browser.Path)) ` -ErrorAction SilentlyContinue | Microsoft.PowerShell.Core\Where-Object -Property Path ` -EQ $browser.Path | Microsoft.PowerShell.Core\Where-Object -Property MainWindowHandle ` -NE 0 | Microsoft.PowerShell.Utility\Sort-Object ` { $PSItem.StartTime } -Descending | Microsoft.PowerShell.Utility\Select-Object -First 1) # check if no process was found if (($processesNew.Length -eq 0) -or ($null -eq $processesNew[0])) { Microsoft.PowerShell.Utility\Write-Verbose ("No process " + "found, retrying..") $window = @() $null = [System.Threading.Thread]::Sleep(80) } else { Microsoft.PowerShell.Utility\Write-Verbose "Found new process" # get window helper utility for main window of process $state.existingWindow = $state.hadVisibleBrowser $process = $processesNew[0] $window = [GenXdev.Helpers.WindowObj]::GetMainWindow($process, 1, 80) break } } catch { Microsoft.PowerShell.Utility\Write-Verbose ("Error: " + "$($_.Exception.Message)") $window = @() $null = [System.Threading.Thread]::Sleep(100) } } while (($i++ -lt 50) -and ($window.length -le 0)) # return process and window information @{ Process = $process Window = $window } } ########################################################################### <# .SYNOPSIS Opens a browser with the specified URL and configuration. .DESCRIPTION Launches a browser process with the provided URL and handles window positioning, process management, and browser-specific configurations. .PARAMETER browser The browser object containing executable path and type information. .PARAMETER currentUrl The URL to open in the browser. .PARAMETER state The state object tracking browser positioning and process information. #> function open($browser, $currentUrl, $state) { Microsoft.PowerShell.Utility\Write-Verbose "open()" # determine if this browser is the system default $state.IsDefaultBrowser = $browser -eq $defaultBrowser # enforce timing delays for proper window positioning enforceMinimumDelays $browser # initialize browser launch variables $startBrowser = $true $state.hadVisibleBrowser = $false $process = $null # find any existing browser process with main window $prcBefore = @(Microsoft.PowerShell.Management\Get-Process ` ([IO.Path]::GetFileNameWithoutExtension($browser.Path)) ` -ErrorAction SilentlyContinue) | Microsoft.PowerShell.Core\Where-Object -Property Path -EQ $browser.Path | Microsoft.PowerShell.Core\Where-Object -Property MainWindowHandle -NE 0 | Microsoft.PowerShell.Utility\Sort-Object { $PSItem.StartTime } -Descending | Microsoft.PowerShell.Utility\Select-Object -First 1 # check if existing browser window was found if ($state.PositioningDone -or (($prcBefore.Length -ge 1) -and ($null -ne $prcBefore[0]))) { Microsoft.PowerShell.Utility\Write-Verbose ("Found existing " + "webbrowser window") $state.hadVisibleBrowser = $true } # determine if we should skip launching new browser process if ((-not $NewWindow) -and (-not ($havePositioning -or $FullScreen)) -and (-not $urlSpecified)) { if ($state.hadVisibleBrowser) { Microsoft.PowerShell.Utility\Write-Verbose ("No url specified, " + "found existing webbrowser window") $startBrowser = $false $process = if ($state.FirstProcess) { $state.FirstProcess } else { $prcBefore[0] } } } # launch new browser process if needed if ($startBrowser) { # handle force parameter to ensure debug port availability if ($Force) { try { # try to get existing browser tabs with debug port $a = GenXdev.Webbrowser\Select-WebbrowserTab ` -Chrome:$Chrome -Edge:$Edge } catch { $a = @() } # close all browser instances if no debug port found if ($a.length -eq 0 -or ($a -is [string])) { Microsoft.PowerShell.Utility\Write-Verbose ("No browser " + "with open debugger port found, closing all browser " + "instances and starting a new one") $null = Microsoft.PowerShell.Management\Get-Process ` -Name ([IO.Path]::GetFileNameWithoutExtension($browser.Path)) ` -ErrorAction SilentlyContinue | Microsoft.PowerShell.Management\Stop-Process -Force ` -ErrorAction SilentlyContinue } } # check if any browser processes currently exist $currentProcesses = @((Microsoft.PowerShell.Management\Get-Process ` -Name ([IO.Path]::GetFileNameWithoutExtension($browser.Path)) ` -ErrorAction SilentlyContinue)) if ($currentProcesses.Count -eq 0) { $NewWindow = $false } # get browser-specific command line arguments $argumentList = constructArgumentList $browser $currentUrl $state # output verbose information about browser launch Microsoft.PowerShell.Utility\Write-Verbose ("$($browser.Name) --> " + "$($argumentList | Microsoft.PowerShell.Utility\ConvertTo-Json)") # start the browser process with constructed arguments $process = Microsoft.PowerShell.Management\Start-Process ` -FilePath ($browser.Path) -ArgumentList $argumentList -PassThru # wait briefly for process to initialize $null = $process.WaitForExit(200) $null = [System.Threading.Thread]::Sleep(200) } # validate that we have a valid process if ($null -eq $process) { Microsoft.PowerShell.Utility\Write-Warning ("Could not start " + "browser $($browser.Name)") return } # skip positioning if not needed or already done if ((-not $PassThru) -and ((-not ($havePositioning -or ($FullScreen -and -not $state.PositioningDone))) -or $state.PositioningDone)) { Microsoft.PowerShell.Utility\Write-Verbose ("No positioning " + "required, done..") return } # return process object if passthru requested if ($PassThru) { # return first process if positioning done and process available if (($state.PositioningDone -or ((-not $FullScreen) -and (-not $havePositioning))) -and ($null -ne $state.FirstProcess) -and (-not $state.FirstProcess.HasExited) -and ($state.FirstProcess.MainWindowHandle -ne 0)) { Microsoft.PowerShell.Utility\Write-Verbose ("Returning " + "first process") Microsoft.PowerShell.Utility\Write-Output $state.FirstProcess return } # return current process if valid and has window if (($null -ne $process) -and (-not $process.HasExited) -and ($process.MainWindowHandle -ne 0)) { Microsoft.PowerShell.Utility\Write-Verbose "Returning process" Microsoft.PowerShell.Utility\Write-Output $process if (-not $havePositioning) { return } } } # allow browser startup time and update process handle if needed enforceMinimumDelays $browser $browserFound = findProcess $browser $process $state $process = $browserFound.Process $window = $browserFound.Window # return process after lookup if passthru requested if (($PassThru -eq $true) -and ($null -ne $process)) { Microsoft.PowerShell.Utility\Write-Verbose ("Returning process " + "after process lookup") Microsoft.PowerShell.Utility\Write-Output $process } # skip positioning if not required or already completed if ((-not ($havePositioning -or ($FullScreen -and -not $state.PositioningDone))) -or $state.PositioningDone) { Microsoft.PowerShell.Utility\Write-Verbose ("No positioning " + "required, done..") return } # mark positioning as completed and store first process $state.PositioningDone = $true $state.FirstProcess = $process # position browser window if we have a valid window handle if ($window.Length -eq 1) { # store browser window reference for later use $state.BrowserWindow = $window[0] Microsoft.PowerShell.Utility\Write-Verbose ("Restoring and " + "positioning browser window") # restore window if not in fullscreen mode if (-not $FullScreen) { $null = $window[0].Show() $null = $window[0].Restore() } # move and resize window to specified position and dimensions $null = $window[0].Move($X, $Y, $Width, $Height) } # wait for window positioning to complete Microsoft.PowerShell.Utility\Start-Sleep 2 } # initialize url processing index counter $index = -1 try { # iterate through each url that needs to be opened foreach ($currentUrl in $Url) { $index++ Microsoft.PowerShell.Utility\Write-Verbose "Opening $currentUrl" # use simple start-process for default browser without positioning if ($useStartProcess -or (($index -gt 0) -and ($state.IsDefaultBrowser))) { Microsoft.PowerShell.Utility\Write-Verbose "Start-Process" # launch default browser with simple start-process method $process = Microsoft.PowerShell.Management\Start-Process $currentUrl ` -PassThru # return process if passthru requested for first launch if ($PassThru -and $useStartProcess -and ($index -eq 0)) { $browserFound = findProcess $defaultBrowser $process $state $process = $browserFound.Process $window = $browserFound.Window Microsoft.PowerShell.Utility\Write-Verbose ("Returning " + "process after Start-Process") Microsoft.PowerShell.Utility\Write-Output $process } continue } # handle opening url in all available browsers if ($All -eq $true) { # open current url in all installed browsers $browsers | Microsoft.PowerShell.Core\ForEach-Object { open $PSItem $currentUrl $state } continue } # handle chrome-specific browser selection elseif ($Chrome -eq $true) { # find and open chrome browser instances $browsers | Microsoft.PowerShell.Core\ForEach-Object { # check if this is a chrome browser if ($PSItem.Name -like "*Chrome*") { # open url in chrome open $PSItem $currentUrl $state } } } # handle edge-specific browser selection elseif ($Edge -eq $true) { # find and open edge browser instances $browsers | Microsoft.PowerShell.Core\ForEach-Object { # check if this is an edge browser if ($PSItem.Name -like "*Edge*") { # open url in edge open $PSItem $currentUrl $state } } } # handle chromium-based browser preference (edge or chrome) elseif ($Chromium -eq $true) { # check if default browser is already chromium-based if (($defaultBrowser.Name -like "*Chrome*") -or ($defaultBrowser.Name -like "*Edge*")) { # use default browser since it's already chromium-based open $defaultBrowser $currentUrl $state continue } # find available chromium-based browsers $browsers | Microsoft.PowerShell.Utility\Sort-Object { $PSItem.Name } ` -Descending | Microsoft.PowerShell.Core\ForEach-Object { # check if this is a chromium-based browser if (($PSItem.Name -like "*Chrome*") -or ($PSItem.Name -like "*Edge*")) { # open url in chromium-based browser open $PSItem $currentUrl $state } } } # handle firefox-specific browser selection if ($Firefox -eq $true) { # find and open firefox browser instances $browsers | Microsoft.PowerShell.Core\ForEach-Object { # check if this is a firefox browser if ($PSItem.Name -like "*Firefox*") { # open url in firefox open $PSItem $currentUrl $state } } } # use default browser when no specific browser requested if (($Chromium -ne $true) -and ($Chrome -ne $true) -and ($Edge -ne $true) -and ($Firefox -ne $true)) { # open url in system default browser open $defaultBrowser $currentUrl $state } } } finally { # handle fullscreen mode activation after all urls processed if ($FullScreen -eq $true) { Microsoft.PowerShell.Utility\Write-Verbose "Setting fullscreen" # use browser window reference if available if ($null -ne $state.BrowserWindow) { Microsoft.PowerShell.Utility\Write-Verbose ("Changing focus " + "to browser window") try { $null = $state.BrowserWindow.Maximize() $null = $state.BrowserWindow.SetForeground() } catch { # ignore window manipulation errors } $tt = 0 $focusedWindowProcess = GenXdev.Windows\Get-CurrentFocusedProcess # wait for browser window to receive focus while (($tt++ -lt 20) -and (($null -eq $focusedWindowProcess) -or ($focusedWindowProcess.MainWindowHandle -ne $state.BrowserWindow.Handle))) { Microsoft.PowerShell.Utility\Write-Verbose ("have browser " + "window, sleeping 500ms") $null = [System.Threading.Thread]::Sleep(500) try { $null = $state.BrowserWindow.Maximize() $null = $state.BrowserWindow.SetForeground() } catch { # ignore window manipulation errors } $null = GenXdev.Windows\Set-ForegroundWindow ` ($state.BrowserWindow.Handle) $focusedWindowProcess = GenXdev.Windows\Get-CurrentFocusedProcess } } else { Microsoft.PowerShell.Utility\Write-Verbose ("Setting " + "fullscreen without having reference to browser window") $tt = 0 $focusedWindowProcess = GenXdev.Windows\Get-CurrentFocusedProcess $powershellWindow = GenXdev.Windows\Get-PowershellMainWindow # wait for powershell window focus before sending f11 while (($tt++ -lt 20) -and (($null -eq $focusedWindowProcess) -or ($null -eq $powerShellWindow) -or ($focusedWindowProcess.MainWindowHandle -ne $powerShellWindow.Handle))) { Microsoft.PowerShell.Utility\Write-Verbose ("no browser " + "window, sleeping 500ms") $null = [System.Threading.Thread]::Sleep(500) $focusedWindowProcess = GenXdev.Windows\Get-CurrentFocusedProcess $powershellWindow = GenXdev.Windows\Get-PowershellMainWindow } } # send f11 key to activate fullscreen if browser has focus if ((GenXdev.Windows\Get-CurrentFocusedProcess).MainWindowHandle -ne (GenXdev.Windows\Get-PowershellMainWindow).Handle) { try { # create com object to send f11 key press $helper = Microsoft.PowerShell.Utility\New-Object ` -ComObject WScript.Shell $null = $helper.sendKeys("{F11}") Microsoft.PowerShell.Utility\Write-Verbose "Sending F11" $null = [System.Threading.Thread]::Sleep(500) } catch { # ignore key sending errors } } } } } ########################################################################### end { # restore powershell window focus if requested if ($RestoreFocus) { # get reference to powershell main window $powerShellWindow = GenXdev.Windows\Get-PowershellMainWindow # restore focus to powershell window if it exists if ($null -ne $powerShellWindow) { # wait briefly before restoring focus $null = [System.Threading.Thread]::Sleep(500) # show and bring powershell window to foreground $null = $powerShellWindow.Show() $null = $powerShellWindow.SetForeground() # ensure powershell window receives focus $null = GenXdev.Windows\Set-ForegroundWindow ` ($powerShellWindow.Handle) } } } } ################################################################################ |