PowerShell: Renaming And Sorting All My Music Files, Updated

I wrote a script to rename all my music files with preceding disk and track numbers here.  The script ran fine, but there were a few niggles and skipped files.  So after a bit of polish, here’s the updated script (and what I changed).

The original script processed all the music files and logged a message (via an object) for each it couldn’t process.  I assumed there’d only be a handful and I could change them manually.  Unfortunately, that wasn’t the case.  When I did a bit of investigating there were a couple of problems.

Many of the music files had metadata titles with characters that were invalid for filenames.  In the original script, there was a fallback solution where if the rename caused an error (like if it had an invalid character) then the script would simply add the track and disk number to the front of the existing filename.

Problem 2 took a bit of troubleshooting;  in some cases even just adding the track number to the front of the existing filename generated an error!  I knew numbers and “-” were valid, so I was a bit stumped.

After a bit of trial-and-error I realised many of of the filenames had “[” or “]” in them.  These were valid in filenames but invalid in file paths.

😦

I was trying to get around the problem with ever more byzantine try-catch statements to get all the errors and the code was looking like a nightmare.  So I took a step back.

I wrote a function to correct the invalid characters in the names;

function Replace-InvalidCharacters
{
param
(
[parameter(Mandatory=$True)]
[string]$Source
)
Write-Verbose "Checking $Source for Invalid Characters."
$Source -replace "\[","(" -replace "\]",")" -replace "[\\\/]","-"
}

This function took a string and replaced any invalid characters with suitable (filename friendly) alternatives.

Here’s the changed code that calls the function;

        $NewFileName=Replace-InvalidCharacters ($TrackNumber.PadLeft(2,"0")+"-"+$Metadata.Title+((gci $path).Extension))
        if (!(Test-Path -IsValid $NewFileName))
        {
            $Object.Result += "Track title invalid for a filename."
            $NewFileName=Replace-InvalidCharacters ($TrackNumber.PadLeft(2,"0")+"-"+$Object.OriginalName)
            Write-Verbose "Trying New FileName : $NewFileName"
        }
        if (!(($Metadata.Disc -eq $Null) -or ($Metadata.Disc -eq "")))
        {
            $NewFileName=([string]$Metadata.Disc).PadLeft(2,"0")+"-"+$NewFileName
        }

It sends the calculated filename (built from the metadata title and the tracknumber) to the function to replace invalid characters.

It tests that as a path;  if it’s still invalid we use the original filename (instead of the title) and replace any invalid characters.

Finally we add the disk number to the front (if present) and go forward with the rest of the code (as before).

Here’s the full script;

[CmdletBinding()]
param
(
    [parameter(Mandatory=$True,ValueFromPipeline=$True)]
    [string[]]$Path
)
BEGIN
{

    function Replace-InvalidCharacters
    {
        param
        (
            [parameter(Mandatory=$True)]
            [string]$Source
        )
        Write-Verbose "Checking $Source for Invalid Characters."
        $Source -replace "\[","(" -replace "\]",")" -replace "[\\\/]","-"
    }

    function Set-FileName
    {
        param
        (
            [parameter(Mandatory=$True)]
            [string]$Path
        )
        Write-Verbose "Processing $Path"
        $Object=New-Object PSObject
        $Object | Add-Member NoteProperty OriginalPath $Path
        $Object | Add-Member NoteProperty OriginalName (Split-Path $Path -Leaf)
        $Object | Add-Member NoteProperty Updated $False
        $Object | Add-Member NoteProperty Result $Null
        $Object | Add-Member NoteProperty Error $Null
        $Metadata=Get-MediaInfo $Path
        if ($Metadata -eq $Null)
        {
            $Object.Result = "No Metadata returned"
            Return $Object
        }
        $Metadata=$Metadata.Tag
        if (($Metadata.Track -eq $Null) -or ($Metadata.Track -eq ""))
        {
            $Object.Result = "No Track #"
            Return $Object
        }
        [String]$TrackNumber=$Metadata.Track
        if ($Metadata.Title -match "^\d")
        {
            $Object.Result = "Title starts with a number."
            Return $Object
        }
        $NewFileName=Replace-InvalidCharacters ($TrackNumber.PadLeft(2,"0")+"-"+$Metadata.Title+((gci $path).Extension))
        if (!(Test-Path -IsValid $NewFileName))
        {
            $Object.Result += "Track title invalid for a filename."
            $NewFileName=Replace-InvalidCharacters ($TrackNumber.PadLeft(2,"0")+"-"+$Object.OriginalName)
            Write-Verbose "Trying New FileName : $NewFileName"
        }
        if (!(($Metadata.Disc -eq $Null) -or ($Metadata.Disc -eq "")))
        {
            $NewFileName=([string]$Metadata.Disc).PadLeft(2,"0")+"-"+$NewFileName
        }
        Try
        {
            Rename-Item -Path $Path -NewName $NewFileName -ErrorAction Stop
        }
        Catch [System.Exception]
        {
            $Object.Result += "Unable to rename item."
            $Object.Error=$_.Exception.Message
            Return $Object
        }
        Write-Verbose "Updated file successfully."
        $Object.Updated=$True
        $Object
    }

    Write-Verbose "Importing MP3Tag Library"
    $myDocumentsFolder = [Environment]::GetFolderPath("MyDocuments")
    $scriptsFolder="\docs\scripts"
    $MPTagFolder="\mptag"
    #Import the MPTag module
    Import-Module ($myDocumentsFolder+$scriptsFolder+$MPTagFolder)

}
PROCESS
{
    foreach ($PathItem in $Path)
    {
        gci -File $PathItem -Recurse | %{Set-FileName -path $_.FullName}
    }
}

1 thought on “PowerShell: Renaming And Sorting All My Music Files, Updated”

  1. Powershell: It’s like someone saw a perl script, and thought: “that’s too obvious, how can I obfuscate it even more?”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s