Saturday, April 26, 2008

Powershell Ripped Media Renaming Script

I recently bought a book on CD and ripped it to .wma so that I could listen to it on my portable media player. When the tracks rip to disk they get named with the track number starting first. I wanted to rename the files so that the two digit disc number preceded the track number so that I could sort all of the tracks in one folder and listen to them in the correct order. Here's a Powershell script that I ran from the folder one below the ripped discs' folders.

# change directory into root of ripped files
cd "D:\Audio\Author Name"
$dirr = "BookName Disc "
$discs = 1..7 # Change to number of discs

foreach($disc in $discs)
    $discdir = $dirr + $disc.ToString()
    cd $discdir
    $dir = get-childitem *.wma
    foreach($x in $dir)
        $newname = "0" + $disc.ToString() + "." + $x.Name.SubString(0,2) + ".wma"
        Rename-Item $x $newname
    cd ..

I've updated the code that appeared here before 8 July 2010. Previously it did not have the loop for each disc. This code still isn't perfect. Instead of prepending the 0 to the disc number when creating the new name I should be formatting the disc value.

Wednesday, April 23, 2008

Download List of Files from Web with Powershell Script

I recently came across Scott Hanselman's Hansel Minutes and it looked like the sort of thing that I wanted to listen to. At the time I found it the archives had 109 podcasts. I wanted to download them all and stick them on my MP3 player but didn't want to click through to each link and repeat myself 109 times. I'm a big fan of the DRY principal. So I wrote a Powershell script to do it for me.

First off I examined the file naming pattern:


Fantastically simple. You couldn't ask for a nicer pattern.

So here's the script:

function main()
    $clnt = new-object System.Net.WebClient

    $sourceNames = 1..109 |%{"hanselminutes_{0:0000}.wma" -f $_}
    foreach($s in $sourceNames)
        $url = "" + $s
        $target = "c:\temp\" + $s
        write-host 'transfering from' $url 'to' $target
        $clnt.DownloadFile($url, $target)



During the execution of the script over the 109 files that were in the archive at the time 3 files failed because of a timeout and 2 files failed because they didn't follow the naming pattern: The interviews with Jonathan Zuck and Robert Pickering (#'s 86 and 76 respectively) had their names tagged on to the file names.

Shrinking SQL Server Log File

I've been trying to work out how to do this for ages and today I've finally found the answer from Books Online. I think that a lot of us experience this. When you're searching the help files and resources you can't find the answer but later when you're not looking for it you stumble across it. For my notes, here is the example. Interestingly on most of my DB's I don't need full recovery so I've skipped the last step and left the DB's at simple recovery.

USE AdventureWorks;
-- Truncate the log by changing the database recovery model to SIMPLE.
-- Shrink the truncated log file to 1 MB.
DBCC SHRINKFILE (AdventureWorks_Log, 1);
-- Reset the database recovery model.

Thursday, April 17, 2008

Experts Exchange

One of the things that constantly frustrates me when looking for answers to programming questions via Google is that one of the top answers that will be listed will be on Experts Exchange but I can't get to see it because it's a paid site and I won't subscribe because I've heard too many stories about how the quality of the answers is worse than the answers given on free boards. Why pay for something that's worse than something that's free?

Jeff Atwood and Joel Spolsky have created a new web site called StackOverflow that is going to compete with sites such as Experts Exchange. This is fantastic news. These guys are talented individuals who write well and I'm sure will pull off a great site with good information and a great way to get to that information. Jeff is on the west coast and Joel on the east coast and they chat to each other weekly and record their conversations which appear as podcasts on the same site. Very cool!

Wednesday, April 16, 2008

Iterating through arrays in TDD

One of the patterns that I frequently follow in Test Driven Development (TDD) that I haven't seen mentioned elsewhere (yet) and that I find extremely effective is to create arrays of potential inputs for parameters to functions that I'm testing and then iterate through those arrays calling the same function and testing the results.

For example, if I had a function ConcatString(string one, string two) I could test it as such:

            string[] one = { "black", "blue", "orange" };
            string[] two = { "yellow", "white", "brown", "cotton" };
            for (int i = 0; i < one.Length; i++)
                for (int j = 0; j < two.Length; j++)
                    string actual = ConcatString(one[i], two[j]);
                    string expected = one[i] + two[j];
                    Assert.AreEqual(expected, actual);

Webmaster Day is April 29

April 29 is Webmaster Day. If you're a webmaster then send yourself an eCard. If you know a webmaster then send him/her an eCard. This year, Webmaster Day falls on a Tuesday.

Sunday, April 13, 2008

Deployed ASP.NET MVC app gives 404 on About Page

I am working through learning how to use the ASP.NET MVC framework with a web application. One of the annoying problems that I recently hit on was that the sample worked great when running under Cassini in the development environment but when deployed to IIS 6 I couldn't get to the About or Home page through the URL paths.

The following comment exists in the Global.asax.cs file:

            // Note: Change the URL to "{controller}.mvc/{action}/{id}" to enable
            //       automatic support on IIS6 and IIS7 classic mode

When running in Cassini you don't need to make this change. However, under IIS 6, if you forget to make this change then you'll hit this problem and get 404 page-not-found errors. Simply making this change appears to solve the problem.

I read some comments on the web that you need to add .mvc as a MIME type with a mapping of C:\WINDOWS\MICROSOFT.NET\FRAMEWORK\V2.0.50727\ASPNET_ISAPI.DLL which I tried initially with no success and then later went back and removed it when I got it working with the above solution. The MIME types don't appear to be the solution.

This was done with the MVC preview 2 released in Dec 2008.


I found that on Server 2003 Enterprise (Dev Machine) I did not need to map .mvc to C:\WINDOWS\MICROSOFT.NET\FRAMEWORK\V2.0.50727\ASPNET_ISAPI.DLL but when I deployed to Production (Server 2003 Standard) I had to go into the web site's properties and click Home Directory (tab) and then Configuration... (button) and then add the mapping. I thought that this was an Enterprise/Standard thing but then on closer inspection I discovered that the Enterprise machine already had this mapping. This probably happened when I installed the MVC preview onto the Enterprise (Dev) machine and it looks like (contrary to what I said before) you do need this mapping.

Addendum 2: (27 Oct 2008):

Since I've upgraded to mvc beta I've found that the above fixes don't work for me - they may still work for you. I've found the following resources useful so far:

Deploying ASP.NET MVC to IIS 6

Using ASP.NET MVC on IIS without the .MVC extension


Friday, April 11, 2008

Powershell renaming filenames

One of the problems that I frequently come across is the need to rename a bunch of files according to a certain pattern which involves numbers. Now I still haven't figured out how to do that yet but I've just seen a Powershell Blog post Managing Datacenter Machine Names that gives me enough information to work it out - I think.

The cool new feature that I've just discovered is the range operator in Powershell:


Will generate the numbers 1 through 5. Pipe this into your command and use some .NET formatting and you can get zero padded numbers to help rename, copy, move, delete files that will save a lot of time on large folders of files.

Monday, April 7, 2008

Gmail Google Alerts Spam

I subscribe to a Google Service called Google Alerts. Anytime certain keywords that I want to watch for are indexed by Google I get an email from them telling me about the new pages on the web that have those keywords.

The email address that these alerts get sent to is my Gmail email address which has the spam filter switch on. It's the best spam filter I've seen and so I trust it but I often glance over the spam list before I "delete all" to make sure that it's doing a good job.

Today I saw a Google Alert in the spam box. The email came from and I checked the IP it came from and it wasn't spoofed. It also contained the regular alert content.

What amazes me is that Google's own email is getting put in the spam bucket by it's own filters. At the very least I would have thought that they would have white listed their own IP. Apparently not.

Social Engineering with USB Drives

I thought that the following short story from Inspired eLearning was very interesting. I you found a USB drive without an owner would you plug it into your computer? Before reading this story I think that I would have. Now I'm more inclined to put it under the car's tire and run over it.

Social Engineering with USB Drives

A network security organization was hired to assess the strength of a credit union's security. They were asked to focus on social engineering because of past problems with employees giving up passwords or other information easily.

Because the credit union indicated that USB drives were a concern, since they make it easy to steal information or bring in potential vulnerabilities such as viruses and Trojans, an experiment using USB drives was implemented.

The security group planted 20 Trojan laced USB drives throughout the parking lot and other areas frequented by employees designed to collect passwords, logins and other information and to email the collected information back to the security group.

The experiment, which worked based on peoples' innate curiosity, resulted in 15 of 20 drives being found by employees and all of those being plugged into and infecting workplace computers.

Copyright © Inspired eLearning Inc, 2003-2007


There's a good article by Dino Esposito called The Rationale Behind ASP.NET MVC. I didn't know that the MVC framework for ASP.NET was as popular as he describes it to be but I can understand it as I saw Scott Guthrie give a great demo of it at a conference recently. I've been playing with it some and it has a bit of a learning curve but looks like a very productive and robust approach to developing web sites. I'm sold.

Sunday, April 6, 2008

Better than a Production Break

I was just watching the Editing Data and Making Forms ASP.NET MVC screencast by Scott Hanselman and heard him say "a broken build is better than a production break." This is the first time that I've heard this quote although I have no doubt that it's not new.

The cool thing about the code that he is showing at this point in the screen cast is how URL's can be removed as strings in ASP.NET MVC and can instead be defined as ActionLinks to strongly typed objects and using the new C# 3.0 lambda expressions "discover" the correct URL.

This means that if your URL is going to change it will happen to the strongly typed object which will break the build. Breaking the build is great because you can fix it then and there before it goes to production.

If you are using strings to describe your URL then when you make a change to the URL you will need to replace all of the strings in that URL. If you miss one then you won't know about it at compile time. It will only become apparent at run time and that might be in production if it's not caught in the test environment.

Saturday, April 5, 2008

Powershell Grep

For whatever reason I always forget the syntax to quickly find text in a bunch of source files from Powershell. Here it is so I can quickly look it up again:

Get-ChildItem -include *.cs -recurse | Select-String "string to search for"

The Get-ChildItem is the equivalent of dir in DOS.

-include is the param to tell Get-ChildItem which files to include in its search. In this case all CSharp (C#) files.

-recurse means look in subfolders under this one as well. i.e. the one that I'm running the command from.

| - this is the pipe symbol. The results of the search (a collection of files) is piped into the process that will open each file and search for the string.

Select-String - this is the command that will open a file and search for the "string to search for" string in the file. Each found line will be listed.

Friday, April 4, 2008

Index into words in string array

The programming problem that I recently ran across was as follows: I had a string of text and I needed to turn that into an array of strings and get a list of where a certain word occurred inside that array. In other words an int array that indexes a word in a string array.

I believe that this is how compression algorithms such as zip work. They store indexes of common occurring words instead of the words themselves.

Here is the code that solved the problem for me using the latest in C# 3.0 and LINQ:

string sentence = "this is an array with is in it three is times";

string[] words = sentence.Split(' ');words.Select((wrds, index) => new {Word = wrds, Indx = index}).Where(a => a.Word == "is").Select(a => a.Indx).ToArray().Dump();



LINQPad by Joseph Albahari is one of the most useful tools I have ever had the pleasure of using. If you are using or learning C# 3.0 and/or the new LINQ syntax it is invaluable.

LINQPad was created to support C# 3.0 in a Nutshell by Joseph Albahari. It provides an interactive means to test snippets of C# 3.0 code and LINQ against arrays, XML and SQL Server databases. Download it now and join the challenge to use it for a week instead of SQL Server Management Studio and you will find that you will be able to replace 80% of what you do in SSMS with LINQPad and while doing that you'll be using LINQ and C# to do your queries in a more interactive and intuitive style.

Thursday, April 3, 2008


I recently indulged in two gadgets from Hauppauge that have turned one of my PC's on my home network into a Tivo style PVR.

An HVR-950 USB TV recorder...


...and a Wireless MediaMVP player.

Wireless MediaMVP

I took a while to configure these toys but the end result seems to be pretty good.

Wednesday, April 2, 2008

Graffiti CMS

On 2 April 2008 I installed Graffiti CMS on this server and the following day I registered (that's modest me) and have started to explore the new Content Management System created by Telligent.
Graffiti CMS claims to be "content made easy." So far it seems that they have achieved their goal. The setup (on a dedicated server) was very simple. Initially I used the default setup which is against a VistaDB database. I quickly changed that to use SQL Server and made one small mistake in the web.config which broke the site but the forum came up with an answer very quickly and I was soon back-on-track.