2

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!

pax
  • 1,547
  • 2
  • 16
  • 46
  • I'm curious myself if this could be done purely with powershell. But if not, powershell does give you access to the entire .NET framework, so you could look into trying to adapt a C# solution for the same thing into a powershell script. e.g - https://stackoverflow.com/questions/1538602/find-number-and-resolution-to-all-monitors . And though I doubt this is an adequate solution for you, have you seen microsoft's "powertoys" utility? It has a feature called Fancy Zones that lets you design and save custom window layouts / workspaces – diopside Nov 07 '21 at 18:56
  • correct URL: https://learn.microsoft.com/en-us/windows/powertoys/fancyzones – diopside Nov 07 '21 at 18:57
  • 1
    Hi @diopside - Ihe fancyzones application doesn't provide the capability to open apps and then dock the app windows to different positions on multiple monitors. Or am I missing something? – pax Nov 08 '21 at 14:15
  • no you're not missing anything, its basically just a window arranger. Just figured i'd throw it out there since arranging your windows seemed like a small, probably trivial, part of what you want to do – diopside Nov 08 '21 at 17:41
  • I do need to arrange those windows, but I need to automatically open those apps first :) – pax Nov 08 '21 at 17:44

1 Answers1

0

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

PsychoData
  • 1,198
  • 16
  • 32
  • Hey @PsychoData, thanks for the answer, I didn't get to implement it yet. I'll do my best to get to it the upcoming weekend and then I'll accept it. – pax Dec 06 '21 at 17:17