I am planning on going to my first Code Camp this weekend in Roanoke. Hope to see you there.
Daily Archives: March 3, 2009
My First Powershell SnapIn – Get-Url (wget)
There are already a lot of people who have solved this problem, but I wanted to solve it too. Powershell doesn’t ship with a wget‘ish cmdlet, at least that I could easily find. So I decided to kill two birds with one stone, create my first SnapIn and create a Get-Url cmdlet. It’s much easier than I thought.
Getting started
Start by creating a new class library project. There are two references you are going to need, System.Configuration.Install and System.Management.Automation. The former ships with .NET. The latter ships with the Windows SDK.

Create the snap-in class
Add a class for the snap in. This class is fairly worthless, but nevertheless it is required. It helps the installer know what needs to be installed, and what the SnapIn will be called.
[RunInstaller(true)] public class WebSnapIn : PSSnapIn { public override string Description { get { return "Snap for web related activities"; } } public override string Name { get { return "WebSnapIn"; } } public override string Vendor { get { return "Brian Hartsock"; } } }
Create the cmdlet
Now to the meat and potatoes, create the cmdlet. I don’t want to get into the details of everything that is necasary, just pay attention to the attributes and the ProcessRecord method. There are much better teachers at the intricacies of SnapIn creation than I.
[Cmdlet(VerbsCommon.Get, "url")] public class GetUrl : Cmdlet { public GetUrl() { Progress = new ProgressRecord(1, "Downloading...", "Starting..."); } [Parameter(Mandatory=true, Position=0)] public Uri Url { get; set; } private ProgressRecord Progress { get; set; } protected override void ProcessRecord() { UpdateProgress("Connecting..."); var request = WebRequest.Create(Url); var response = request.GetResponse(); UpdateProgress("Connected"); using (var responseStream = response.GetResponseStream()) using (var fileStream = new FileStream(GetFilePath(), FileMode.OpenOrCreate)) { CopyStream( responseStream, fileStream, 1024, response.ContentLength, (current, total) => UpdateDownloadProgress(current, total)); } } private string GetFilePath() { var fileName = Url.Segments.Last(); var fullPath = Path.Combine(Directory.GetCurrentDirectory(), fileName); return fullPath; } private void CopyStream(Stream source, Stream sink, int bufferSize, long sourceLength, Action<long, long> notification) { byte[] buffer = new byte[bufferSize]; long numberOfBytesCopied = 0; while (true) { var actual = source.Read(buffer, 0, buffer.Length); if (actual == 0) { break; } sink.Write(buffer, 0, actual); numberOfBytesCopied += actual; notification(numberOfBytesCopied, sourceLength); } } private void UpdateProgress(string description) { Progress.StatusDescription = description; WriteProgress(Progress); } private void UpdateDownloadProgress(long current, long total) { int percent = (int)((100 * current) / total); Progress.StatusDescription = string.Format("{0} bytes of {1} ({2}%)", current, total, percent); Progress.PercentComplete = percent; WriteProgress(Progress); } }
Build, and your almost ready to start using it.
Install and run
InstallUtil must be used to register the DLL, then you have to add the snap-in to the current session.
c:\Windows\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe WebSnapIn.dll add-snapin WebSnapIn get-url http://prdownloads.sourceforge.net/nunit/NUnit-2.4.8-net-2.0.zip?download
Here it is in action, although the video is pretty terrible. Imagine the text is clear and you can see what is going on. (I am a video noob)
Get-Url in action from Brian Hartsock on Vimeo.
Lastly, my appologies to NUnit/SourceForge. I probably downloaded NUnit 30 times testing this script out.