Write the command so that it could target multiple computers (no error handling needed) if desired

Want to go obscure? Feel free to use aliases and whatever other shortcuts you want to produce a teeny-tiny one-liner.

Now, I will be the first to admit that one-liners are not my strong point. My scripts tend to be pretty verbose; I don’t often use aliases, and even after several years of using PowerShell I still stumble when reading code like this:

So, with verbosity in mind and with the realisation that at least two WMI classes would need to be queried to solve this puzzle, I first thought about how I might solve this if I wasn’t restricted to one line of code. The solution is pretty straight forward:

Query the two WMI classes, make a custom object with the required properties and then output the object.

Because of the challenge to use no more than one semicolon, I was keen to try and avoid using semicolons to separate the statements. The alternative I found, which at the time I thought was pretty clever, was to separate the commands using parentheses and commas.
What I later realised is that what this is doing is generating an array where each array member is the result of the command run in the parentheses. This is why I had to use Out-Null to suppress PowerShell’s desire output all three elements to the display.

So, I was down to one line but still had too many semicolons. Next up was to find an alternative way to create the object. Rather than use the [PSCustomObject] accelerator, I opted for the old-school cmdlet New-Object and its friend Add-Member. Format-Table was used to format the output exactly as specified in the puzzle, without it there were too many tabs.

The next step was to use aliases to reduce the amount of text. I also took advantage of PowerShell’s ability to recognise parameters using the fewest number of unique characters to shorten them as far as possible:

Finally, I had to handle multiple computers. I opted for Read-Host for this, and just used a while loop to enable the user to keep entering computer names until they get bored and use ctrl + c to exit.

There is no doubt that this is a very awkward solution to a fairly simple problem; clearly it’s not the kind of solution that the puzzle setter had in mind. That said, with the exception of its phenomenal length, it does meet the brief :).

Note: All code can be entered on a single line with out pressing ENTER until you’ve typed the last character, I’ve wrapped the lines at natural points to aid readability.

When you rip a CD into Windows Media Player (WMP), WMP will attempt to retrieve information about the album from the Internet. I have encountered a problem with this where, sometimes, all of the album information is retrieved except for the information for the first track. Instead of showing the correct track name and associated album, the track is orphaned as ‘Track 1’ belonging to ‘Unknown Album (DD/MM/YY HH/MM/SS)’.

When ripping music, for a single album, this is trivial, a minor inconvenience quickly fixed with a manual edit. However, if WMP rebuilds the media library, such as when you move your music collection to a different partition, you may be left with hundreds of orphaned tracks. The reason for this is that WMP repopulates the library using the meta data for the music file. If you view the meta data by opening the Details tab for the file in Windows Explorer you will see that it’s incorrect.

In this article I will show how the information for the track can be retrieved from the full filename and then used to populate the information in the WMP library, this will ensure that the tracks are displayed correctly when viewed in WMP.

The output from Get-Member shows us that the $wmp object has a mediaCollection property. The mediaCollection property is itself an object and we can pipe this object to Get-Member to explore its properties and methods.

We can see that the mediaCollection object provides several methods that could be used to query the library. Our orphaned tracks are missing or have incorrect data for Author, Genre, and Album but do we know that they’re consistently named ‘Track 1’ so we will use the getByName() method.

The getbyName() method will return a Playlist object containing all of the media items in the library called ‘Track 1’.

$playList = $wmp.mediaCollection.getByName('Track 1')

Each item in the playlist is referenced by an index number, starting at 0. So to assign the first item in the playlist to the variable $item we would use:

$item = $playList.Item(0)

To access each item in the playlist in turn we can use a for loop to increment the index number.

All of the information about the track that we want to update can be obtained from its full filename. The full filename is stored in the sourceURL attribute. This is accessed using the getItemInfo() method which accepts an attribute name as an argument.

To obtain the track name we can use Split-Path to get the filename from the sourceURL.

$fileName = $sourceURL | Split-Path -Leaf

The filename will have the format ‘nn Track Name.abc’ where nn is the track number and .abc is the file extension of the media file. To set the track name, we only require the ‘Track Name’ substring which we can obtain as follows:

The album name is the parent folder of the media file which we can obtain by splitting the path twice.

$albumName = $sourceURL | Split-Path | Split-Path -leaf

The artist name is the parent folder of the album folder which we can obtain by splitting the path three times.

$artistName = $sourceURL | Split-Path | Split-Path | Split-Path -leaf

One situation where this does not have the desired result is where the album is by various artists as this will result in the Artist attribute being set to ‘Various Artists’ rather than the actual artist that performed that particular track.

Once we have the required information we can update the item’s information using the setItemInfo() method which we call with two arguments, the name of the attribute that we want to update and the new value for the attribute.

In the final version of the script, I wrapped getting and setting of the information in a try catch block in case I was left with any tracks that could not be updated. I also chose not to process any items where the filename included the string ‘Unknown Artist’. If WMP has stored the album as ‘Unknown Artist’ it was unable to get information for that CD from the Internet, therefore the information in the file name is not correct and it’s pointless updating the library.

Finally, during testing, I found that the library does not always update straight away.
There is mention made of this in the documentation which states that “If you write code using the Windows Media Player control to change the value of an existing read/write attribute in a media item that has been added to the library, the effect is nearly the same as if the user had modified the attribute using Windows Media Player. The value is written to the library database and at some indeterminate time the database synchronizes with the file.”.
Releasing the COM object, with the final line of code, seems to consistently speed up this process.

Post Script
When I originally wrote this article I had not found a way to update the file meta data so although I now had a way to repair the orphaned tracks by updating the information in the Windows Media Player database the underlying problem still remained. During further research I found a library, TagLib that can be used to write file meta data. In a future article I’ll look at how that library can be used with PowerShell to update the file meta data.