Behind the PowerShell Pipeline logo

Behind the PowerShell Pipeline

Subscribe
Archives
April 11, 2025

Control Scripting

I've spent a few issues reviewing how I built a PowerShell tool to insert text into a graphic image. The function I wrote and demonstrated last time, will work with any graphic file, even though I created the function with a specific use case in mind. I want to take an image file associated with one of my musical compositions, insert the name, and use the image in the MP3 file. I also want to make this an easy to invoke repeatable process. When I update a score, I'll end up with a new MP3 file which will need to be updated again.

I have taken the functions I wrote for manage my score files into a module. The module is not in a PSModulePath location, so I import it specifying the path.

Import-Module c:\scripts\MuseScoreTools -force

I have created a test folder to use during development so that I don't pollute my original score files.

The MP3 file has already been updated with tags.

PS C:\temp\violin-nocturne> Get-MuseScoreMp3 '.\Nocturne for Violin.mp3' | Tee -Variable a

Title       : Nocturne for Violin
Subtitle    : in G Minor
Length      : 00:05:40
Composer    : {Jeffery Hicks}
Album       :
Track       : 0
Year        : 2023
Genre       : {Classical}
Description : https://musescore.com/user/26698536/scores/7210278
Comment     : This is a computer generated performance. Created with MuseScore 3.6.2
Copyright   : c. 2021-2023 Jeffery D. Hicks
Size        : 5488208
Path        : C:\temp\violin-nocturne\Nocturne for Violin.mp3

The original cover image is stored in the MP3.

Raw MP3 cover image
figure 1

What I need is a PowerShell solution that merges my stand-alone Add-TextToImage function with tools in the MuseScoreTools module. I could add the function to the module and update the module commands. But if I wanted to use the function for something else, I'd have to remember it is in the MuseScoreTools module. What I don't want is to have the same function in two locations because that means twice as much maintenance.

Instead, I think I will create a stand-alone script file. I can load the function and import the module in the script file. Given that every image will be different, each cover image will have a different font style and color. My initial design consideration is that I will manually invoke the script on a single folder.

This gives me a starting point for the control script.

#requires -version 7.5
#requires -module pwshSpectreConsole

#C:\Scripts\UpdateScoreMPCover.ps1

Param(
    [Parameter(HelpMessage = 'The path to the MuseScore files')]
    [string]$Path = "."
)

. C:\scripts\Add-ImageText.ps1
Import-Module C:\scripts\MuseScoreTools -Force

Organize

When approaching a control script, I think you'll find it helpful if you can verbalize each step in the process. Unlike a function which is designed to do one task, a control script is an orchestration of tasks. Take the time up front to organize your thoughts. Even better, write them in your script file as comments.

#convert the path to a full file system path

#Get the MP3 file in the location. There should only be one.

#Validate that the MP3 file tags have been updated.

#Update the MP3 file if missing information.

#Test for cover image settings

#import cover image settings if found

#otherwise use parameter values

#Create a preview image file of the cover image with imported or parameter settings

#update the MP3 file with preview cover image

#show the new image

#export the cover image settings

Since I want to be able to quickly refresh a cover image with text, I intend to save settings like font and color in a JSON file. My comments layout a workflow. Looking at the comments and visualizing the process also ensure I have steps in the proper order. All I need to do now is write code to implement the steps. When I'm finished, they will already be documented!

Getting paths is simple enough.

#convert the path to a full file system path
$Path = Convert-Path $Path

#Get the MP3 file in the location. There should only be one.
$mp3Path = (Get-ChildItem -Path $Path -Filter *.mp3).FullName

As is validating that the MP3 file has been updated.

#Validate that the MP3 file tags have been updated.
$mp3Tags = Get-MuseScoreMp3 -Path $mp3Path
if (-Not $mp3Tags.Title) {
    #Update the MP3 file if missing information.
    Write-Host "Updating MP3 tags" -ForegroundColor Yellow
    Update-MuseScoreMp3 -Path $mp3path
    Write-Host "MP3 tags updated" -ForegroundColor Green
    $mp3Tags = Get-MuseScoreMp3 -Path $mp3Path
}

After writing the code, I realized I need to move one of the workflow comments up. I should also explain that I am manually executing each block of code interactively in my test folder. If the code works, I copy and paste it into the control script. If I mess things up, I can re-copy the source files into the test folder.

Want to read the full issue?
GitHub Bluesky LinkedIn Mastodon https://jdhitsoluti…
Powered by Buttondown, the easiest way to start and grow your newsletter.