This started out as a question on the #PowerShell IRC channel (irc.freenode.net) about how to edit tags on mp3 files, but we quickly discovered TagLib#, which lets you access and edit tags on not only mp3s, but on everything from asf and avi to wma and wav and even includes supports for DIVX and FLAC and MovieID tags on top of ID3, etc.
Using TagLib# is pretty simple. Once you load the library, you can create a TagLib file record, view or edit the tags, and then save the changes back to the file:
In my obsession to completely explore these sorts of things even though I don’t actually care for myself, I wrote a Add-MediaInfo filter which you can take and use if you like. It adds all of the properties in “Tag” and “Properties” to each object which matches the file extensions filter, prefixing them with the word “Media” to avoid naming conflicts. You’ll need to have the TagLib# assembly loaded (maybe put that in your Profile script).
If you pass the switch parameter (-editable), it also puts the TagLib object into the file as “MediaTags”, which you can use to edit the tags, since you can’t actually edit and save NoteProperty values. I have a couple ideas for next steps, and if anyone does anything with this, I’d love to see it:
In response to Kirk Munro’s comment on my Writing Cmdlets for the PowerShell Pipeline post:
You know, I’ve looked at your articles about cmdlets/functions in the pipeline and I feel you’re missing something. The purpose of the InputObject parameter is to pass in a collection as a single object. This is as opposed to using the pipeline where a collection is passed along the pipeline one item at a time. There are cases where you want to pass in a collection as a collection.
Quite simply, I disagree. The documentation for these parameters says quite clearly that inputObject “Specifies an object or objects to input to the cmdlet.†This clearly means that I should be able to pass multiple objects, and have them treated as multiple objects, not as a single array object.
If you look at your example (Select -First 3 -Unique -InputObject $a), this does in fact work. It receives one object, an array. It then selects the first 3 objects, but there is only 1 so that is moot. And lastly it selects unique objects, but again there is only 1 so that is moot as well and finally the object is output using the default formatter. In this case the default formatter is showing the contents of the array.
In this example, Select-Object has no reason to take a single object as an input object, at all. The only time that it would be useful for Select-Object to take a single inputObject would be in combination with the property parameters. In fact, if you want to Select-Object from an array to get the first of last n objects, or to get a set of unique objects, you have to pass the objects in via the pipeline — there’s no other way to make it select from an array. If that was indeed the intent, it should have been written as a separate ParameterSet, and the documentation should be changed to reflect that only a single object can be passed in, and that you can’t use the inputObject parameter with the first, last, or unique parameters at all. That’s worse than useless, it’s misleading and confusing.
Kirk is absolutely right that if you assume that the InputObject argument is only allowed to take a single object, then the behavior is correct – but it’s not logical. In fact, the behavior you see in the output of this command is so useless as to be a bug – even if the documentation did not say the parameter accepts multiple objects as input:
But quite frankly, just because someone important wrote something useless is no reason to emulate the behavior. The inputObject parameter IS the same parameter which pipeline objects go into. There’s no logical explanation for us to get different results when we pass an array in via the parameter by name instead of via pipeline: the PowerShell pipeline passing the things in the pipeline into the –inputObject parameter … it’s not using some mystical variable like it does in script functions.
Of course, we all know the powershell pipeline unwraps arrays — that’s convenient, and we can work around it when we really want to pass an array in:
My point in all of this is that InputObject is actually a very useful parameter, because there are cases where you really want to pass a collection as a collection into a cmdlet and then do something with it. By making InputObject instead split the collection passed in and pipeline it through, you’re forcing users to wrap collections in an array just to get them passed in as a collection, and personally I don’t feel they should have to do that.
While it’s true that passing in an array is sometimes desirable that’s not the reason the parameter exists, and I don’t believe it should be the default behavior here. It should be just as easy for me to use the cmdlet with the inputObject parameter directly as it is to input them via the pipeline. If I put in unwrapping for the inputObject parameter, you can work around it in the same way I did in the examples above. Incidentally, I think *PowerShell* should unwrap arrays to ValueFromPipeline parameters regardless of whether they’re on the pipeline, but I recognize it’s probably too late for that.
Basically, this is my argument: If inputObject unwraps arrays, the syntax for passing an array by wrapping it in @(,$array) is simple, for those rare occasions when that’s actually what you want. But if it does not unwrap arrays, you’re forced to call it via a separate pipeline, because unwrapping the array and passing it in one at a time in a foreach loop will almost certainly not do the same thing, and this is much uglier — and not compatible with use within the pipeline, particularly if you need to pass the pipeline output into a different parameter.
I guess my final word would be to agree with Kirk that “InputObject … isn’t documented clearly enough†… in fact, it’s clearly behaving incorrectly according to the documentation, and that’s why I originally proposed to unwrap the inputObject parameter when it’s passed as a parameter: to make it work the way the documentation suggests it would, which seems to me to be a better way than the way it actually works.
Well, I am going to put this all on CodePlex tomorrow, but I promised a few people that I’d throw it up here for them yesterday, so I figured it’s past time to post it … without further ado.
The Window Automation Snapin and it’s source should be downloaded from the CodePlex project where updates can be tracked. 
This is basically an upgrade to the Win32.Windows snapin I released a while back, the one thing that’s missing in this release that was possible in that one is using frame-set definitions to position windows. That will make it back in eventually, but in the meantime, I present some major new additions which add up to the ability to do 90% of what you’d want to do in testing or automating your winforms app’s UI.
Select-Window notepad | Send-Keys "%(ea)Testing{Enter}{F5}" (and for extra fun, try it with multiple notepad windows open).There’s no help right now, so get used to using Get-Command -PSSnapin WindowAutomation and checking out the ParameterSets … hopefully you can figure it out from that for now. Oh, one other thing, there might be a few extras hiding in these:
[Huddled.Win32.WindowExtenders] | Get-Member -static [Huddled.Win32.WindowFinder] | Get-Member -staticFor now, that will have to do, it’s past time for bed. You might want to play with this and the out-voice script I posted on CodePlex awhile back, it makes things extra fun.
There have been a lot of blog posts around the internet about how to fix or change the “zoom” feature on the Microsoft Natural Ergonomic Keyboard 4000 into a scroll up/down feature instead — my favorite is this one by Olivier Dagenais which suggested using an XSL transform.
However, nobody seems to have fixed the F-Lock problem … so I started digging into the command mapping to see what I could figure out. I’ve got a fix posted at the bottom, so if you don’t care how this works, just skip to the end. I’m working on a Natural Ergonomic 4000, but some of what I found should apply to any keyboard using Microsoft’s IntelliType software. What we all know by now is that it has xml-based command remapping. The definitions for the remapping are in a file called commands.xml in the install directory, which is, by default: “C:\Program Files\Microsoft IntelliType Pro”.
There’s two interesting things happening in the IntelliType software. First, the “My Favorites” buttons on the Natural 4000 don’t seem to be a part of this remapping scheme. Second, although all of the remapping can be done in the commands.xml file, the control panel (at least in Vista) doesn’t use the commands.xml file at all — it adds entries to the registry! (more…)
Just a quick post to upload a simple PowerShell script that transforms XML files with XSL files. There’s actually a cmdlet in PowerShell Community Extensions which does this, but believe it or not, in all my tests the script outperforms the cmdlet (the cmdlet takes, on average, 117ms on a file which takes the script 63ms on average).
7 Dec
There’s a conversation going on in the Alt.Net discussion list about code solubility. The term (as applied to code) seems to have been coined by Scott Bellaware as a measure of how easy it is for someone reading a code base to absorb the information in it. In essence, soluble code is a refinement of simple code and readable code. While individual blocks of code can be judged as simple or readable, Scott argues that solubility only applies to an entire code base, and is a more stringent requirement than readability: “code can be readable without being soluble” (although soluble code has to be readable, of course).
The reason this came up on the discussion list is that someone asked if there was an example in the open source world of a highly soluble code base … Like everyone else, I’m having a hard time coming up with an example of an open source project who’s code I would consider imminently grokable and tractable, but I’m intrigued by the discussion because it has turned to a couple of threads about the usefulness of “solubility” as a metric:
As far as the metric of solubility, I think it’s true that the skill level of the reader is going to be the primary factor. Scott said, in a comment on his own post, that “Some writers come as close as possible to being objectively soluble,” and added the idea that a developer should be “intent on ensuring the communication of understanding.” I still think that there’s no such thing as “objectively soluble” without specifying a level of expertise. If we have a coder who has just started on our project and there are pieces of code in our code base which I would naturally expect any software engineering or computer science graduate to understand at first sight … but this guy does not understand them without having them explained (or spending time reading them on his own), does that necessarily mean that the code isn’t soluble? Maybe it just means that he isn’t literate enough. (more…)