powershell script: open apps and position windows

Viewed 698

DISCLAIMER: I'm new to PowerShell - I watched a few tutorials on YouTube.

THE-PROBLEM: Before work I need to do the following: (I have a 3 screen/monitor setup)

  1. open VSCode
  2. maximize VSCode on my middle screen
  3. open 4 (four) instances of powershell
  4. dock the powershell windows on my left-hand side screen and dock them (top-left, top-right, bot-left, bot-right) - I need 4 instances, because I have multiple different processes running at the same time
  5. open Chrome
  6. maximize Chrome on my right-hand side screen

I figured out how to open the apps I need at a certain path, but that's about it :(

Start-Process -FilePath 'C:\Users\...\Code.exe' -ArgumentList 'C:\repos'
Start-Process -FilePath 'C:\Windows\...\powershell.exe' -ArgumentList 'C:\repos'

I didn't find any commands in the PowerShell documentation with which I could get a reference to the monitors connected to my PC.

Long story short - this is what i need to do, written in pseudo-code:

// $screenMid = get the mid screen object (reference)
// $vscodeIinstance = open VSCode at a path
// $vscodeIinstance.position = $screenMid.position.maximize()


// $screenLeft = get the left screen object (reference)

// $powershellWindowOne = open PS at a path
// $powershellWindowOne.position = $screenLeft.position.dockTopLeft()

// $powershellWindowTwo = open PS at a path
// $powershellWindowTwo.position = $screenLeft.position.dockTopRight()

// ...do the same for another two PS windows (dockBotLeft, dockBotRight)


// $screenRight = get the right screen object (reference)
// $browser = open browser with url
// $browser position = $screenRight.position.maximize()

I've been doing this every single workday for some time now, so I'm trying to automate the full process.

It's been a couple of days since I started looking for a solution. No luck so far.

Thank you all for help!

1 Answers

Finding Monitor Objects

To find a listing of monitors connected to your PC try this

Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Screen]::AllScreens

Here is a sample of how it returns on my system, where you can see the Working Area is the actual X and Y coordinates that the monitor covers.

Add-Type -AssemblyName System.Windows.Forms
PS C:\> [System.Windows.Forms.Screen]::AllScreens


BitsPerPixel : 32
Bounds       : {X=0,Y=0,Width=1920,Height=1080}
DeviceName   : \\.\DISPLAY9
Primary      : True
WorkingArea  : {X=0,Y=0,Width=1920,Height=1032}

BitsPerPixel : 32
Bounds       : {X=1920,Y=0,Width=1920,Height=1080}
DeviceName   : \\.\DISPLAY1
Primary      : False
WorkingArea  : {X=1920,Y=0,Width=1920,Height=1032}

Initially, the coordinates might not seem particularly useful, but consider if the monitors were arranged unevenly - they might not be such clean numbers. For example take this image with monitors partially offset Images of monitors that don't line up easily

it returns much less simple/clean numbers than the first example

PS C:\>
PS C:\> [System.Windows.Forms.Screen]::AllScreens


BitsPerPixel : 32
Bounds       : {X=0,Y=0,Width=1920,Height=1080}
DeviceName   : \\.\DISPLAY9
Primary      : True
WorkingArea  : {X=0,Y=0,Width=1920,Height=1032}

BitsPerPixel : 32
Bounds       : {X=1920,Y=293,Width=1920,Height=1080}
DeviceName   : \\.\DISPLAY1
Primary      : False
WorkingArea  : {X=1920,Y=293,Width=1920,Height=1032}

NOTE: If you change the monitor Layout after the PowerShell session has started, the session doesn't pick it up - it's probably something about an instance of System.Windows.Forms being reused, and only built at construction, not dynamically as you ask for it. Just start a new PowerShell session to check it.

Which Monitor is where?

How do we find the leftmost, rightmost, etc monitor? You can use the WorkingArea to tell which monitor is leftmost

[System.Windows.Forms.Screen]::AllScreens | sort -Property {$_.WorkingArea.X} | select -First 1

Rightmost? Flip the Sort with -Descending

[System.Windows.Forms.Screen]::AllScreens | sort -Property {$_.WorkingArea.X} -Descending | select -First 1

OK, so you have three monitors and want the middle? Skip the first and take 1 to get the second

[System.Windows.Forms.Screen]::AllScreens | sort -Property {$_.WorkingArea.X} -Descending | select -skip 1 -first 1

OK, OK, but what if I have Vertical monitors? If you just have one that is top or bottom, you might be able to get away with something similar, but just $_.WorkingArea.Y but if not you might need to filter first.

#Simple Filter for top monitor
```powershell
[System.Windows.Forms.Screen]::AllScreens | sort -Property {$_.WorkingArea.Y} -Descending | select -first 1

But what if you have multiple? One Laptop monitor on the bottom, with three monitors arranged on equal horizontally up above

#Filter for top monitors, then select middle monitor
```powershell
#Get all of the Top Edge heights and finding the highest Top Edge 
$UpperBounds = [System.Windows.Forms.Screen]::AllScreens.WorkingArea.Top | select -Unique

#Find all monitors whose top-edge is on the highest physically (0,0 is the top,left) 
$HighestBound = $UpperBounds | Sort | select -first 1
$highLevelMonitors = [System.Windows.Forms.Screen]::AllScreens | where {$_.WorkingArea.Top -eq $HighestBound} 

#Find the middle monitor of the highest monitors, like above
$highLevelMonitors | sort -Property {$_.WorkingArea.X} | select -Skip 1 -first 1

Related