Functions/GenXdev.Webbrowser/Select-WebbrowserTab.ps1
################################################################################ <# .SYNOPSIS Selects a browser tab for automation in Chrome or Edge. .DESCRIPTION Manages browser tab selection for automation tasks. Can select tabs by ID, name, or reference. Shows available tabs when no selection criteria are provided. Supports both Chrome and Edge browsers. Handles browser connection and session management. This function provides comprehensive tab selection capabilities for web browser automation. It can list available tabs, select specific tabs by various criteria, and establish automation connections to the selected tab. The function supports both Chrome and Edge browsers with debugging capabilities enabled. Key features: - Tab selection by numeric ID, URL pattern, or session reference - Automatic browser detection and connection establishment - Session management with state preservation - Force restart capabilities when debugging ports are unavailable - Integration with browser automation frameworks .PARAMETER Id Numeric identifier for the tab, shown when listing available tabs. .PARAMETER Name URL pattern to match when selecting a tab. Selects first matching tab. .PARAMETER ByReference Session reference object from Get-ChromiumSessionReference to select specific tab. .PARAMETER Monitor The monitor to use for window placement: - 0 = Primary monitor - -1 = Discard positioning - -2 = Configured secondary monitor (uses $Global:DefaultSecondaryMonitor or defaults to monitor 2) - 1+ = Specific monitor number .PARAMETER Width The initial width of the browser window in pixels. .PARAMETER Height The initial height of the browser window in pixels. .PARAMETER X The initial X coordinate for window placement. .PARAMETER Y The initial Y coordinate for window placement. .PARAMETER AcceptLang Sets the browser's Accept-Language HTTP header for internationalization. .PARAMETER FullScreen Opens the browser in fullscreen mode using F11 key simulation. .PARAMETER Private Opens the browser in private/incognito browsing mode. .PARAMETER Chromium Opens URLs in either Microsoft Edge or Google Chrome, depending on which is set as the default browser. .PARAMETER Firefox Specifically opens URLs in Mozilla Firefox browser. .PARAMETER All Opens the specified URLs in all installed modern browsers simultaneously. .PARAMETER Left Positions the browser window on the left half of the screen. .PARAMETER Right Positions the browser window on the right half of the screen. .PARAMETER Top Positions the browser window on the top half of the screen. .PARAMETER Bottom Positions the browser window on the bottom half of the screen. .PARAMETER Centered Centers the browser window on the screen using 80% of the screen dimensions. .PARAMETER ApplicationMode Hides browser controls for a distraction-free experience. .PARAMETER NoBrowserExtensions Prevents loading of browser extensions. .PARAMETER DisablePopupBlocker Disables the browser's popup blocking functionality. .PARAMETER RestoreFocus Returns focus to the PowerShell window after opening the browser. .PARAMETER NewWindow Forces creation of a new browser window instead of reusing existing windows. .PARAMETER FocusWindow Gives focus to the browser window after opening. .PARAMETER SetForeground Brings the browser window to the foreground after opening. .PARAMETER Maximize Maximizes the browser window after positioning. .PARAMETER KeysToSend Keystrokes to send to the browser window after opening. .PARAMETER SendKeyEscape Escapes control characters when sending keystrokes to the browser. .PARAMETER SendKeyHoldKeyboardFocus Prevents returning keyboard focus to PowerShell after sending keystrokes. .PARAMETER SendKeyUseShiftEnter Uses Shift+Enter instead of regular Enter for line breaks when sending keys. .PARAMETER SendKeyDelayMilliSeconds Delay between sending different key sequences in milliseconds. .PARAMETER Edge Switch to force selection in Microsoft Edge browser. .PARAMETER Chrome Switch to force selection in Google Chrome browser. .PARAMETER Force Switch to force browser restart if needed during selection. .EXAMPLE Select-WebbrowserTab -Id 3 -Chrome -Force Selects tab ID 3 in Chrome browser, forcing restart if needed. .EXAMPLE st -Name "github.com" -e Selects first tab containing "github.com" in Edge browser using alias. #> function Select-WebbrowserTab { [CmdletBinding(DefaultParameterSetName = 'ById')] [OutputType([string], [PSCustomObject])] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')] [Alias('st', 'Select-BrowserTab')] param( ######################################################################## [Parameter( Mandatory = $false, Position = 0, ParameterSetName = 'ById', HelpMessage = 'Tab identifier from the shown list' )] [ValidateRange(0, [int]::MaxValue)] [int] $Id = -1, ######################################################################## [Parameter( Mandatory = $true, Position = 0, ParameterSetName = 'ByName', HelpMessage = 'Selects first tab containing this name in URL' )] [ValidateNotNullOrEmpty()] [SupportsWildcards()] [string] $Name, ######################################################################## [Parameter( ParameterSetName = 'ByReference', Mandatory = $true, HelpMessage = 'Select tab using reference from Get-ChromiumSessionReference' )] [ValidateNotNull()] [PSCustomObject] $ByReference, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = ('The monitor to use, 0 = default, -1 is discard, ' + '-2 = Configured secondary monitor, defaults to ' + "`$Global:DefaultSecondaryMonitor or 2 if not found") )] [Alias('m', 'mon')] [int] $Monitor, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'The initial width of the webbrowser window' )] [int] $Width, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'The initial height of the webbrowser window' )] [int] $Height, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'The initial X position of the webbrowser window' )] [int] $X, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'The initial Y position of the webbrowser window' )] [int] $Y, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Set the browser accept-lang http header' )] [Alias('lang', 'locale')] [string] $AcceptLang, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Opens in fullscreen mode' )] [Alias('fs', 'f')] [switch] $FullScreen, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Opens in incognito/private browsing mode' )] [Alias('incognito', 'inprivate')] [switch] $Private, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = ('Opens in Microsoft Edge or Google Chrome, ' + 'depending on what the default browser is') )] [Alias('c')] [switch] $Chromium, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Opens in Firefox' )] [Alias('ff')] [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, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Hide the browser controls' )] [Alias('a', 'app', 'appmode')] [switch] $ApplicationMode, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Prevent loading of browser extensions' )] [Alias('de', 'ne', 'NoExtensions')] [switch] $NoBrowserExtensions, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Disable the popup blocker' )] [Alias('allowpopups')] [switch] $DisablePopupBlocker, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Restore PowerShell window focus' )] [Alias('rf', 'bg')] [switch] $RestoreFocus, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = ("Don't re-use existing browser window, instead, " + 'create a new one') )] [Alias('nw', 'new')] [switch] $NewWindow, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Focus the browser window after opening' )] [Alias('fw','focus')] [switch] $FocusWindow, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Set the browser window to foreground after opening' )] [Alias('fg')] [switch] $SetForeground, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Maximize the window after positioning' )] [switch] $Maximize, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = ('Keystrokes to send to the Browser window, ' + 'see documentation for cmdlet GenXdev.Windows\Send-Key') )] [string[]] $KeysToSend, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Escape control characters when sending keys' )] [Alias('Escape')] [switch] $SendKeyEscape, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = ('Prevent returning keyboard focus to PowerShell ' + 'after sending keys') )] [Alias('HoldKeyboardFocus')] [switch] $SendKeyHoldKeyboardFocus, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = ('Send Shift+Enter instead of regular Enter for ' + 'line breaks') )] [Alias('UseShiftEnter')] [switch] $SendKeyUseShiftEnter, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = ('Delay between sending different key sequences ' + 'in milliseconds') )] [Alias('DelayMilliSeconds')] [int] $SendKeyDelayMilliSeconds, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Opens in Microsoft Edge' )] [Alias('e')] [switch] $Edge, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Opens in Google Chrome' )] [Alias('ch')] [switch] $Chrome, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Forces browser restart if needed' )] [switch] $Force ) begin { # store existing sessions from global state $sessions = $Global:chromeSessions ? $Global:chromeSessions : @() # determine debugging port based on browser selection or reference $debugPort = if ($null -ne $ByReference) { $ByReference.webSocketDebuggerUrl -replace 'ws://localhost:(\d+)/.*', '$1' } elseif ($Edge) { GenXdev.Webbrowser\Get-EdgeRemoteDebuggingPort } elseif ($Chrome) { GenXdev.Webbrowser\Get-ChromeRemoteDebuggingPort } else { GenXdev.Webbrowser\Get-ChromiumRemoteDebuggingPort } # ensure global state storage exists if ($Global:Data -isnot [HashTable]) { $Global:Data = @{} } Microsoft.PowerShell.Utility\Write-Verbose "Using browser debugging port: $debugPort" } process { # helper function to display available browser tabs function Show-TabList { $index = 0 $Global:chromeSessions | Microsoft.PowerShell.Core\ForEach-Object { if (![String]::IsNullOrWhiteSpace($PSItem.url)) { # mark current tab with asterisk $bullet = $PSItem.id -eq ` $Global:chromeSession.id ? '*' : ' ' $url = $PSItem.url $title = $PSItem.title [PSCustomObject]@{ id = $index A = $bullet url = $url title = $title } $index++ } } } # create or update automation connection if needed if ($Global:chrome -isnot [Hashtable] -or $Global:chrome.Port -ne $debugPort -or $null -eq $Global:chrome.Browser -or (-not $Global:chrome.Browser.IsConnected)) { Microsoft.PowerShell.Utility\Write-Verbose 'Establishing new browser automation connection' $Global:chrome = @{ Debugurl = "http://localhost:$debugPort" Port = $debugPort Browser = GenXdev.Webbrowser\Connect-PlaywrightViaDebuggingPort ` -WsEndpoint "http://localhost:$debugPort" } $Global:CurrentChromiumDebugPort = $debugPort } # handle tab selection by name or show available tabs if (($null -eq $ByReference -and $Id -lt 0) -or ![string]::IsNullOrWhiteSpace($Name)) { Microsoft.PowerShell.Utility\Write-Verbose 'Retrieving list of available browser tabs' try { # get all page tabs from browser $sessions = @( (Microsoft.PowerShell.Utility\Invoke-WebRequest -Uri "http://localhost:$debugPort/json").Content | Microsoft.PowerShell.Utility\ConvertFrom-Json | Microsoft.PowerShell.Core\Where-Object -Property 'type' -EQ 'page' ) $Global:chromeSessions = $sessions } catch { if ($Force -and ($null -eq $ByReference)) { # force browser restart if requested $null = GenXdev.Webbrowser\Close-Webbrowser -Chrome:$Chrome -Edge:$Edge -Force -Chromium # copy identical parameters between functions $invocationArguments = GenXdev.Helpers\Copy-IdenticalParamValues ` -BoundParameters $PSBoundParameters ` -FunctionName 'GenXdev.Webbrowser\Open-Webbrowser' ` -DefaultValues (Microsoft.PowerShell.Utility\Get-Variable -Scope Local -Name * ` -ErrorAction SilentlyContinue) # set url if name was provided if (-not [string]::IsNullOrWhiteSpace($Name)) { $invocationArguments.Url = $Name } $invocationArguments.Force = $true $invocationArguments.Chromium = $true $null = GenXdev.Webbrowser\Open-Webbrowser @invocationArguments # prepare parameters for recursive call $invocationArguments = GenXdev.Helpers\Copy-IdenticalParamValues ` -BoundParameters $PSBoundParameters ` -FunctionName 'GenXdev.Webbrowser\Select-WebbrowserTab' ` -DefaultValues (Microsoft.PowerShell.Utility\Get-Variable -Scope Local -Name * ` -ErrorAction SilentlyContinue) $invocationArguments.Force = $false } else { return 'No browser available with open debugging port, use -Force to restart' } # reset global state $Global:chromeSessions = @() $Global:chromeController = $null $Global:chrome = $null $Global:chromeSession = $null return } $Global:chromeSessions = $sessions Microsoft.PowerShell.Utility\Write-Verbose "Found $($sessions.Count) browser tabs" # ensure we have at least one session if ($sessions.Count -eq 0) { Microsoft.PowerShell.Utility\Write-Warning 'No browser sessions found' $Global:chromeSession = $null return 'No browser sessions available' } # find matching session based on criteria $sessionId = 0 while ($sessionId -lt ($sessions.Count - 1) -and ( (![string]::IsNullOrWhiteSpace($Name) -and ($sessions[$sessionId].url -notlike "$Name")) -or (($null -ne $ByReference) -and ($sessions[$sessionId].id -ne $ByReference.id)) )) { Microsoft.PowerShell.Utility\Write-Verbose "Skipping tab: $($sessions[$sessionId].url)" $sessionId++ } $sessionId = [Math]::Min($sessionId, $sessions.Count - 1) # preserve session data when switching tabs $origId = $Global:chromeSession ? $Global:chromeSession.id : $null; $origData = $Global:chromeSession ? $Global:chromeSession.data : $null; $Global:chromeSession = $sessions[$sessionId] # validate that we have a valid session if ($null -eq $Global:chromeSession) { Microsoft.PowerShell.Utility\Write-Warning "No valid session found at index $sessionId" return 'No valid browser session available' } $newId = $Global:chromeSession ? $Global:chromeSession.id : $null; $newData = $Global:chromeSession ? $Global:chromeSession.data : $null; if ($origId -ne $newId) { Microsoft.PowerShell.Utility\Write-Verbose "Selected tab: $($sessions[$sessionId].url)" } else { # only add member if session is not null if ($null -ne $Global:chromeSession) { Microsoft.PowerShell.Utility\Add-Member -InputObject $Global:chromeSession ` -MemberType NoteProperty -Name 'data' -Value $origData -Force } Microsoft.PowerShell.Utility\Write-Verbose "Selected tab: $($sessions[$sessionId].url) (unchanged)" } # connect to selected tab via automation if (($null -ne $Global:chrome) -and ($null -ne $Global:chrome.Browser) -and ($null -ne $Global:chrome.Browser.Contexts) -and ($null -ne $Global:chrome.Browser.Contexts[0])) { $Global:chromeController = $Global:chrome.Browser.Contexts[0].Pages | Microsoft.PowerShell.Core\ForEach-Object { $session = $Global:chrome.Browser.Contexts[0].NewCDPSessionAsync($PSItem).Result; $info = $session.sendAsync('Target.getTargetInfo').Result | Microsoft.PowerShell.Utility\ConvertFrom-Json if ($info.targetInfo.targetId -eq $Global:chromeSession.id) { $PSItem } } | Microsoft.PowerShell.Utility\Select-Object -First 1; Microsoft.PowerShell.Utility\Write-Verbose "Connected to tab: $($sessions[$sessionId].url)" } else { throw 'No browser automation object available' } } else { if ($null -eq $ByReference) { # handle selection by ID $sessions = $Global:chromeSessions # refresh sessions if ID out of range if ($Id -ge $sessions.Count) { $sessions = @((Microsoft.PowerShell.Utility\Invoke-WebRequest ` -Uri "http://localhost:$debugPort/json").Content | Microsoft.PowerShell.Utility\ConvertFrom-Json | Microsoft.PowerShell.Core\Where-Object -Property 'type' -EQ 'page') $Global:chromeSessions = $sessions Microsoft.PowerShell.Utility\Write-Verbose "Refreshed sessions, found $($sessions.Count)" Show-TabList throw 'Session expired, select new session with Select-WebbrowserTab -> st' } # connect to selected tab $Global:chromeSession = $sessions[$Id] $Global:chromeController = $Global:chrome.Browser.Contexts[0].Pages | Microsoft.PowerShell.Core\ForEach-Object { $session = $Global:chrome.Browser.Contexts[0].NewCDPSessionAsync($PSItem).Result; $info = $session.sendAsync('Target.getTargetInfo').Result | Microsoft.PowerShell.Utility\ConvertFrom-Json if ($info.targetInfo.targetId -eq $Global:chromeSession.id) { $PSItem } } | Microsoft.PowerShell.Utility\Select-Object -First 1; # refresh session list try { $sessions = @((Microsoft.PowerShell.Utility\Invoke-WebRequest ` -Uri "http://localhost:$debugPort/json").Content | Microsoft.PowerShell.Utility\ConvertFrom-Json | Microsoft.PowerShell.Core\Where-Object -Property 'type' -EQ 'page') $Global:chromeSessions = $sessions } catch { throw 'Session expired, select new session with Select-WebbrowserTab -> st' } Microsoft.PowerShell.Utility\Write-Verbose 'Updated tab list' } else { # use provided reference $Global:chromeSession = $ByReference } # connect to selected tab $Global:chromeController = $Global:chrome.Browser.Contexts[0].Pages | Microsoft.PowerShell.Core\ForEach-Object { $session = $Global:chrome.Browser.Contexts[0].NewCDPSessionAsync($PSItem).Result; $info = $session.sendAsync('Target.getTargetInfo').Result | Microsoft.PowerShell.Utility\ConvertFrom-Json if ($info.targetInfo.targetId -eq $Global:chromeSession.id) { $PSItem } } | Microsoft.PowerShell.Utility\Select-Object -First 1; # verify tab still exists $found = $null -ne $Global:chromeController if (!$found) { if ($null -eq $ByReference) { Show-TabList } throw 'Session expired, select new session with st' } } # show available tabs unless using reference if ($null -eq $ByReference) { Show-TabList } } end { } } ################################################################################ |