Scott Hanselman

A Very Poor Man's Vonage Web Service using Watir

July 02, 2006 Comment on this post [13] Posted in Ruby | Watir
Sponsored By

Folks keep calling after 9pm and waking the baby. We use Vonage, and I really wish they had a feature where I could indicate "do not call" times. Alas, they don't. So, then I wished for a Vonage Web Service. Nope.

So, instead here's a Watir script, recorded with a early version of Michael Kelly and John Hann's port of WatirMaker to Ruby (via "ruby watirmaker.rb > myscript.rb") then edited to taste.

#Enable Instant Forward to Voice Mail
require 'watir'
include Watir

ie = IE.new
ie.goto( 'http://www.vonage.com/' )

ie.text_field( :name, 'username' ).set( 'username' )
ie.text_field( :name, 'password' ).set( 'password' )
ie.button( :name, 'submit' ).click

ie.link(:text,"Features").click

ie.button( :name, 'callForwardingButton' ).click

ie.select_list( :name, 'callForwardingSeconds' ).select( 'Instantly' )
ie.text_field( :name, 'singleAddress' ).set( '15035551234' )

ie.button(:value,'Enable').click

ie.link(:text,"Log Out").click
ie.close

And the disable...

require 'watir'
include Watir

ie = IE.new
ie.goto( 'http://www.vonage.com/' )

ie.text_field( :name, 'username' ).set( 'username')
ie.text_field( :name, 'password' ).set( 'password' )
ie.button( :name, 'submit' ).click

ie.link(:text,"Features").click

ie.button( :name, 'callForwardingButton' ).click

ie.button(:value,'Disable').click

ie.link(:text,"Log Out").click
ie.close

These now run on a schedule in my house using the Windows Scheduler. If you run them like 'ruby enable.rb -b' they run in the background and you'll never see Internet Explorer.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Capturing Video a Web Camera using WIA - Not Possible?

June 30, 2006 Comment on this post [0] Posted in Coding4Fun
Sponsored By

My Coding4Fun article using a $4 webcam would capture single frames using WIA, the WIA Automation Layer and upload them to a blog.

However, I get 3 emails a week asking how to capture video using WIA. I don't think it's possible. WIA supports "TakePicture" but that operation isn't fast enough to get more than a few frames a second, and then even only in JPEG format.

WIA does support Video Overlay though so you can see what you're not capturing, so that's nice. ;)

Seriously, though, WIA isn't the way, it appears that DirectShow likely is. This .NET Library wrapper around the notoriously difficult DirectShow APIs says it supports "capture from video capture devices to WMV files." It appears that this library also exposes that notorious hardness, so take a breath before you dive in. It's hardcore.

Other possibilities are the CAPTURENET Sample that might do the trick. Also Kristoffer Vinther (a master sorter at least) has a library that looks pretty capable.

Aside: Yes, that's a signed 12" Vinyl of Bobby McFerrin's Simple Pleasures album, framed on my wall just below Miles Davis. I used to look for good echos for acappella on campus, but I am nothing compared to my buddy from Vertigo Software (and high school) Matt Hempey and the several acappella albums he has under his belt.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Testing PowerShell scripts with NUnit

June 30, 2006 Comment on this post [4] Posted in PowerShell | NUnit
Sponsored By

We've been doing lots of PowerShell at work, but we're also a continuous integration shop and we try to do TDD so testing, specifically NUnit, is very important to us.

Here's how Jason Scheuerman from my team tests PowerShell scripts with NUnit.

using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Management.Automation.Runspaces;
using System.Management.Automation;
using NUnit.Framework;
using System.Security;

namespace PSUnitTestLibrary.Test
{
    [TestFixture]
    public class Program
    {
        private Runspace myRunSpace;
 
        [TestFixtureSetUp]
        public void PSSetup()
        {
            myRunSpace = RunspaceFactory.CreateRunspace();
            myRunSpace.Open();
            Pipeline cmd = myRunSpace.CreatePipeline(@"set-Location 'C:\dev\someproject");
            cmd.Invoke();
         } 

        [Test]
        public void PSTest()
        {
            Pipeline cmd = myRunSpace.CreatePipeline("get-location");
            Collection<PSObject> resultObject = cmd.Invoke();
            string currDir = resultObject[0].ToString();
            Assert.IsTrue(currDir == @"'C:\dev\someproject");

            cmd = myRunSpace.CreatePipeline(@".\new-securestring.ps1 password");
            resultObject = cmd.Invoke();
            SecureString ss = (SecureString)resultObject[0].ImmediateBaseObject;
            Assert.IsTrue(ss.Length == 8);

            myRunSpace.SessionStateProxy.SetVariable("ss", ss);
            cmd = myRunSpace.CreatePipeline(@".\getfrom-securestring.ps1 $ss");
            resultObject = cmd.Invoke();
            string clearText = (string)resultObject[0].ImmediateBaseObject;
            Assert.IsTrue(clearText == "password");
        }
    }
} 

The "CreatePipeline" calls are us telling PowerShell "do that!" The Pipeline of commands is created, passed into cmd then Invoke'd.

Also in this case we're assuming one PowerShell RunSpace per TestFixture and we're using the TestFixtureSetUp method to get that RunSpace going, but you could certainly move things around if you wanted different behavior or isolation.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

PowerShell, AnkhSVN and Subversion

June 30, 2006 Comment on this post [3] Posted in PowerShell | ASP.NET | Subversion | Tools
Sponsored By

I've been up to my ears in PowerShell (podcast) this last week at work. It continues to rock my world. I've been doing some automation work using Subversion not as source control but as a quasi-journaled file system.

There's a number of ways one could use Subversion from PowerShell, but I kind of want it as integrated as possible. I'm still trying out a few things. Here's what I've got so far...

Via SVN.exe

One could just use svn.exe, the command-line client. There's some obscure switches to remember, but Arild, the guy that wrote AnkhSVN (Subversion support within Visual Studio) has written a PowerShell tabcompletion script that gives one completion for svn.exe commands.

So you might type svn c[TAB] and get svn cat then [TAB] and get svn checkout, etc. Clever and cool but it just extends the command line tool with help.

Via TortoiseProc (the command line that comes with TortoiseSVN)

One could use the TortoiseProc without it being in the PATH with a script like this (stolen from Brad Wilson). This isn't that interesting of a script as the file could just be in the PATH, but it is an example of a decent pattern for calling tools that have discoverable paths (via the registry, etc) but aren't in the PATH proper.

if ($args.Length -lt 1) {
    write-host "usage: tsvn <command>"
    return
}

if ((test-path "HKLM:\Software\TortoiseSVN") -eq $false) {
 write-host -foregroundColor Red "Error: Could not find TortoiseProc.exe"
 return
}

$tortoiseKey = get-itemproperty "HKLM:\Software\TortoiseSVN"

if ($tortoiseKey -eq $null) {
 write-host -foregroundColor Red "Error: Could not find TortoiseProc.exe"
 return
}

$tortoise = $tortoiseKey.ProcPath

if ($tortoise -eq $null) {
 write-host -foregroundColor Red "Error: Could not find TortoiseProc.exe"
 return
}

$commandLine = '/command:' + $args[0] + ' /notempfile /path:"' + ((get-location).Path) + '"'
& $tortoise $commandLine

Use NSvn.Core directly, in-process, from PowerShell

The most attractive option to me was to find a way to talk to Subversion directly using something in-process. These last two options would require "shelling out" to non-PowerShell things. I was hoping to update Subversion from within ASP.NET for some Admin stuff, and while I could use System.EnterpriseServices to manage identity, I didn't want to have new processes firing up for a number of obvious reasons.

Deep in AnkhSVN is a great little .NET library called NSvn that did just want I needed. It doesn't appear to be distributed outside of Ankh, but I just took it from the latest install.  It's got no docs but Reflector to the rescue got me this PowerShell script that I called get-fromsvn.ps1.

param ([string]$svnurl       = $(read-host "Please specify the path to SVN"),
       [string]$svnlocalpath = $(read-host "Please specify the local path")
      )

if ([System.IO.Path]::IsPathRooted($svnlocalpath) -eq $false)
{
  throw "Please specific a local absolute path"
}

[System.Reflection.Assembly]::LoadFrom((join-Path $GLOBAL:someGlobalPath -childPath NSvn.Common.dll))
[System.Reflection.Assembly]::LoadFrom((join-Path $GLOBAL:someGlobalPath -childPath NSvn.Core.dll))

$PRIVATE:svnclient = new-object NSvn.Core.Client
$PRIVATE:svnclient.AuthBaton.Add( [NSvn.Core.AuthenticationProvider]::GetWindowsSimpleProvider() )
if ((test-Path $svnlocalpath) -eq $true )
{
  write-progress -status "Updating from $svnurl" -activity "Updating Working Copy"
  $PRIVATE:svnclient.Update($svnlocalpath, [NSvn.Core.Revision]::Head, $true)
}
else
{
  write-progress -status "Checkout from $svnurl" -activity "Updating Working Copy"
  $PRIVATE:svnclient.Checkout($svnurl, $svnlocalpath, [NSvn.Core.Revision]::Head, $true)
}

This script lets me checkout/update from Subversion happily. There's still some voodoo I need to work out like getting progress updates...

(How do you do a delegate from within PowerShell if a .NET Assembly needs a delegate with a certain signature? This library will call me back with status updates I'd like to broker to write-progress)

...but it gets 90% of what I need from an in-process call to Subversion from PowerShell. I know Arild Fines is not only the author of this library but a fan of PowerShell as well. Perhaps he'll help me either update this script, or better yet, write a PSSnapin to use Subversion as first-class cmdlets with progress and detailed logging. It'd be as useful, if not more so, than the SVN PSDriveProvider he's been messing with.

UPDATE: Arild Fines posted a solution to my question. I agree that the syntax for delegates is poo and I hope the PowerShell team takes that feedback. ;) The syntax for events, however, is quite elegant.

The addition of two lines gives me the write-progress and event notification support I wanted:

param ([string]$svnurl       = $(read-host "Please specify the path to SVN"),
       [string]$svnlocalpath = $(read-host "Please specify the local path")
      )

if ([System.IO.Path]::IsPathRooted($svnlocalpath) -eq $false)
{
  throw "Please specific a local absolute path"
}

[System.Reflection.Assembly]::LoadFrom((join-Path $GLOBAL:someGlobalPath -childPath NSvn.Common.dll))
[System.Reflection.Assembly]::LoadFrom((join-Path $GLOBAL:someGlobalPath -childPath NSvn.Core.dll))

$PRIVATE:svnclient = new-object NSvn.Core.Client

$PRIVATE:notificationcallback = [NSvn.Core.NotificationDelegate]{
        Write-Progress -status ("{0}: {1}" -f ($_.Action, $_.Path)) -activity "Updating Working Copy"
    }
    
$PRIVATE:svnclient.add_Notification($notificationcallback)   

$PRIVATE:svnclient.AuthBaton.Add( [NSvn.Core.AuthenticationProvider]::GetWindowsSimpleProvider() )
if ((test-Path $svnlocalpath) -eq $true )
{
  write-progress -status "Updating from $svnurl" -activity "Updating Working Copy"
  $PRIVATE:svnclient.Update($svnlocalpath, [NSvn.Core.Revision]::Head, $true)
}
else
{
  write-progress -status "Checkout from $svnurl" -activity "Updating Working Copy"
  $PRIVATE:svnclient.Checkout($svnurl, $svnlocalpath, [NSvn.Core.Revision]::Head, $true)
}

I hope more people in the community start digging into PowerShell and seeing how truly powerful it is to have .NET at the command line.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Hanselminutes Podcast 22

June 30, 2006 Comment on this post [1] Posted in Podcast | ASP.NET | XML | Tools
Sponsored By

HanselminutesMy twenty-second Podcast is up. This episode is mostly about portable GPS units but we'll call it Hanselminutiae #2. Next episode we'll steer towards more development topics.

We're listed in the iTunes Podcast Directory, so I encourage you to subscribe with a single click (two in Firefox) with the button below. For those of you on slower connections there are lo-fi and torrent-based versions as well.

Subscribe to my Podcast in iTunes

NEW COUPON CODE EXCLUSIVELY FOR HANSELMINUTES LISTENERS: The folks at XCeed are giving Hanselminutes listeners that is Coupon Code "hm-20-20." It'll work on their online shop or over the phone. This is an amazing deal, and I encourage you to check our their stuff. The coupon is good for 20% off any component or suite, with or without subscription, for 1 developer all the way up to a site license.

Our sponsors are XCeed, CodeSmith Tools, PeterBlum and the .NET Dev Journal. There's a $100 off CodeSmith coupon for Hanselminutes listeners - it's coupon code HM100. Spread the word, now's the time to buy.

As I've said before this show comes to you with the audio expertise and stewardship of Carl Franklin. The name comes from Travis Illig, but the goal of the show is simple. Avoid wasting the listener's time. (and make the commute less boring)

  • The basic MP3 feed is here, and the iPod friendly one is here. There's a number of other ways you can get it (streaming, straight download, etc) that are all up on the site just below the fold. I use iTunes, myself, to listen to most podcasts, but I also use FeedDemon and it's built in support.
  • Note that for now, because of bandwidth constraints, the feeds always have just the current show. If you want to get an old show (and because many Podcasting Clients aren't smart enough to not download the file more than once) you can always find them at http://www.hanselminutes.com.
  • I have, and will, also include the enclosures to this feed you're reading, so if you're already subscribed to ComputerZen and you're not interested in cluttering your life with another feed, you have the choice to get the 'cast as well.
  • If there's a topic you'd like to hear, perhaps one that is better spoken than presented on a blog, or a great tool you can't live without, contact me and I'll get it in the queue!

Enjoy. Who knows what'll happen in the next show?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.