Functions/GenXdev.Windows/Set-WindowPosition.ps1
<##############################################################################
Part of PowerShell module : GenXdev.Windows Original cmdlet filename : Set-WindowPosition.ps1 Original author : René Vaessen / GenXdev Version : 1.290.2025 ################################################################################ MIT License Copyright 2021-2025 GenXdev Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ################################################################################> ################################################################################ <# .SYNOPSIS Positions and resizes windows when explicit positioning parameters are provided. .DESCRIPTION Provides precise control over window positioning and sizing when positioning parameters are specified. Supports multiple monitors, border removal, and various preset positions like left/right split, top/bottom split, and center placement. Windows can be positioned by coordinates or using predefined layouts. Without positioning parameters, the function performs no action on the window. .PARAMETER ProcessName The process name of the window to position .PARAMETER Process Process or processes whose windows need positioning .PARAMETER WindowHelper Window helper object for direct window manipulation .PARAMETER Monitor Monitor selection: 0=primary, 1+=specific monitor, -1=current, -2=secondary .PARAMETER NoBorders Removes window borders and title bar for a cleaner appearance .PARAMETER Width Window width in pixels .PARAMETER Height Window height in pixels .PARAMETER X Window horizontal position in pixels .PARAMETER Y Window vertical position in pixels .PARAMETER Left Places window on left half of screen .PARAMETER Right Places window on right half of screen .PARAMETER Top Places window on top half of screen .PARAMETER Bottom Places window on bottom half of screen .PARAMETER Centered Centers window on screen .PARAMETER Fullscreen Maximizes window to fill entire screen .PARAMETER RestoreFocus Returns focus to PowerShell window after positioning .PARAMETER PassThru Returns window helper object for further manipulation .PARAMETER SideBySide Will either set the window fullscreen on a different monitor than Powershell, or side by side with Powershell on the same monitor .PARAMETER FocusWindow Focus the window after positioning .PARAMETER SetForeground Set the window to foreground after positioning .PARAMETER Minimize Minimizes the window after positioning .PARAMETER Maximize Maximize the window after positioning .PARAMETER KeysToSend Keystrokes to send to the window after positioning .PARAMETER SendKeyEscape Escape control characters and modifiers when sending keys .PARAMETER SendKeyHoldKeyboardFocus Hold keyboard focus on target window when sending keys .PARAMETER SendKeyUseShiftEnter Use Shift+Enter instead of Enter when sending keys .PARAMETER SendKeyDelayMilliSeconds Delay between different input strings in milliseconds when sending keys .PARAMETER SessionOnly Switch to use alternative settings stored in session for AI preferences .PARAMETER ClearSession Switch to clear alternative settings stored in session for AI preferences .PARAMETER SkipSession Switch to store settings only in persistent preferences without affecting session .EXAMPLE Set-WindowPosition -Centered -Monitor 0 -NoBorders Position PowerShell window centered on primary monitor with no borders .EXAMPLE Get-Process notepad,calc | wp -m 1 -l,-r Split notepad and calc side by side on second monitor using aliases .EXAMPLE Set-WindowPosition -ProcessName notepad Does nothing - no positioning parameters specified .EXAMPLE Set-WindowPosition -ProcessName notepad -KeysToSend "Hello World" Sends keystrokes to notepad window without repositioning it #> ################################################################################ function Set-WindowPosition { [CmdletBinding(DefaultParameterSetName = 'Default', SupportsShouldProcess = $true)] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')] [Alias('wp')] param( ######################################################################## [parameter( ParameterSetName = 'ProcessName', Mandatory = $false, Position = 0, HelpMessage = 'The process name of the window to position', ValueFromPipeline, ValueFromPipelineByPropertyName, ValueFromRemainingArguments = $false )] [SupportsWildcards()] [Alias('Name')] [string] $ProcessName, ######################################################################## [parameter( ParameterSetName = 'Process', Mandatory = $false, HelpMessage = 'The process of the window to position', ValueFromPipeline, ValueFromPipelineByPropertyName, ValueFromRemainingArguments = $false )] [ValidateNotNull()] [System.Diagnostics.Process] $Process, ######################################################################## [parameter( ParameterSetName = 'WindowHelper', Mandatory = $false, HelpMessage = 'Get-Window helper object for direct window manipulation', ValueFromPipeline, ValueFromPipelineByPropertyName, ValueFromRemainingArguments = $false )] [ValidateNotNull()] [GenXdev.Helpers.WindowObj[]] $WindowHelper, ######################################################################## [parameter( Mandatory = $false, HelpMessage = 'Monitor selection: 0=primary, 1+=specific monitor, -1=current, -2=secondary' )] [Alias('m', 'mon')] [int] $Monitor = -1, ######################################################################## [Alias('nb')] [parameter( Mandatory = $false, HelpMessage = 'Removes the borders of the window' )] [switch] $NoBorders, ######################################################################## [parameter( Mandatory = $false, HelpMessage = 'Window width in pixels' )] [int] $Width = -999999, ######################################################################## [parameter( Mandatory = $false, HelpMessage = 'Window height in pixels' )] [int] $Height = -999999, ######################################################################## [parameter( Mandatory = $false, HelpMessage = 'Window horizontal position in pixels' )] [int] $X = -999999, ######################################################################## [parameter( Mandatory = $false, HelpMessage = 'Window vertical position in pixels' )] [int] $Y = -999999, ######################################################################## [parameter( Mandatory = $false, HelpMessage = 'Place window on the left side of the screen' )] [switch] $Left, ######################################################################## [parameter( Mandatory = $false, HelpMessage = 'Place window on the right side of the screen' )] [switch] $Right, ######################################################################## [parameter( Mandatory = $false, HelpMessage = 'Place window on the top side of the screen' )] [switch] $Top, ######################################################################## [parameter( Mandatory = $false, HelpMessage = 'Place window on the bottom side of the screen' )] [switch] $Bottom, ######################################################################## [parameter( Mandatory = $false, HelpMessage = 'Place window in the center of the screen' )] [switch] $Centered, ######################################################################## [parameter( Mandatory = $false, HelpMessage = 'Maximize the window' )] [Alias('fs')] [switch] $Fullscreen, ######################################################################## [parameter( Mandatory = $false, HelpMessage = 'Restore PowerShell window focus' )] [Alias('rf', 'bg')] [switch]$RestoreFocus, ######################################################################## [parameter( Mandatory = $false, HelpMessage = 'Returns the window helper for each process' )] [Alias('pt')] [switch]$PassThru, ######################################################################## [parameter( Mandatory = $false, HelpMessage = ('Will either set the window fullscreen on a different ' + 'monitor than Powershell, or side by side with Powershell on the ' + 'same monitor') )] [Alias('sbs')] [switch]$SideBySide, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Focus the window after opening' )] [Alias('fw','focus')] [switch] $FocusWindow, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Set the window to foreground after opening' )] [Alias('fg')] [switch] $SetForeground, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Minimizes the window after positioning' )] [switch] $Minimize, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Maximize the window after positioning' )] [switch] $Maximize, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = ('Keystrokes to send to the Window, ' + 'see documentation for cmdlet GenXdev.Windows\Send-Key') )] [string[]] $KeysToSend, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Escape control characters and modifiers when sending keys' )] [Alias('Escape')] [switch] $SendKeyEscape, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Hold keyboard focus on target window when sending keys' )] [Alias('HoldKeyboardFocus')] [switch] $SendKeyHoldKeyboardFocus, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = 'Use Shift+Enter instead of Enter when sending keys' )] [Alias('UseShiftEnter')] [switch] $SendKeyUseShiftEnter, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = ('Delay between different input strings in ' + 'milliseconds when sending keys') )] [Alias('DelayMilliSeconds')] [int] $SendKeyDelayMilliSeconds, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = ('Use alternative settings stored in session for AI ' + 'preferences') )] [switch] $SessionOnly, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = ('Clear alternative settings stored in session for AI ' + 'preferences') )] [switch] $ClearSession, ######################################################################## [Parameter( Mandatory = $false, HelpMessage = ('Store settings only in persistent preferences without ' + 'affecting session') )] [Alias('FromPreferences')] [switch] $SkipSession ######################################################################## ) begin { # get primary screen and all available screens $screen = $null $allScreens = @([WpfScreenHelper.Screen]::AllScreens | Microsoft.PowerShell.Core\ForEach-Object { $PSItem }) Microsoft.PowerShell.Utility\Write-Verbose ("Found $($allScreens.Count) " + "monitors available for window positioning") # list all available monitors for debugging for ($i = 0; $i -lt $allScreens.Count; $i++) { $screenInfo = $allScreens[$i] Microsoft.PowerShell.Utility\Write-Verbose ("Monitor ${i}: " + "$($screenInfo.WorkingArea.Width)x$($screenInfo.WorkingArea.Height) " + "at ($($screenInfo.WorkingArea.X),$($screenInfo.WorkingArea.Y)) " + "Device: $($screenInfo.DeviceName)") } # store reference to powershell window for focus restoration $powerShellWindow = GenXdev.Windows\Get-PowershellMainWindow if ($null -ne $powerShellWindow) { Microsoft.PowerShell.Utility\Write-Verbose ("PowerShell window " + "found - Handle: $($powerShellWindow.Handle), " + "Position: $($powerShellWindow.Position().X)," + "$($powerShellWindow.Position().Y), " + "Size: $($powerShellWindow.Size().Width)x" + "$($powerShellWindow.Size().Height)") } else { Microsoft.PowerShell.Utility\Write-Verbose ("PowerShell window " + "not found or not available") } # auto-enable side by side if second monitor requested but not available $wpparams = GenXdev.Helpers\Copy-IdenticalParamValues ` -BoundParameters $PSBoundParameters ` -FunctionName 'GenXdev.Windows\Set-WindowPosition' Microsoft.PowerShell.Utility\Write-Verbose ("Window positioning " + "parameters available: $($wpparams.Keys -join ', ')") $ForcedSideBySide = ($Monitor -eq -2) -and ( ($allScreens.Count -lt 2) -or (-not ($Global:DefaultSecondaryMonitor -is [int] -and ($Global:DefaultSecondaryMonitor -gt 0))) ) if ($ForcedSideBySide) { Microsoft.PowerShell.Utility\Write-Verbose ("Forcing side-by-side " + "positioning: insufficient monitors ($($allScreens.Count)) or " + "invalid DefaultSecondaryMonitor " + "($Global:DefaultSecondaryMonitor)") } if ($SideBySide -or $ForcedSideBySide){ Microsoft.PowerShell.Utility\Write-Verbose ("Configuring " + "side-by-side positioning - PowerShell monitor: " + "$($powerShellWindow.GetCurrentMonitor()), " + "Target monitor: $($powerShellWindow.GetCurrentMonitor() + 1)") $SideBySide = $true $Monitor = $powerShellWindow.GetCurrentMonitor() + 1 $SetForeground = $true $RestoreFocus = $true $Maximize = $false $FullScreen = $false if ($KeysToSend.Count -eq 1 -and $KeysToSend[0] -in @('f', '{F11}')) { $KeysToSend = @() } Microsoft.PowerShell.Utility\Write-Verbose ("Side-by-side final " + "settings: Monitor=$Monitor, SetForeground=$SetForeground, " + "RestoreFocus=$RestoreFocus, Maximize=$Maximize") } # store reference to bound parameters for later use $myPSBoundParameters = $PSBoundParameters # determine which process to work with based on parameter set switch ($PSCmdlet.ParameterSetName) { 'ProcessName' { Microsoft.PowerShell.Utility\Write-Verbose ('ParameterSetName: ProcessName') # get processes by name $foundProcess = Microsoft.PowerShell.Management\Get-Process ` -Name $ProcessName ` -ErrorAction SilentlyContinue | Microsoft.PowerShell.Core\Where-Object ` -Property 'MainWindowHandle' ` -NE 0 | Microsoft.PowerShell.Utility\Sort-Object ` -Property 'StartTime' ` -Descending | Microsoft.PowerShell.Utility\Select-Object ` -First 1 if ($null -eq $foundProcess) { Microsoft.PowerShell.Utility\Write-Verbose ("No process found with name '$ProcessName' (ProcessName set)") Microsoft.PowerShell.Utility\Write-Error ('No process found with ' + "name '$ProcessName'") } else { Microsoft.PowerShell.Utility\Write-Verbose ("Process found: $($foundProcess.ProcessName) with ID $($foundProcess.Id) (ProcessName set)") $Process = $foundProcess Microsoft.PowerShell.Utility\Write-Verbose ('Found process: ' + "$($Process.ProcessName) with ID $($Process.Id)") } break; } 'Process' { Microsoft.PowerShell.Utility\Write-Verbose ('ParameterSetName: Process') # get process by id first $foundProcess = Microsoft.PowerShell.Management\Get-Process ` -Id ($Process.Id) ` -ErrorAction SilentlyContinue | Microsoft.PowerShell.Core\Where-Object ` -Property 'MainWindowHandle' ` -NE 0 if ($null -eq $foundProcess) { Microsoft.PowerShell.Utility\Write-Verbose ("No process found by Id $($Process.Id), trying by Name $($Process.Name) (Process set)") # fallback to process by name $foundProcess = Microsoft.PowerShell.Management\Get-Process ` -Name ($Process.Name) ` -ErrorAction SilentlyContinue | Microsoft.PowerShell.Core\Where-Object ` -Property 'MainWindowHandle' ` -NE 0 if ($null -eq $foundProcess) { Microsoft.PowerShell.Utility\Write-Verbose ("No process found with name '$($Process.Name)' (Process set)") Microsoft.PowerShell.Utility\Write-Error ('No process found with ' + "name '$($Process.Name)'") $Process = $null } else { Microsoft.PowerShell.Utility\Write-Verbose ("Process found by Name: $($foundProcess.ProcessName) with ID $($foundProcess.Id) (Process set)") } } else { Microsoft.PowerShell.Utility\Write-Verbose ("Process found by Id: $($foundProcess.ProcessName) with ID $($foundProcess.Id) (Process set)") $Process = $foundProcess Microsoft.PowerShell.Utility\Write-Verbose ('Found process: ' + "$($Process.ProcessName) with ID $($Process.Id)") } break; } 'WindowHelper' { Microsoft.PowerShell.Utility\Write-Verbose ('ParameterSetName: WindowHelper') # get processes from window helper handles $foundProcess = Microsoft.PowerShell.Management\Get-Process ` -ErrorAction SilentlyContinue | Microsoft.PowerShell.Core\Where-Object ` -Property MainWindowHandle ` -EQ $WindowHelper.Handle if ($null -eq $foundProcess) { Microsoft.PowerShell.Utility\Write-Verbose ("No process found with window handle '$($WindowHelper.Handle)' (WindowHelper set)") Microsoft.PowerShell.Utility\Write-Error ('No process found with ' + "window handle '$($WindowHelper.Handle)'") } else { Microsoft.PowerShell.Utility\Write-Verbose ("Process found by WindowHelper: $($foundProcess.ProcessName) with ID $($foundProcess.Id) (WindowHelper set)") $Process = $foundProcess Microsoft.PowerShell.Utility\Write-Verbose ('Found process: ' + "$($Process.ProcessName) with ID $($Process.Id)") } break; } default { Microsoft.PowerShell.Utility\Write-Verbose ('ParameterSetName: default (using PowerShell main window process)') # default to powershell main window process $Process = (GenXdev.Windows\Get-PowershellMainWindowProcess) break; } } } process { ######################################################################## # process each window that needs positioning if ($null -ne $Process) { Microsoft.PowerShell.Utility\Write-Verbose ("Processing window for process: $($Process.ProcessName) (Id: $($Process.Id))") # determine if any positioning parameters are provided $havePositioningParams = ($X -gt -999999) -or ($Y -gt -999999) ` -or ($Width -gt 0) -or ($Height -gt 0) ` -or $Left -or $Right -or $Top -or $Bottom ` -or $Centered -or $Fullscreen -or $SideBySide ` -or $Maximize -or $Minimize -or $NoBorders # determine if any focus/foreground parameters are provided $haveFocusParams = $SetForeground -or $FocusWindow -or $RestoreFocus -or ($KeysToSend -and ($KeysToSend.Count -gt 0)) # determine if we should process the window (positioning, focus, or keys) $shouldProcessWindow = $havePositioningParams -or $haveFocusParams -or ($null -ne $KeysToSend -and ($KeysToSend.Count -gt 0)) Microsoft.PowerShell.Utility\Write-Verbose ("Positioning parameters " + "detected: $havePositioningParams (X=$X, Y=$Y, Width=$Width, " + "Height=$Height, Left=$Left, Right=$Right, Top=$Top, " + "Bottom=$Bottom, Centered=$Centered, Fullscreen=$Fullscreen, " + "SideBySide=$SideBySide, Maximize=$Maximize, Minimize=$Minimize, " + "NoBorders=$NoBorders)") Microsoft.PowerShell.Utility\Write-Verbose ("Focus parameters " + "detected: $haveFocusParams (SetForeground=$SetForeground, " + "FocusWindow=$FocusWindow, RestoreFocus=$RestoreFocus)") Microsoft.PowerShell.Utility\Write-Verbose ("Should process window: " + "$shouldProcessWindow (positioning=$havePositioningParams, " + "focus=$haveFocusParams, keys=$($null -ne $KeysToSend -and ($KeysToSend.Count -gt 0)))") # get window handle - use powershell window or process main window $window = $WindowHelper ? $WindowHelper : (GenXdev.Windows\Get-Window -ProcessId ($Process.Id)) if ($null -ne $window) { Microsoft.PowerShell.Utility\Write-Verbose ("`r`n-----------`r`nWindow object found:`r`n" + "Title: $($window.Title)`r`n" + "Handle: $($window.Handle)`r`n" + "Position: $($window.Position().X),$($window.Position().Y)`r`n" + "Size: $($window.Size().Width)x$($window.Size().Height)`r`n-----------") } else { Microsoft.PowerShell.Utility\Write-Verbose ("No window object " + "available for process $($Process.ProcessName)") } # detect window's current monitor for comparison $currentWindowScreen = $null if ($null -ne $window) { $currentWindowScreen = [WpfScreenHelper.Screen]::FromPoint(@{X = $window.Position().X; Y = $window.Position().Y }) Microsoft.PowerShell.Utility\Write-Verbose ("Window's current " + "monitor detected: $($currentWindowScreen.DeviceName) - " + "$($currentWindowScreen.WorkingArea.Width)x" + "$($currentWindowScreen.WorkingArea.Height)") } if ($Monitor -eq 0) { Microsoft.PowerShell.Utility\Write-Verbose ('Choosing primary ' + 'monitor, because default monitor requested using -Monitor 0') $Screen = [WpfScreenHelper.Screen]::PrimaryScreen; Microsoft.PowerShell.Utility\Write-Verbose ("Primary monitor " + "selected: $($Screen.DeviceName) - " + "$($Screen.WorkingArea.Width)x$($Screen.WorkingArea.Height) " + "at ($($Screen.WorkingArea.X),$($Screen.WorkingArea.Y))") } elseif ((-not $SideBySide) -and ((GenXdev.Windows\Get-MonitorCount) -gt 1) -and $Monitor -eq -2 -and $Global:DefaultSecondaryMonitor -is [int] -and $Global:DefaultSecondaryMonitor -ge 0) { $userMonitorNum = $Global:DefaultSecondaryMonitor $screenIndex = ($Global:DefaultSecondaryMonitor) % $AllScreens.Length Microsoft.PowerShell.Utility\Write-Verbose ('Picking monitor ' + "#$userMonitorNum as secondary (requested with -monitor -2) " + "set by `$Global:DefaultSecondaryMonitor") $Screen = $AllScreens[$screenIndex]; $Monitor = $Global:DefaultSecondaryMonitor; Microsoft.PowerShell.Utility\Write-Verbose ("Secondary monitor " + "selected: $($Screen.DeviceName) - " + "$($Screen.WorkingArea.Width)x$($Screen.WorkingArea.Height) " + "at ($($Screen.WorkingArea.X),$($Screen.WorkingArea.Y))") } elseif ($Monitor -eq -2 -and ((GenXdev.Windows\Get-MonitorCount) -gt 1) -and -not $SideBySide) { Microsoft.PowerShell.Utility\Write-Verbose ('Picking monitor #1 ' + 'as default secondary (requested with -monitor -2), because ' + '`$Global:DefaultSecondaryMonitor not set') $Screen = $AllScreens[1 % $AllScreens.Length]; Microsoft.PowerShell.Utility\Write-Verbose ("Default secondary " + "monitor selected: $($Screen.DeviceName) - " + "$($Screen.WorkingArea.Width)x$($Screen.WorkingArea.Height) " + "at ($($Screen.WorkingArea.X),$($Screen.WorkingArea.Y))") } elseif ($Monitor -eq -2 -and -not $SideBySide) { Microsoft.PowerShell.Utility\Write-Verbose ('Monitor -2 requested ' + 'but no secondary monitor found, defaulting to primary.') $Monitor = 0 $Screen = [WpfScreenHelper.Screen]::PrimaryScreen; Microsoft.PowerShell.Utility\Write-Verbose ("Fallback to primary " + "monitor: $($Screen.DeviceName)) - " + "$($Screen.WorkingArea.Width)x$($Screen.WorkingArea.Height) " + "at ($($Screen.WorkingArea.X),$($Screen.WorkingArea.Y))") } elseif ((-not $SideBySide) -and $Monitor -ge 1) { $selectedIndex = ($Monitor - 1) % $AllScreens.Length Microsoft.PowerShell.Utility\Write-Verbose ('Picking monitor ' + "#$selectedIndex as requested by the -Monitor parameter " + "($Monitor)") $Screen = $AllScreens[$selectedIndex] Microsoft.PowerShell.Utility\Write-Verbose ("Requested monitor " + "selected: $($Screen.DeviceName) - " + "$($Screen.WorkingArea.Width)x$($Screen.WorkingArea.Height) " + "at ($($Screen.WorkingArea.X),$($Screen.WorkingArea.Y))") } else { if (-not $SideBySide) { Microsoft.PowerShell.Utility\Write-Verbose ('Picking monitor ' + '#1 (FromPoint)') $Screen = $currentWindowScreen if ($null -ne $Screen) { Microsoft.PowerShell.Utility\Write-Verbose ("Window's " + "current monitor used: $($Screen.DeviceName) - " + "$($Screen.WorkingArea.Width)x$($Screen.WorkingArea.Height) " + "at ($($Screen.WorkingArea.X),$($Screen.WorkingArea.Y))") } } else { $Screen = $allScreens[$powerShellWindow.GetCurrentMonitor()] Microsoft.PowerShell.Utility\Write-Verbose ("PowerShell's " + "current monitor used for side-by-side: " + "$($Screen.DeviceName) - " + "$($Screen.WorkingArea.Width)x$($Screen.WorkingArea.Height) " + "at ($($Screen.WorkingArea.X),$($Screen.WorkingArea.Y))") } } # handle side-by-side positioning if ($SideBySide -and ($powerShellWindow.Handle -ne $window.Handle)) { Microsoft.PowerShell.Utility\Write-Verbose ('SideBySide requested and ' + 'window is not PowerShell main window.') $powershellMonitorIndex = $AllScreens.IndexOf($PowershellScreen)+1 Microsoft.PowerShell.Utility\Write-Verbose ('Window and PowerShell are ' + 'on the same screen.') Microsoft.PowerShell.Utility\Write-Verbose ("PowerShell screen index: " + "$powershellMonitorIndex for side-by-side positioning") $left = $false; $top = $false; $right = $false; $FullScreen = $false; $Centered = $false $KeysToSend = ($KeysToSend.Count -eq 1) -and ($KeysToSend[0] -in @('f', '{F11}') ? @() : $KeysToSend) $RestoreFocus = $true # split horizontally or vertically based on screen orientation if ($PowershellScreen.WorkingArea.Width -gt $PowershellScreen.WorkingArea.Height) { Microsoft.PowerShell.Utility\Write-Verbose ('Screen is taller than ' + 'wide, splitting vertically (Bottom). Screen dimensions: ' + "$($PowershellScreen.WorkingArea.Width)x" + "$($PowershellScreen.WorkingArea.Height)") GenXdev.Windows\Set-WindowPosition -Bottom -Monitor $powershellMonitorIndex $FullScreen = $false $Top = $true Microsoft.PowerShell.Utility\Write-Verbose ('PowerShell moved to ' + 'bottom, target window will be positioned at top') } else { Microsoft.PowerShell.Utility\Write-Verbose ('Screen is wider than ' + 'tall, splitting horizontally (Left)). Screen dimensions: ' + "$($PowershellScreen.WorkingArea.Width)x" + "$($PowershellScreen.WorkingArea.Height)") GenXdev.Windows\Set-WindowPosition -Left -Monitor $powershellMonitorIndex $FullScreen = $false $right = $true; Microsoft.PowerShell.Utility\Write-Verbose ('PowerShell moved to ' + 'left, target window will be positioned on right') } } if ($null -eq $screen) { Microsoft.PowerShell.Utility\Write-Verbose ("No screen object set, using window's current monitor as fallback.") $screen = $currentWindowScreen ? $currentWindowScreen : $allScreens[0] } # detect if monitor change is being requested $isMonitorChangeRequest = $false if (($Monitor -ge 0) -and ($null -ne $currentWindowScreen) -and ($null -ne $Screen)) { $isMonitorChangeRequest = ($currentWindowScreen.DeviceName -ne $Screen.DeviceName) if ($isMonitorChangeRequest) { Microsoft.PowerShell.Utility\Write-Verbose ("Monitor change " + "detected: Moving window from " + "'$($currentWindowScreen.DeviceName)' to " + "'$($Screen.DeviceName)'") Microsoft.PowerShell.Utility\Write-Verbose ("Source monitor " + "working area: $($currentWindowScreen.WorkingArea.Width)x" + "$($currentWindowScreen.WorkingArea.Height) at " + "($($currentWindowScreen.WorkingArea.X)," + "$($currentWindowScreen.WorkingArea.Y))") Microsoft.PowerShell.Utility\Write-Verbose ("Target monitor " + "working area: $($Screen.WorkingArea.Width)x" + "$($Screen.WorkingArea.Height) at " + "($($Screen.WorkingArea.X),$($Screen.WorkingArea.Y))") # Monitor change implies positioning is needed if (-not $havePositioningParams) { Microsoft.PowerShell.Utility\Write-Verbose ('No explicit ' + 'positioning parameters, but monitor change requested ' + '- enabling positioning for monitor change') $havePositioningParams = $true Microsoft.PowerShell.Utility\Write-Verbose ('Detecting ' + 'current window position to preserve when moving to ' + 'new monitor') # Get current window position and size $currentPos = $window.Position() $currentSize = $window.Size() $currentWorkArea = $currentWindowScreen.WorkingArea # Calculate relative position within current monitor's work area $relativeX = ($currentPos.X - $currentWorkArea.X) / $currentWorkArea.Width $relativeY = ($currentPos.Y - $currentWorkArea.Y) / $currentWorkArea.Height $relativeWidth = $currentSize.Width / $currentWorkArea.Width $relativeHeight = $currentSize.Height / $currentWorkArea.Height Microsoft.PowerShell.Utility\Write-Verbose ("Current relative position: X=$([Math]::Round($relativeX, 2)), Y=$([Math]::Round($relativeY, 2)), W=$([Math]::Round($relativeWidth, 2)), H=$([Math]::Round($relativeHeight, 2))") # Detect positioning style based on relative position and size $tolerance = 0.1 # 10% tolerance for position detection $sizeTolerance = 0.4 # 40% minimum size to consider positioned (allows for half-screen at 50%) # Determine primary positioning based on which dimension is more constrained # If width is more constrained (< 90% of screen), check left/right first # If height is more constrained (< 90% of screen), check top/bottom first $widthConstrained = $relativeWidth -lt 0.9 $heightConstrained = $relativeHeight -lt 0.9 # Priority 1: Check the more constrained dimension first if ($widthConstrained -and (-not $heightConstrained)) { # Width is constrained, height spans most/all screen - check left/right if ($relativeWidth -ge $sizeTolerance) { if ($relativeX -le $tolerance) { $Left = $true Microsoft.PowerShell.Utility\Write-Verbose ('Detected LEFT positioning (full height) - preserving on new monitor') } elseif (($relativeX + $relativeWidth) -ge (1.0 - $tolerance)) { $Right = $true Microsoft.PowerShell.Utility\Write-Verbose ('Detected RIGHT positioning (full height) - preserving on new monitor') } } } elseif ($heightConstrained -and (-not $widthConstrained)) { # Height is constrained, width spans most/all screen - check top/bottom if ($relativeHeight -ge $sizeTolerance) { if ($relativeY -le $tolerance) { $Top = $true Microsoft.PowerShell.Utility\Write-Verbose ('Detected TOP positioning (full width) - preserving on new monitor') } elseif (($relativeY + $relativeHeight) -ge (1.0 - $tolerance)) { $Bottom = $true Microsoft.PowerShell.Utility\Write-Verbose ('Detected BOTTOM positioning (full width) - preserving on new monitor') } } } elseif ($widthConstrained -and $heightConstrained) { # Both dimensions constrained - check for corner positioning or centered $centerX = $relativeX + ($relativeWidth / 2) $centerY = $relativeY + ($relativeHeight / 2) # Window with 10% margins (like X=0.1, W=0.8) should be considered centered $leftMargin = $relativeX $rightMargin = 1.0 - ($relativeX + $relativeWidth) $topMargin = $relativeY $bottomMargin = 1.0 - ($relativeY + $relativeHeight) # Consider centered if ALL margins are small (≤ 10% for more reasonable detection) $hasSmallMargins = ($leftMargin -le 0.1) -and ($rightMargin -le 0.1) -and ($topMargin -le 0.1) -and ($bottomMargin -le 0.1) Microsoft.PowerShell.Utility\Write-Verbose ("Positioning check: centerX=$([Math]::Round($centerX, 2)), centerY=$([Math]::Round($centerY, 2))") Microsoft.PowerShell.Utility\Write-Verbose ("Window bounds: X=$([Math]::Round($relativeX, 2)), Y=$([Math]::Round($relativeY, 2)), W=$([Math]::Round($relativeWidth, 2)), H=$([Math]::Round($relativeHeight, 2))") Microsoft.PowerShell.Utility\Write-Verbose ("Actual margins: Left=$([Math]::Round($leftMargin, 3)), Right=$([Math]::Round($rightMargin, 3)), Top=$([Math]::Round($topMargin, 3)), Bottom=$([Math]::Round($bottomMargin, 3))") Microsoft.PowerShell.Utility\Write-Verbose ("Has small margins (all ≤ 10%): $hasSmallMargins") # If window has small margins on all sides, consider it centered if ($hasSmallMargins) { $Centered = $true Microsoft.PowerShell.Utility\Write-Verbose ('Detected CENTERED positioning (small margins on all sides) - preserving on new monitor') } else { # Check for specific edge positioning # Check left/right first if ($relativeWidth -ge $sizeTolerance) { if ($relativeX -le $tolerance) { $Left = $true Microsoft.PowerShell.Utility\Write-Verbose ('Detected LEFT positioning - preserving on new monitor') } elseif (($relativeX + $relativeWidth) -ge (1.0 - $tolerance)) { $Right = $true Microsoft.PowerShell.Utility\Write-Verbose ('Detected RIGHT positioning - preserving on new monitor') } } # Then check top/bottom if ($relativeHeight -ge $sizeTolerance) { if ($relativeY -le $tolerance) { $Top = $true Microsoft.PowerShell.Utility\Write-Verbose ('Detected TOP positioning - preserving on new monitor') } elseif (($relativeY + $relativeHeight) -ge (1.0 - $tolerance)) { $Bottom = $true Microsoft.PowerShell.Utility\Write-Verbose ('Detected BOTTOM positioning - preserving on new monitor') } } # If no specific positioning detected, just enable positioning for auto-sizing if ((-not $Left) -and (-not $Right) -and (-not $Top) -and (-not $Bottom)) { Microsoft.PowerShell.Utility\Write-Verbose ('No specific positioning detected - enabling auto-sizing to maximum') } } } else { # Neither dimension particularly constrained - likely fullscreen or very large window # Check margins for large window centered detection $leftMargin = $relativeX $rightMargin = 1.0 - ($relativeX + $relativeWidth) $topMargin = $relativeY $bottomMargin = 1.0 - ($relativeY + $relativeHeight) # For large windows, be even more generous (≤ 15% margins) $hasSmallMargins = ($leftMargin -le 0.15) -and ($rightMargin -le 0.15) -and ($topMargin -le 0.15) -and ($bottomMargin -le 0.15) if (-not $hasSmallMargins) { $Centered = $true Microsoft.PowerShell.Utility\Write-Verbose ('Detected CENTERED positioning (large window with small margins) - preserving on new monitor') } else { Microsoft.PowerShell.Utility\Write-Verbose ('Large window not centered - enabling auto-sizing to maximum') } } } } } # calculate final window coordinates and dimensions if (($X -le -999999) -or ($X -isnot [int])) { Microsoft.PowerShell.Utility\Write-Verbose ('X not provided or invalid, using screen.WorkingArea.X') $X = $Screen.WorkingArea.X; } else { # adjust x position for monitor offset if ($Monitor -ge 0) { Microsoft.PowerShell.Utility\Write-Verbose ('Adjusting X for monitor offset.') $X = $Screen.WorkingArea.X + $X; } } Microsoft.PowerShell.Utility\Write-Verbose ("X determined to be $X") # calculate y position if (($Y -le -999999) -or ($Y -isnot [int])) { Microsoft.PowerShell.Utility\Write-Verbose ('Y not provided or invalid, using screen.WorkingArea.Y') $Y = $Screen.WorkingArea.Y; } else { # adjust y position for monitor offset if ($Monitor -ge 0) { Microsoft.PowerShell.Utility\Write-Verbose ('Adjusting Y for monitor offset.') $Y = $Screen.WorkingArea.Y + $Y; } } Microsoft.PowerShell.Utility\Write-Verbose ("Y determined to be $Y") # set fullscreen dimensions if requested if ($Fullscreen -eq $true) { Microsoft.PowerShell.Utility\Write-Verbose ('Fullscreen requested, setting Width/Height to screen.WorkingArea.') $Width = $Screen.WorkingArea.Width; $Height = $Screen.WorkingArea.Height; } Microsoft.PowerShell.Utility\Write-Verbose ('Have positioning parameters set') # Reset width/height for smart positioning if detected during monitor change if ($isMonitorChangeRequest -and ($Left -or $Right -or $Top -or $Bottom -or $Centered)) { $Width = -999999 $Height = -999999 Microsoft.PowerShell.Utility\Write-Verbose ('Reset Width/Height to allow smart positioning to control sizing') } # check if width and height were explicitly provided $widthProvided = ($Width -gt 0) -and ($Width -is [int]); $heightProvided = ($Height -gt 0) -and ($Height -is [int]); # use screen width if width not provided if ($widthProvided -eq $false) { Microsoft.PowerShell.Utility\Write-Verbose ('Width not provided, using screen.WorkingArea.Width') $Width = $Screen.WorkingArea.Width; Microsoft.PowerShell.Utility\Write-Verbose ('Width not provided ' + "resetted to $Width") } # use screen height if height not provided if ($heightProvided -eq $false) { Microsoft.PowerShell.Utility\Write-Verbose ('Height not provided, using screen.WorkingArea.Height') $Height = $Screen.WorkingArea.Height; Microsoft.PowerShell.Utility\Write-Verbose ('Height not provided ' + "resetted to $Height") } # apply layout positioning (left/right/top/bottom/centered) if ($Left -eq $true) { Microsoft.PowerShell.Utility\Write-Verbose ('Left positioning requested.') $X = $Screen.WorkingArea.X; Microsoft.PowerShell.Utility\Write-Verbose ("Left positioning: " + "X coordinate set to screen working area left edge: $X") # use half width if not explicitly provided if ($widthProvided -eq $false) { Microsoft.PowerShell.Utility\Write-Verbose ('Width not provided ' + 'for Left, using half screen width.') $Width = [Math]::Min($Screen.WorkingArea.Width / 2, $Width); Microsoft.PowerShell.Utility\Write-Verbose ("Auto-calculated " + "width for left positioning: $Width (half of " + "$($Screen.WorkingArea.Width))") } Microsoft.PowerShell.Utility\Write-Verbose ("Left chosen, " + "X = $X, Width = $Width") } else { # position on right side if ($Right -eq $true) { Microsoft.PowerShell.Utility\Write-Verbose ('Right positioning requested.') # use half width if not explicitly provided if ($widthProvided -eq $false) { Microsoft.PowerShell.Utility\Write-Verbose ('Width not ' + 'provided for Right, using half screen width.') $Width = [Math]::Min($Screen.WorkingArea.Width / 2, $Width); Microsoft.PowerShell.Utility\Write-Verbose ("Auto-calculated " + "width for right positioning: $Width (half of " + "$($Screen.WorkingArea.Width))") } $X = $Screen.WorkingArea.X + $Screen.WorkingArea.Width - $Width; Microsoft.PowerShell.Utility\Write-Verbose ("Right positioning: " + "X coordinate calculated as " + "$($Screen.WorkingArea.X) + $($Screen.WorkingArea.Width) " + "- $Width = $X") Microsoft.PowerShell.Utility\Write-Verbose ("Right chosen, " + "X = $X, Width = $Width") } } # position on top if ($Top -eq $true) { Microsoft.PowerShell.Utility\Write-Verbose ('Top positioning requested.') $Y = $Screen.WorkingArea.Y; Microsoft.PowerShell.Utility\Write-Verbose ("Top positioning: " + "Y coordinate set to screen working area top edge: $Y") # use half height if not explicitly provided if ($heightProvided -eq $false) { Microsoft.PowerShell.Utility\Write-Verbose ('Height not provided ' + 'for Top, using half screen height.') $Height = [Math]::Min($Screen.WorkingArea.Height / 2, $Height); Microsoft.PowerShell.Utility\Write-Verbose ("Auto-calculated " + "height for top positioning: $Height (half of " + "$($Screen.WorkingArea.Height))") } Microsoft.PowerShell.Utility\Write-Verbose ("Top chosen, " + "Y = $Y, Height = $Height") } else { # position on bottom if ($Bottom -eq $true) { Microsoft.PowerShell.Utility\Write-Verbose ('Bottom positioning requested.') # use half height if not explicitly provided if ($heightProvided -eq $false) { Microsoft.PowerShell.Utility\Write-Verbose ('Height not ' + 'provided for Bottom, using half screen height.') $Height = [Math]::Min($Screen.WorkingArea.Height / 2, $Height); Microsoft.PowerShell.Utility\Write-Verbose ("Auto-calculated " + "height for bottom positioning: $Height (half of " + "$($Screen.WorkingArea.Height))") } $Y = $Screen.WorkingArea.Y + $Screen.WorkingArea.Height - $Height; Microsoft.PowerShell.Utility\Write-Verbose ("Bottom positioning: " + "Y coordinate calculated as " + "$($Screen.WorkingArea.Y) + $($Screen.WorkingArea.Height) " + "- $Height = $Y") Microsoft.PowerShell.Utility\Write-Verbose ("Bottom chosen, " + "Y = $Y, Height = $Height") } } # center window on screen if ($Centered -eq $true) { Microsoft.PowerShell.Utility\Write-Verbose ('Centered positioning requested.') # use 80% of screen dimensions if not explicitly provided if ($heightProvided -eq $false) { Microsoft.PowerShell.Utility\Write-Verbose ('Height not provided ' + 'for Centered, using 80% of screen height.') $Height = [Math]::Round([Math]::Min($Screen.WorkingArea.Height * 0.8, $Height), 0); Microsoft.PowerShell.Utility\Write-Verbose ("Auto-calculated " + "height for centered positioning: $Height (80% of " + "$($Screen.WorkingArea.Height))") } if ($widthProvided -eq $false) { Microsoft.PowerShell.Utility\Write-Verbose ('Width not provided ' + 'for Centered, using 80% of screen width.') $Width = [Math]::Round([Math]::Min($Screen.WorkingArea.Width * 0.8, $Width), 0); Microsoft.PowerShell.Utility\Write-Verbose ("Auto-calculated " + "width for centered positioning: $Width (80% of " + "$($Screen.WorkingArea.Width))") } # calculate center position $X = $Screen.WorkingArea.X + [Math]::Round(($screen.WorkingArea.Width - $Width) / 2, 0); $Y = $Screen.WorkingArea.Y + [Math]::Round(($screen.WorkingArea.Height - $Height) / 2, 0); Microsoft.PowerShell.Utility\Write-Verbose ("Centered position " + "calculation: X = $($Screen.WorkingArea.X) + " + "(($($screen.WorkingArea.Width) - $Width) / 2) = $X") Microsoft.PowerShell.Utility\Write-Verbose ("Centered position " + "calculation: Y = $($Screen.WorkingArea.Y) + " + "(($($screen.WorkingArea.Height) - $Height) / 2) = $Y") Microsoft.PowerShell.Utility\Write-Verbose ("Centered chosen, " + "X = $X, Width = $Width, Y = $Y, Height = $Height") } # recalculate shouldProcessWindow after all positioning logic is complete # (monitor change detection may have updated havePositioningParams) $shouldProcessWindow = $havePositioningParams -or $haveFocusParams -or ($null -ne $KeysToSend -and ($KeysToSend.Count -gt 0)) Microsoft.PowerShell.Utility\Write-Verbose ("Final shouldProcessWindow check: $shouldProcessWindow (positioning=$havePositioningParams, focus=$haveFocusParams, keys=$($null -ne $KeysToSend -and ($KeysToSend.Count -gt 0)))") if (-not $shouldProcessWindow) { Microsoft.PowerShell.Utility\Write-Verbose ('No positioning, focus, or key parameters provided - exiting early') return; } # confirm with user if whatif support is enabled $whatIfMessage = if ($havePositioningParams) { "Set position/size to: X=$X Y=$Y W=$Width H=$Height" } elseif ($haveFocusParams) { "Apply focus/foreground changes" } else { "Send keystrokes: $($KeysToSend -join ', ')" } if ($PSCmdlet.ShouldProcess( "Window of process '$($Process.ProcessName)'", $whatIfMessage)) { Microsoft.PowerShell.Utility\Write-Verbose ('ShouldProcess returned ' + 'true, proceeding with window operations.') if ($havePositioningParams) { Microsoft.PowerShell.Utility\Write-Verbose ("Final window positioning: " + "Process='$($Process.ProcessName))', Handle=$($window.Handle), " + "Target coordinates: X=$X, Y=$Y, Width=$Width, Height=$Height") Microsoft.PowerShell.Utility\Write-Verbose ("Target monitor: " + "$($Screen.DeviceName) - Working area: " + "$($Screen.WorkingArea.Width)x$($Screen.WorkingArea.Height) " + "at ($($Screen.WorkingArea.X),$($Screen.WorkingArea.Y))") } else { Microsoft.PowerShell.Utility\Write-Verbose ("Processing window for focus/foreground or keystroke operations only - no positioning") } # have a handle to the mainwindow of the browser? if ($null -ne $window) { if ($havePositioningParams) { Microsoft.PowerShell.Utility\Write-Verbose ('Restoring and ' + 'positioning window') # restore window and position it Microsoft.PowerShell.Utility\Write-Verbose ('Showing window ' + '(first call to ensure window is visible)') $null = $window.Focus() Microsoft.PowerShell.Utility\Write-Verbose ("[Set-WindowPosition] " + "About to move window. Handle: $($window.Handle) " + "Target: X=$X, Y=$Y, Width=$Width, Height=$Height") Microsoft.PowerShell.Utility\Write-Verbose ('Executing first ' + 'Move operation to set window position and size') $null = $window.Move($X, $Y, $Width, $Height) Microsoft.PowerShell.Utility\Write-Verbose ('Executing second ' + 'Move operation for stability (some windows need this)') $null = $window.Move($X, $Y, $Width, $Height) Microsoft.PowerShell.Utility\Write-Verbose ('Window positioning ' + 'operations completed successfully') } else { Microsoft.PowerShell.Utility\Write-Verbose ('No positioning parameters - skipping window positioning operations') } # maximize window if fullscreen requested if ($Fullscreen) { Microsoft.PowerShell.Utility\Write-Verbose ('Fullscreen ' + 'requested, sending F11 keystroke.') $KeysToSend = ($KeysToSend ? $KeysToSend : @()) + @('{F11}') } # needs to be set noborders manually? if ($NoBorders -eq $true) { Microsoft.PowerShell.Utility\Write-Verbose ('Setting NoBorders ' + '- removing window chrome and decorations') $null = $window.RemoveBorder(); Microsoft.PowerShell.Utility\Write-Verbose ('Window border ' + 'removal completed') } if ($Maximize) { Microsoft.PowerShell.Utility\Write-Verbose ('Maximize requested ' + 'or no positioning, maximizing window.') $null = $window.Maximize() Microsoft.PowerShell.Utility\Write-Verbose ('Window maximization ' + 'completed') } if ($Minimize) { Microsoft.PowerShell.Utility\Write-Verbose ('Minimize requested, ' + 'minimizing window.') $null = $window.Minimize() } # handle focus and foreground - if both requested, SetForeground handles both if ($SetForeground -eq $true) { Microsoft.PowerShell.Utility\Write-Verbose ('Setting window to ' + 'foreground (bringing to front and giving focus)') $null = $window.SetForeground() Microsoft.PowerShell.Utility\Write-Verbose ('Window foreground ' + 'operation completed') } elseif ($FocusWindow -eq $true) { Microsoft.PowerShell.Utility\Write-Verbose ('Focusing window') $null = $window.Focus() } # send keys if specified, after a delay to ensure window is ready if ($null -ne $KeysToSend -and ($KeysToSend.Count -gt 0)) { Microsoft.PowerShell.Utility\Write-Verbose ('Sending keystrokes ' + 'to window after 500ms delay. Keys to send: ' + "$($KeysToSend -join ', ')") Microsoft.PowerShell.Utility\Start-Sleep -Milliseconds 500 # copy identical parameters between functions $params = GenXdev.Helpers\Copy-IdenticalParamValues ` -FunctionName 'GenXdev.Windows\Send-Key' ` -BoundParameters $myPSBoundParameters ` -DefaultValues (Microsoft.PowerShell.Utility\Get-Variable ` -Scope Local -ErrorAction SilentlyContinue) # set the window handle for the send-key function $params.WindowHandle = $window.Handle $null = $params.Remove('Process') $null = $params.Remove('ProcessName') # send keys to the window Microsoft.PowerShell.Utility\Write-Verbose ("Calling Send-Key " + "with window handle $($window.Handle) and parameters: " + "$($params | Microsoft.PowerShell.Utility\Out-String)") $null = GenXdev.Windows\Send-Key @params -SendKeyHoldKeyboardFocus Microsoft.PowerShell.Utility\Write-Verbose ('Keystroke sending ' + 'operation completed') } } else { Microsoft.PowerShell.Utility\Write-Verbose ('No window object ' + 'available to position.') } # return window helper if passthru specified if ($PassThru -eq $true) { Microsoft.PowerShell.Utility\Write-Verbose ('PassThru specified, returning window object.') $window } } else { Microsoft.PowerShell.Utility\Write-Verbose ('ShouldProcess returned false, skipping window positioning.') } } else { Microsoft.PowerShell.Utility\Write-Verbose ('No process object available, skipping window positioning.') } } end { # only proceed if restore focus was requested if ($RestoreFocus) { $powerShellWindow = GenXdev.Windows\Get-PowershellMainWindow if (-not $powerShellWindow) { Microsoft.PowerShell.Utility\Write-Verbose 'Failed to retrieve PowerShell main window for focus restoration.' return } Microsoft.PowerShell.Utility\Write-Verbose ('RestoreFocus requested ' + 'and target window differs from PowerShell window') Microsoft.PowerShell.Utility\Write-Verbose ("Target window handle: " + "$($process.MainWindowHandle)), PowerShell handle: " + "$($powerShellWindow.handle)") Microsoft.PowerShell.Utility\Write-Verbose ('Restoring focus to ' + 'PowerShell window using Set-WindowPosition with ' + '-SetForeground and -FocusWindow') $null = $powerShellWindow.SetForeground(); Microsoft.PowerShell.Utility\Write-Verbose ('PowerShell window ' + 'focus restoration completed') } } } ################################################################################ |