About Me · Send mail to the author(s) E-mail · Twitter

At GROSSWEBER we practice what we preach. We offer trainings for modern software technologies like Behavior Driven Development, Clean Code and Git. Our staff is fluent in a variety of languages, including English.

Feed Icon


Open Source Projects


Blogs of friends

Now playing [?]

Error retrieving information from external service.

Sorting Visual Studio's "Add New Item" Dialog

Posted in PowerShell | Visual Studio at Saturday, 03 March 2007 18:33 W. Europe Standard Time

While browsing my ever increasing stack of unread The Daily Grind posts I came across a blog post by K. Scott Allen that describes how to sort Visual Studio's "Add New Item" dialog with PowerShell. Neat idea, as I always disliked the fact that Visual Studio has no way of sorting these items alphabetically but relies on a property inside vstemplate files.

Visual Studio Default Sort Order

After downloading and running the PowerShell script he provides on my machine, I was greeted with some error messages. Some WinFX templates were destroyed, as these have an App_Code subfolder inside the zip that the Scott's script doesn't handle well. Fortunately the script creates backups so it wasn't a dealbreaker but rather a point to start from revisiting the script and making it more compatible.

# sort-vsItems
# scott at OdeToCode dot com
# Modified by AlexanderGross at gmx dot de
# Use at your own risk!
# Script will make a backup of each template just in case.
# vjslib for .zip support.
[System.Reflection.Assembly]::Load("vjslib, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a") | out-null
# Get list of VS installed templates.
$installDir = [System.IO.Path]::Combine((gp HKLM:Software\Microsoft\VisualStudio\8.0).InstallDir, "ItemTemplates")
$templateFiles = gci -recurse $installDir | ? {$_.extension -eq ".zip"}
# Append list of custom templates.
$installDir = [System.IO.Path]::Combine((gp "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders").Personal, "Visual Studio 2005\Templates\ItemTemplates")
$templateFiles += gci -recurse $installDir | ? {$_.extension -eq ".zip"}   # Sort all templates by filename. $templateFiles = $templateFiles | sort name   $i = 1 $count = 0 $tmpDir = new-item ([System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName())) -type directory $buffer = new-object System.SByte[] (8192)   # Iterate through all template files. foreach($templateFile in $templateFiles) {     write-host "Processing" $templateFile.FullName       # Extract all files (no methods available to modify zip in place).     $zip = new-object$templateFile.FullName)     $entries = $zip.entries()     while($entries.hasMoreElements())     {         $zipEntry = $entries.nextElement()           # Ensure output directory exists.         $filename = [System.IO.Path]::Combine($tmpDir.FullName, $zipEntry.getName())           # $zipEntry.isDirectory() does not work for Microsoft zips (e.g. Web\CSharp\         $directory = [System.IO.Path]::GetDirectoryName($filename)         if ([System.IO.Directory]::Exists($directory) -ne $true)         {             mkdir $directory | out-null               # In case the zip tells us it's a directory entry, skip the entry to prevent exceptions.             if ($zipEntry.isDirectory())             {                 continue             }         }           $in = $zip.getInputStream($zipEntry)         $out = new-object$filename)           while(($count = $$buffer, 0, $buffer.Count)) -gt 0)         {             $out.write($buffer, 0, $count)         }           $out.Close()         $in.Close()     }     $zip.Close()       # Tweak the sort order element.     $vst = gci -recurse $tmpDir | ? {$_.extension -eq ".vstemplate"}     if ($vst -eq $null)     {         # The zip file does not contain a vstemplate.           # Clean temporary directory for the next template file.         del $tmpDir\* -force -recurse         continue     }       $xmlDoc = new-object System.Xml.XmlDocument     $xmlDoc.Load($vst.FullName)     if ($xmlDoc.VSTemplate.TemplateData.SortOrder -ne $null)     {         # Sort by zip name. Sort order must be a multiple of 10.         $xmlDoc.VSTemplate.TemplateData.SortOrder = ($i++ * 10).ToString()           # Sort by item name in Visual Studio.         # Uncomment this line if you want to let Visual Studio sort by item name.         # $xmlDoc.VSTemplate.TemplateData.SortOrder = "10"           $xmlDoc.Save($vst.FullName)     }       # Backup existing zip file.     $backupName = $templateFile.FullName + ".bak"     if(test-path $backupName)     {         # Remove previous backups.         remove-item $backupName     }     move-item $templateFile.FullName $backupName       # Zip up modified version.     $zip = new-object$templateFile.FullName))     $files = gci -recurse $tmpDir     foreach($file in $files)     {         if ($file.Attributes -contains "Directory")         {             # Subfolders are created automatically with files residing in subfolders.             continue         }           # Create a file entry.         # Replacing the last backslash from $tmpDir.FullName is crucial, the zips would work with any other         # zip editor but Visual Studio doesn't like files with a leading backslash (though one doesn't see         # it in WinZip).         $zipEntry = new-object$file.FullName.Replace($tmpDir.FullName + "\", ""))         $zip.putNextEntry($zipEntry)         $in = new-object$file.FullName)         while(($count = $$buffer, 0, $buffer.Count)) -gt 0)         {             $zip.write($buffer, 0, $count)         }         $in.close()         $zip.closeEntry()       }     $zip.close()       # Clean temporary directory for the next template file.     del $tmpDir\* -force -recurse }   del $tmpDir -force -recurse   write-host "Running Visual Studio to refresh templates" $vstudio = (gp HKLM:Software\Microsoft\VisualStudio\8.0).InstallDir & $vstudio\devenv /setup

DownloadDownload the updated script.

Please note the part highlighted in red: If you leave that last red line commented, the item template entries will be sorted based on the zip file name. Just like Scott's original script did. As you can see in the screenshot below, this will get you some pseudo-grouping as all WinFX templates are at the bottom.

Sorted by Zip File Name

If you want to let Visual Studio do the sorting, uncomment the last red line and you'll get truly sorted item templates.

Sorted by Item Name

There's also another solution to the problem, but FixVsItemSortOrder has a bug that prevents "<Language>ProjectItems" folders from being sorted (so says the readme). Not sure what he means there because there's no ProjectItems folder, maybe he means the ProjectTemplates folder. FixVsItemSortOrder, in contrast to the PowerShell script above, also doesn't take user-specific item templates into account.

Now Playing [?]: AirThe Virgin Suicides O.S.T. – Bathroom girl

Wednesday, 28 March 2007 16:13:02 (W. Europe Daylight Time, UTC+02:00)
This script is a mess. Have you ever heard of encapsulation, classes, methods, and other oo concepts? I realize it's powershell, but this kind of crap will become a maintenance nightmare. Try smaller methods. Have you ever heard of the single responsibility principle. Learn it, you might have a future in programming.
Learn how to write better code.
Wednesday, 28 March 2007 19:54:45 (W. Europe Daylight Time, UTC+02:00)
Thank you Mr troll, I suppose no offence intended here?

The script is a modified version of K. Scott Allen's script that I just wanted to get to work on my machine. Did I say I wanted it to be a perfect littler helper? No. Does it work as it's supposed to? Yes. Go ahead and publish your revisited version.

If you want to judge my OO code I suggest you take a look at the Now Playing source code.
Friday, 20 July 2007 18:59:26 (W. Europe Daylight Time, UTC+02:00)
Thanks for the script, seams to work great.

I can not see anything marked with red though (IE or FF).
I found the lines to comment / uncomment, so no worries for me ;)
Happy reader
Friday, 20 July 2007 19:27:20 (W. Europe Daylight Time, UTC+02:00)
Happy Reader,

Thanks for the hint, the red part should be visible now!
All comments require the approval of the site owner before being displayed.
(will show your gravatar icon)
[Captcha]Enter the code shown (prevents robots):

Live Comment Preview