How can I change middle item of path in PowerShell?

81 views Asked by At

I would like to invoke ImageMagick to compare images by SSIM. The images are in following directory structure:

+ root
  |
  +- FooBar
  |  |
  |  +- 2023-10
  |  |  \- *.png
  |  \- 2023-11
  |     \- *.png
  \- FooBar.cmp
     |
     +- 2023-10
     |  \- *.jpg
     \- 2023-11
        \- *.jpg

Images in root\FooBar and root\FooBar.cmp follow in some rules:

  • FooBar is replaced with actual application name
  • root\FooBar is original image
  • root\FooBar.cmp is "compressed" image (how they done is not important in this question)
  • They are named in format of FooBar_%Y-%m-%d_%H-%M-%S.<millisecond>_<display_w>x<display_h>.<extension>, where:
    • % and following character is replaced with corresponding C's strftime formatting element with taken date.
    • <millisecond> is replaced with the millisecond of taken date.
    • <display_w> is the width of the resolution.
    • <display_h> is the height of the resolution.
    • <extension> is either png or jpg.

I've tried:

Get-ChildItem .\root\FooBar -Recurse -Include "*.png" | % { $new = Join-Path -Path $_.Directory.Parent.Parent.FullName -ChildPath ($_.Directory.Parent.Name + ".cmp"); $new = Join-Path -Path $new -ChildPath $_.Directory.BaseName; $new = Join-Path -Path $new -ChildPath ($_.BaseName + ".jpg"); magick compare -metric SSIM $new $_  NUL 2>&1 | % ToString }

(2>&1 | % ToString avoids implicit RemoteException, please ignore)

However, it is not elegant because I would like to modify "middle" element of path.

For example, given root\FooBar\2023-11\2023-11-01_02-03-04.567_890x1234.png, corresponds root\FooBar.cmp\2023-11\2023-11-01_02-03-04.567_890x1234.jpg. Is there any way to shorten this where $PSVersionTable is following? Also what if I update PS to latest version?

PS> $PSVersionTable

Name                           Value                                                                                                                                                                        
----                           -----                                                                                                                                                                        
PSVersion                      5.1.19041.3570                                                                                                                                                               
PSEdition                      Desktop                                                                                                                                                                      
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                                                                                                                                                      
BuildVersion                   10.0.19041.3570                                                                                                                                                              
CLRVersion                     4.0.30319.42000                                                                                                                                                              
WSManStackVersion              3.0                                                                                                                                                                          
PSRemotingProtocolVersion      2.3                                                                                                                                                                          
SerializationVersion           1.1.0.1 
1

There are 1 answers

3
mclayton On

Writing on phone, so shooting from the hip a little bit, but this should work (apart from some possible syntax errors / simple tweaks required).

# get fully qualified paths to folders
$leftRoot  = Convert-Path ".\root\FooBar"
$rightRoot = Convert-Path ".\root\FooBar.cmp"

Get-ChildItem $leftRoot -Recurse -Include *.png | 
    ForEach-Object {
        $leftFile  = $_.FullName;
        $rightFile = [System.IO.Path]::ChangeExtension(
            $rightRoot + $leftFile.Substring($leftRoot.Length),
            "jpg"
        );
        magick compare -metric SSIM $rightFile $leftFile … etc …
    }