Musings of a dad with too much time on his hands and not enough to do. Wait. Reverse that.

Tag: powershell (Page 3 of 7)

Sorting your teammates randomly

You go first? No, you go first.

Every week, my team has a status meeting where we spend part of the time going around our virtual meeting room getting updates from each team member. To try to keep things fair, my manager attempts to randomly pick the next team member to give his or her update. If she really wanted to be fair, she’d simply run this PowerShell command every week:

"Larry","Moe","Curly","Doc","Sneazy","Grumpy"|sort {random}

Here, I start with an array of my team members.: Larry, Moe, Curly, Doc, Sneazy, and Grumpy. I pipe that array to the Sort-Object cmdlet. The “random” portion of the sort command basically tells the sort to sort the list according to the large random number that is generated. This doesn’t feel completely random to me and I’m not sure it would work well for teams larger than nine people, but it certainly works better than drawing names out of a hat–or the manager’s head, for that matter.

Hat tip to this blog post for the inspiration.

Scanning slides, Part 2

Believe it or not, you used to be able to walk right up to the White House

A while back, I wrote about some PowerShell tricks I use as I scan the thousands of slides my dad has amassed over the last five decades. I did leave one small trick out, though, that I wish to share now.

As I scan old photos, I do my best to document every detail I can about the picture: when it was taken, where, who are the people in the photo, etc. One of these days, I’ll figure out a more robust way to store these details, but for now, I write them to text files that I keep in the very folders of the images they describe.

When I first began genealogy back in the 1990s, a lot of the software I worked with professionally used INI configuration files in which a section would begin left-aligned in the file and all other lines for the section would be tab-indented underneath. This is the format I adopted back then and, for consistency sake, have continued with ever since:

Example of my current image documentation file

So, you might be asking yourself, “self, what does any of this have to do with PowerShell?” Well, as I scan a set of slides, I’ll house them in their own folder. Then, I’ll run PowerShell like the following to quickly generate a readme/documentation text file to describe the images:

# generate a readme file for the directory
$dir = "C:\my_path\slides\grp_007"
$desc_line1 = "Slide appears to be dated "
$desc_line2 = "Slide is number #.  Photographer was likely John Jones. Slide is labeled 'Kodachrome II Transparency'. Slide was part of a metal container labeled magazine number '2'. Handwritten label on slide case reads, "
gci $dir | where {$_.Extension.ToLower() -eq ".jpg"} | foreach{"{0}`r`n`t{1}`r`n`t{2}`r`n" -f $_.Name, $desc_line1, $desc_line2} | Out-File ("{0}\readme_grp007.txt" -f $dir)

This code will quickly scaffold out my documentation file and save me a lot of typing. Typically, each slide has some sort of handwritten label that I’ll also want to capture in the readme file, so I’ll still have to go through each slide and type out the label corresponding to the image, but most of the slides share many of the same properties and being able to capture all those common properties at once is a great time saver.

Positioning Windows with PowerShell

When it comes to multiple monitor displays connected to my workstations–either at home or at work–I’m a little like Tim “the Toolman” Taylor: I need more!  And just as I carefully separate my peas and carrots, I must carefully separate the sort of tasks I perform on each monitor.  For example, I like to do my folder and file browsing in my right most monitor and in my left most monitor, I like to do my command shell work.

At work, I interface with a lot of Linux servers, so I tend to have a few command shells open at once connected to these systems.  Since I like to have these shells in my left most monitor, I sought out a solution to automatically launch and proportionally position multiple command shells in my left most monitor.  Initially, I did this with an AutoIt script.  That was an OK solution, but I didn’t find it all that flexible.  I work at home occasionally and my multiple monitor setup is different between home and work.  I found it challenging to make my AutoIt script sufficiently adaptive between each environment.  So, I embarked on a PowerShell solution for my problem.  Here’s how I went about crafting my solution:

Step 1: Establish a windows positioning solution

AutoIt already has a nice window positioning library included with it, but PowerShell does not.  Fortunately, someone wrote a great solution called Set-Window.  I downloaded this script and made two small alterations:

  1. I turned the script into a PowerShell module (PSM1) so that more than one PowerShell script I write can take advantage of this tool and
  2. I changed the script’s ProcessName parameter to ProcessId.  That way, I could pass the script the process id of the window I want to position and there would be no ambiguity as to the exact window I want to change.  You can find my modifications here.

Step 2: Figure out where my left most window is

To be honest, I never explored whether or not AutoIt could give me all the properties of the monitors attached to my workstation, but I knew PowerShell could and that was enough for me.  The .NET namespace System.Windows.Forms.Screen contains an AllScreens function that easily gives me all the details I want.  All I need to do is sort by the X coordinate and grab the first returned record to capture the properties of my left most monitor:


1
2
3
4
5
Add-Type -AssemblyName System.Windows.Forms
$left_most_screen = [System.Windows.Forms.Screen]::AllScreens|sort -Property {$_.WorkingArea.X}|select -First 1
$x = $left_most_screen.WorkingArea.X
$screen_width = $left_most_screen.WorkingArea.Width
$screen_height = $left_most_screen.WorkingArea.Height

Step 3: Launch my command shell instances and position them accordingly

The last step is to run a loop for the number of command shells I want to open.  At present, I’m setting a variable to 2 shells, but I can always change that variable and the script will automatically adjust.  Note that for my shells, I’m using the Ubuntu instance of the Windows Subsystem for Linux (WSL).  In each loop, the script performs three tasks:

  1. It launches a new shell instance
  2. It does some simple math to figure out where to place the shell in the left most monitor and
  3. It calls Set-Window to do the positioning

One note: on my work monitor, when I first call Set-Window on a command shell, it mysteriously sets a slightly smaller height and width for the window.  I’ve found that the easiest fix for this problem is to simply call Set-Window a second time:


1
2
3
4
5
6
7
8
9
1..$nbr_of_windows_to_open|%{
    $app = Start-Process $ubuntu_path -PassThru
    Start-Sleep -Seconds 3
    $y = ( ($_ - 1) * ($screen_height / $nbr_of_windows_to_open) )
    $h = ( $screen_height / $nbr_of_windows_to_open )
    Set-Window -ProcessId $app.Id -X $x -Y $y -Width $screen_width -Height $h -Passthru
    # strangely, on some monitors, the first Set-Window doesn't quite take, but setting it again seems to work
    Set-Window -ProcessId $app.Id -X $x -Y $y -Width $screen_width -Height $h -Passthru
}

You can find my full solution here.  To truly functionalize this solution, I can (and do) take two more steps:

  1. Wrap my PowerShell script in a batch script.  In a BAT file, I can write a command like so: powershell -command “& ‘C:\somePath\launch_ubuntu_windows.ps1’ ” -ExecutionPolicy Bypass
  2. Call that BAT file from Slickrun

But wait, there’s more

I recently replaced my work laptop.  More memory, more power…a true Tim “The Toolman” Taylor moment.  I’m now running the script I described above to launch and neatly place a couple of command shells in my new-and-improved system.  But a frustrating situation occurs to me, not all the time, but enough to be annoying.  I will launch my shells, do a few hours of work, then get up to stretch my legs, get some coffee or otherwise move away from my workstation.  Before moving away, I lock my workstation like any decently security-minded person would.  When I get back, quite often, all my applications, including my command shells, have shifted off my extended monitors and on to my main monitor, negating all the work I did to line them up just right on my extended displays.  I don’t want to re-run my “launch” script again because I don’t need to open more shells–just reposition the ones I already have open.  What I now need is a repositioning script!

My repositioning script works exactly like my “launch” script, only, instead of starting brand new command shell processes, it uses PowerShell’s Get-Process cmdlet to find the already open command shells, get their PIDs, and reposition them the same way as I did before.  Here’s a snippet:


1
2
3
4
5
6
7
8
9
10
$running_ubuntu_pids = Get-Process|?{$_.Name -eq "Ubuntu"}|select Id
$count = 1
foreach($uPid in $running_ubuntu_pids){
    $y = ( ($count - 1) * ($screen_height / $running_ubuntu_pids.Count) )
    $h = ( $screen_height / $running_ubuntu_pids.Count )
    Set-Window -ProcessId $app.Id -X $x -Y $y -Width $screen_width -Height $h -Passthru
    # strangely, on some monitors, the first Set-Window doesn't quite take, but setting it again seems to work
    Set-Window -ProcessId $app.Id -X $x -Y $y -Width $screen_width -Height $h -Passthru
    $count++
}

What next?

So far, I’ve only played around with launching and position 2-3 command shells.  If I ever get the urge to launch four or more, I should probably work out the math to position all those shells in a grid-like pattern.  Also, it’d be nice to have a script that launches, positions, and repositions all types of applications, not just my command shells.  Maybe even a script that will memorize the current positions of my applications and use that to reposition them as needed.

« Older posts Newer posts »

© 2024 DadOverflow.com

Theme by Anders NorenUp ↑