Behind the PowerShell Pipeline logo

Behind the PowerShell Pipeline

Subscribe
Archives
March 11, 2025

Extending PowerShell Objects with ScriptMethods

We're in the midst of building a tool set to help me manage my MuseScore files. You should be able to apply the techniques and concepts to your work, especially if you are creating functions that write custom objects to the pipeline. When we left off, I had a function that creates a custom object from a MuseScore file.

PS Hypnos:\> Get-MuseScoreProperty

Title     : Hypnos Suite
SubTitle  : Nocturne for Chamber Orchestra
Composer  : Jeffery D. Hicks
Copyright : (c) 2023-2025 Jeffery D. Hicks - all rights reserved
Software  : MuseScore 4.4.4
Online    : https://musescore.com/user/26698536/scores/13605262
CoverArt  : C:\Users\Jeff\Documents\MuseScore4\Scores\nocturne-chamber-orchestra\slumber.jpg
MP3       : C:\Users\Jeff\Documents\MuseScore4\Scores\nocturne-chamber-orchestra\Hypnos Suite.mp3
Length    : 00:12:39
Date      : 3/3/2025 12:00:00 AM
Path      : C:\Users\Jeff\Documents\MuseScore4\Scores\nocturne-chamber-orchestra\
Duration  : 00:12:39

I even extended the object to define an alias and a property set.

PS Hypnos:\> Get-MuseScoreProperty | Get-Member

   TypeName: MuseScoreInfo

Name          MemberType    Definition
----          ----------    ----------
Duration      AliasProperty Duration = Length
Equals        Method        bool Equals(System.Object obj)
GetHashCode   Method        int GetHashCode()
GetType       Method        type GetType()
ToString      Method        string ToString()
Composer      NoteProperty  string Composer=Jeffery D. Hicks
Copyright     NoteProperty  string Copyright=(c) 2023-2025 Jeffery D. Hicks - all rights reserved
CoverArt      NoteProperty  string CoverArt=C:\Users\Jeff\Documents\MuseScore4\Scores\nocturne...
Date          NoteProperty  datetime Date=3/3/2025 12:00:00 AM
Length        NoteProperty  System.TimeSpan Length=00:12:39
MP3           NoteProperty  string MP3=C:\Users\Jeff\Documents\MuseScore4\Scores\nocturne-chamb...
Online        NoteProperty  string Online=https://musescore.com/user/26698536/scores/13605262
Path          NoteProperty  string ath=C:\Users\Jeff\Documents\MuseScore4\Scores\nocturne-chamb...
Software      NoteProperty  string Software=MuseScore 4.4.4
SubTitle      NoteProperty  string SubTitle=Nocturne for Chamber Orchestra
Title         NoteProperty  string Title=Hypnos Suite
RecordingData PropertySet   RecordingData {Title, Subtitle, MP3, Online, Duration, CoverArt}

PS Hypnos:\> Get-MuseScoreProperty | Select RecordingData

Title    : Hypnos Suite
SubTitle : Nocturne for Chamber Orchestra
MP3      : C:\Users\Jeff\Documents\MuseScore4\Scores\nocturne-chamber-orchestra\Hypnos Suite.mp3
Online   : https://musescore.com/user/26698536/scores/13605262
Duration : 00:12:39
CoverArt : C:\Users\Jeff\Documents\MuseScore4\Scores\nocturne-chamber-orchestra\slumber.jpg

I enjoy exploring how far I can go with this process, so I decided to extend the object with several ScriptMethod members. I've demonstrated in other articles to to create a ScriptProperty that executes a PowerShell script block to return a value. A ScriptMethod also executes a script block, but it performs an action with the object.

ScriptMethod

If I wanted to perform an action on multiple objects, it probably makes more sense to create a function that accepts pipeline input. However, the methods I have in mind only make sense when invoked on a single object. Yes, I could still write a function that processes a single object, but I want a reason to demonstrate creating a ScriptMethod.

The score object includes a property with the path to the MP3 file.

PS Hypnos:\> $score = Get-MuseScoreProperty
PS Hypnos:\> $score.mp3
C:\Users\Jeff\Documents\MuseScore4\Scores\nocturne-chamber-orchestra\Hypnos Suite.mp3

Why not create a method to play the MP3 file?

Update-TypeData -TypeName MuseScoreInfo -MemberType ScriptMethod -MemberName Play -Value {
    If (Test-Path $this.MP3) {
        Invoke-Item $this.MP3
    }
    else {
        Write-Warning "Can't find the MP3 file for this score."
    }
} -Force

It is possible the score won't have an MP3 file so I need to test the path. If the file exists I'll use Invoke-Item to open the file. This cmdlet will launch the default application associated with MP3 files. If the file doesn't exist, I'll write a warning message.

Don't forget that the Value property is a script block. Use $this to reference the current object. Using the method is a sample as this:

$score.play()
Want to read the full issue?
GitHub Bluesky LinkedIn About Jeff
Powered by Buttondown, the easiest way to start and grow your newsletter.