PS1 search for existing edge/opened link before opening

<# Powershell.exe -NoProfile -ExecutionPolicy Bypass -File "\\gal-arc01\T\Script\PS1\Edge-Open-Link-conditional\Edge-Open-Link-Conditional.ps1" -Link "https://planner.cloud.microsoft/webui/plan/6MwYXy_J30-C38ToHv9SxmUAGUaG/view/board?tid=94e13abb-51f9-4cae-9154-1dc424fb2c80" File: launch-conditional-Edge.ps1 Goal: - If Edge is not launched (no visible Edge window): open Link in a new window. - If Edge is launched AND the Link is already open in any tab: focus that tab (do nothing else). - If Edge is launched BUT the Link is NOT open: open Link in a new tab. Usage: powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\launch-conditional-Edge.ps1 -Link "https://..." Notes: - UI Automation may fail if Edge is elevated but this script isn't (or vice versa). Run at same elevation. - Tab scanning is best-effort; if UIA cannot read the address bar, script will open a new tab. #> # --- Parameter declaration --- param( # Link to open if not already open [Parameter(Mandatory = $false)] [string]$Link ) # --- Preference declaration --- $ErrorActionPreference = "Stop" # --- Function declaration --- function Explain-Behavior { <# .SYNOPSIS Prints a concise explanation of what this script does. #> Write-Host "" Write-Host "Behavior:" Write-Host " 1) If Microsoft Edge has no visible window: opens the link in a NEW Edge window." Write-Host " 2) If Edge is running and the link is already open in any tab: focuses that tab." Write-Host " 3) If Edge is running but the link is NOT open: opens the link in a NEW tab." Write-Host "" Write-Host "Best-effort notes:" Write-Host " - Uses Windows UI Automation to scan tabs + read the address bar." Write-Host " - If UI Automation cannot read the URL, it falls back to opening a new tab." Write-Host " - If Edge is elevated, run this script elevated too." Write-Host "" } # --- Function declaration --- function Show-Help { <# .SYNOPSIS Prints help text and exits. #> Write-Host "" Write-Host "launch-conditional-Edge.ps1" Write-Host "" Write-Host "Usage:" Write-Host " powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\launch-conditional-Edge.ps1 -Link ""https://...""" Write-Host "" Write-Host "Parameters:" Write-Host " -Link (Required) The URL to ensure is open in Edge." Explain-Behavior } # --- Function declaration --- function Normalize-Url { param( # URL to normalize for comparison [Parameter(Mandatory = $true)][string]$Url ) # Local variable declaration $u = $Url.Trim() # Control structure: if/then if (($u.StartsWith('"') -and $u.EndsWith('"')) -or ($u.StartsWith("'") -and $u.EndsWith("'"))) { $u = $u.Substring(1, $u.Length - 2) } # Control structure: while loop while ($u.EndsWith("/")) { $u = $u.Substring(0, $u.Length - 1) } return $u.ToLowerInvariant() } # --- Function declaration --- function Resolve-EdgeExePath { # Local variable declaration $cmd = Get-Command "msedge.exe" -ErrorAction SilentlyContinue # Control structure: if/then if ($cmd) { return $cmd.Source } # Local variable declaration $candidates = @( "$env:ProgramFiles\Microsoft\Edge\Application\msedge.exe", "$env:ProgramFiles(x86)\Microsoft\Edge\Application\msedge.exe", "$env:LocalAppData\Microsoft\Edge\Application\msedge.exe" ) # Control structure: foreach foreach ($p in $candidates) { # Control structure: if/then if ($p -and (Test-Path $p)) { return $p } } # Local variable declaration (registry App Paths locations) $regKeys = @( "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\msedge.exe", "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\App Paths\msedge.exe", "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\msedge.exe" ) # Control structure: foreach foreach ($k in $regKeys) { # Control structure: try/catch try { # Local variable declaration $val = (Get-ItemProperty -Path $k -ErrorAction Stop).'(default)' # Control structure: if/then if ($val -and (Test-Path $val)) { return $val } } catch { # Intentionally ignore missing keys/permissions } } # Control structure: return (soft-fail) return $null } # --- Function declaration --- ##Expanded to launch under bypass and search for MSEdge install function Open-EdgeUrl { param( # URL to open [Parameter(Mandatory = $true)][string]$Url, # Mode: new-window or new-tab (best-effort if msedge.exe is not found) [Parameter(Mandatory = $true)] [ValidateSet("new-window", "new-tab")] [string]$Mode ) # Local variable declaration $edgeExe = Resolve-EdgeExePath # Control structure: if/then/else if ($edgeExe) { # Control structure: if/then/else if ($Mode -eq "new-window") { Start-Process -FilePath $edgeExe -ArgumentList @("--new-window", $Url) | Out-Null } else { Start-Process -FilePath $edgeExe -ArgumentList @("--new-tab", $Url) | Out-Null } } else { # Fall back to the registered Edge protocol handler (works even if msedge.exe path isn't discoverable) Start-Process -FilePath ("microsoft-edge:" + $Url) | Out-Null } } # --- Function declaration --- function Add-User32 { # Control structure: try/catch try { Add-Type -Namespace Win32 -Name User32 -MemberDefinition @" using System; using System.Runtime.InteropServices; public static class User32 { [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow); } "@ -ErrorAction Stop | Out-Null } catch { # Intentionally ignore if already added in this session } } # --- Function declaration --- # --- Function declaration --- function Focus-Window { param( # Window handle to focus [Parameter(Mandatory = $true)][IntPtr]$Handle ) # Control structure: try/catch (UIA assembly load) try { Ensure-UIAutomationLoaded } catch { return $false } # Local variable declaration (window automation element) $winElem = [System.Windows.Automation.AutomationElement]::FromHandle($Handle) # Control structure: if/then (handle -> element validation) if (-not $winElem) { return $false } # Control structure: try/catch (restore window if minimized) try { $wp = $winElem.GetCurrentPattern([System.Windows.Automation.WindowPattern]::Pattern) $wp.SetWindowVisualState([System.Windows.Automation.WindowVisualState]::Normal) } catch { # Ignore if pattern not available } # Control structure: try/catch (focus window) try { $winElem.SetFocus() return $true } catch { return $false } } # --- Function declaration --- function Get-EdgeWindows { # Return Edge processes with visible windows Get-Process -Name "msedge" -ErrorAction SilentlyContinue | Where-Object { $_.MainWindowHandle -ne 0 } | Sort-Object Id } # --- Function declaration --- function Ensure-UIAutomationLoaded { # Load UI Automation assemblies for AutomationElement, patterns, etc. Add-Type -AssemblyName UIAutomationClient -ErrorAction Stop Add-Type -AssemblyName UIAutomationTypes -ErrorAction Stop } # --- Function declaration --- function Find-AddressBarElement { param( # UIA AutomationElement representing the Edge window [Parameter(Mandatory = $true)] [System.Windows.Automation.AutomationElement]$Window ) # Local variable declaration (UIA conditions) $editType = New-Object System.Windows.Automation.PropertyCondition( [System.Windows.Automation.AutomationElement]::ControlTypeProperty, [System.Windows.Automation.ControlType]::Edit ) # Local variable declaration (name heuristics for address bar; can vary) $name1 = New-Object System.Windows.Automation.PropertyCondition( [System.Windows.Automation.AutomationElement]::NameProperty, "Address and search bar" ) # Local variable declaration (alternate name heuristic) $name2 = New-Object System.Windows.Automation.PropertyCondition( [System.Windows.Automation.AutomationElement]::NameProperty, "Search or enter web address" ) # Local variable declaration (alternate automation id heuristic) $autoId = New-Object System.Windows.Automation.PropertyCondition( [System.Windows.Automation.AutomationElement]::AutomationIdProperty, "addressEditBox" ) # Local variable declaration (combine heuristics) $orNames = New-Object System.Windows.Automation.OrCondition($name1, $name2) $orAll = New-Object System.Windows.Automation.OrCondition($orNames, $autoId) $and = New-Object System.Windows.Automation.AndCondition($editType, $orAll) return $Window.FindFirst([System.Windows.Automation.TreeScope]::Descendants, $and) } # --- Function declaration --- function Get-AddressBarValue { param( # UIA AutomationElement representing the Edge window [Parameter(Mandatory = $true)] [System.Windows.Automation.AutomationElement]$Window ) # Local variable declaration $addr = Find-AddressBarElement -Window $Window # Control structure: if/then if (-not $addr) { return $null } # Control structure: try/catch try { $vp = $addr.GetCurrentPattern([System.Windows.Automation.ValuePattern]::Pattern) return $vp.Current.Value } catch { return $null } } # --- Function declaration --- function Get-TabItems { param( # UIA AutomationElement representing the Edge window [Parameter(Mandatory = $true)] [System.Windows.Automation.AutomationElement]$Window ) # Local variable declaration (condition for TabItem controls) $cond = New-Object System.Windows.Automation.PropertyCondition( [System.Windows.Automation.AutomationElement]::ControlTypeProperty, [System.Windows.Automation.ControlType]::TabItem ) return $Window.FindAll([System.Windows.Automation.TreeScope]::Descendants, $cond) } # --- Function declaration --- function Select-TabItem { param( # UIA AutomationElement representing a tab [Parameter(Mandatory = $true)] [System.Windows.Automation.AutomationElement]$TabItem ) # Control structure: try/catch try { $sel = $TabItem.GetCurrentPattern([System.Windows.Automation.SelectionItemPattern]::Pattern) $sel.Select() return $true } catch { # Control structure: nested try/catch try { $inv = $TabItem.GetCurrentPattern([System.Windows.Automation.InvokePattern]::Pattern) $inv.Invoke() return $true } catch { return $false } } } # --- Function declaration --- function Send-UrlToFocusedEdge { param( # URL to type into the currently focused Edge window [Parameter(Mandatory = $true)][string]$Url ) # Load SendKeys helper Add-Type -AssemblyName System.Windows.Forms | Out-Null Start-Sleep -Milliseconds 200 [System.Windows.Forms.SendKeys]::SendWait("^l") Start-Sleep -Milliseconds 80 [System.Windows.Forms.SendKeys]::SendWait($Url) Start-Sleep -Milliseconds 80 [System.Windows.Forms.SendKeys]::SendWait("{ENTER}") } # --- Function declaration --- function Open-EdgeUrl { param( # URL to open [Parameter(Mandatory = $true)][string]$Url, # Mode: new-window or new-tab [Parameter(Mandatory = $true)] [ValidateSet("new-window", "new-tab")] [string]$Mode ) # Local variable declaration $edgeExe = Resolve-EdgeExePath # Control structure: if/then/else if ($Mode -eq "new-window") { Start-Process -FilePath $edgeExe -ArgumentList @("--new-window", $Url) | Out-Null } else { Start-Process -FilePath $edgeExe -ArgumentList @("--new-tab", $Url) | Out-Null } } # --- Function declaration --- function Try-FocusExistingEdgeTabByUrl { param( # Target URL to find among Edge tabs [Parameter(Mandatory = $true)][string]$TargetUrl ) Ensure-UIAutomationLoaded # Local variable declarations $targetNorm = Normalize-Url -Url $TargetUrl $windows = Get-EdgeWindows # Control structure: if/then if (-not $windows -or $windows.Count -eq 0) { return $false } # Control structure: foreach foreach ($p in $windows) { # Local variable declaration $h = [IntPtr]$p.MainWindowHandle # Control structure: if/then if ($h -eq [IntPtr]::Zero) { continue } # Control structure: if/then (best-effort focus; continue even if it fails) if (-not (Focus-Window -Handle $h)) { # Proceed without hard focus; tab scanning may still work } Start-Sleep -Milliseconds 150 # Local variable declaration $winElem = [System.Windows.Automation.AutomationElement]::FromHandle($h) # Control structure: if/then if (-not $winElem) { continue } # Local variable declaration $curUrl = Get-AddressBarValue -Window $winElem # Control structure: if/then if ($curUrl -and (Normalize-Url -Url $curUrl) -eq $targetNorm) { return $true } # Local variable declaration $tabs = Get-TabItems -Window $winElem # Control structure: if/then if (-not $tabs -or $tabs.Count -eq 0) { continue } # Local variable declaration (cap scanning for safety) $maxTabs = [Math]::Min($tabs.Count, 80) # Control structure: for loop for ($i = 0; $i -lt $maxTabs; $i++) { # Local variable declaration $tab = $tabs.Item($i) # Control structure: if/then if (-not (Select-TabItem -TabItem $tab)) { continue } Start-Sleep -Milliseconds 120 # Local variable declaration $tabUrl = Get-AddressBarValue -Window $winElem # Control structure: if/then if (-not $tabUrl) { continue } # Control structure: if/then if ((Normalize-Url -Url $tabUrl) -eq $targetNorm) { return $true } } } return $false } # --- Main block declarations --- # Control structure: if/then (help gate) if ($PSBoundParameters.Count -eq 0) { Show-Help exit 1 } # Control structure: if/then (argument validation) if (-not $Link -or [string]::IsNullOrWhiteSpace($Link)) { Show-Help exit 1 } # Local variable declaration $target = $Link # Local variable declaration $found = $false # Control structure: try/catch try { $found = Try-FocusExistingEdgeTabByUrl -TargetUrl $target } catch { $found = $false } # Control structure: if/then/else if ($found) { exit 0 } else { # Local variable declaration $hasVisibleEdge = (Get-EdgeWindows | Measure-Object).Count -gt 0 # Control structure: if/then/else if (-not $hasVisibleEdge) { Open-EdgeUrl -Url $target -Mode "new-window" exit 0 } else { # Control structure: try/catch try { Open-EdgeUrl -Url $target -Mode "new-tab" exit 0 } catch { # Control structure: foreach (focus first available window then type URL) foreach ($p in (Get-EdgeWindows)) { # Local variable declaration $h = [IntPtr]$p.MainWindowHandle # Control structure: if/then if ($h -ne [IntPtr]::Zero) { # Control structure: if/then (best-effort focus; continue even if it fails) if (-not (Focus-Window -Handle $h)) { # Proceed without hard focus; tab scanning may still work } Send-UrlToFocusedEdge -Url $target break } } exit 0 } } }

Comments

Popular posts from this blog

Powerpoint countdown and current time in slides VBA

Revit area plans adding new types and references (Gross and rentable)

Revit Dynamo View Form Python Output Form Resizable, Aggressively on top