Morning Coffee 33

I realize yesterday I said I was on vacation starting today. In reality, I’m not going to the office today, but I have time to post this before my vacation starts in earnest.

  • I hit Zero Email Bounce in advance of my vacation. It’s been quite a while since the last time I got here and I hope to hit it much more often in the future.
  • The DSL tools team shipped a Designer Integration PowerToy that allows you to integrate models from multiple DSL designers into a single authoring tool. Gareth has more here.
  • Assorted PowerShell links: PowerShell Analyzer and PowerShellIDE. Both look interesting.
  • Personally, I like Notepad2 but apparently the only way to add a new syntax highlight scheme requires modifying the source code. Ugh. Anyone out there already added PS support to Notepad2? How about a suggestion for a simple text editor that supports extensible syntax highlighting?
  • Steve, Nick and Tomas all commented on my long running services WCF post. Tomas mentions Advanced Message Queuing Protocol (AMQP) which looks to be developing an open spec queuing system like MSMQ or MQ series. Interesting, but given the lack of involvement of the major MQ and DB vendors, I’m hard pressed to imagine this gaining any kind of critical mass.

Morning Coffee 31

  • Architect MVP business news keeps on coming. Today it’s Corillian – the company Scott Hansleman works for – getting acquired by CheckFree.
  • Los Angeles is looking to provide city-wide low-cost (maybe free) wireless access. My father has often suggested that Internet access be treated like other utilities like water and power. Sounds like LA is heading down that path. I wonder if they’re looking at WiMAX?
  • The .NET Micro Framework – which powers the SPOT watch – now has an SDK. For those keeping track, that makes three embedded solution platforms from Microsoft, the Micro FX, Windows CE (which also just shipped a new version) and Windows XP Embedded. (via Larkware)
  • BEA’s Bruce Graham talks somewhat obtusely on a topic I am particularly passionate about: putting more power in business people’s hands to build their own systems. (via Joe McKendrick)
  • Register for the Windows Home Server beta. Also check out the forums, team blog and SuperSite Preview. Looks pretty sweet (via Scott Hansleman)
  • The final version of Live Search for Mobile was released a few days ago. This program rocks. I’m using the Windows Mobile version, but there’s also J2ME version as well. (via Dare Obasanjo)
  • Any lingering interest I had in Ruby vanished yesterday as got to chapter 8 of Windows Powershell in Action. Chapter 8 is called “ScriptBlocks and Objects” and it is specifically about meta-programming. After reading that chapter, PS seems more flexible in this space than Ruby, which is the current industry darling for metaprogramming. For example, in Ruby you can optionally pass a block of code to any method. In PS, you can define a ScriptBlock like any other parameter. That means you can tell from the method signature that the ScriptBlock is used. Or you can define a function that takes multiple ScriptBlock parameters. Much more thought on this is needed.

Perusing Powershell Part 2: Error or No Output?

In yesterday’s post on PS, I provided the source for my implementation of Get-SQLServer. I realized after I made the post that there was a significant bug in the ProcessRecord method. If you specify a service instance (default or named), the cmdlet makes no effort to actually validate that such a SQL server instance exists. So if you ask for a instance that doesn’t exist, Get-SQLServer will happily write an invalid Server object to the pipeline. So I changed it to actually validate that the specified instance exists. I connect to the specified machine (local machine if not specified) using ManagedComputer and look in it’s ServerInstances collection for the specified SQL instance.

The question is, what should you do if the specified SQL instance doesn’t exist on the specified machine? One the one hand, you could write an error indicating that the SQL instance doesn’t exist. Or, you could simply write nothing to the output pipeline, which may cause an error down the line.

Which is the right approach?

At first, I wrote an error when I couldn’t find the instance, but decided that wasn’t the right approach. It isn’t really an error unless you attempt to act on that instance, right? So I thought the more PS friendly approach would be to write nothing and let the down stream cmdlets deal with it. I do write a debug message if the specified instance doesn’t exist, so the scripter isn’t completely in the dark.

So here’s the new and improved ProcessRecord method of my Get-SQLServer cmdlet:

protected override void ProcessRecord()
{
    //Make sure both -Name and -Default aren’t specified
    if (!string.IsNullOrEmpty(_Name) && _Default.IsPresent)
    {
        WriteError(new ErrorRecord(
            new ArgumentException(
                “Default and Name parameters can’t both be specified”),
            “DefaultAndName”,
            ErrorCategory.InvalidArgument,
            null));
        return;
    }

    //If the machine name is not specified, assume the local machine
    //(via the “.” value)
    string machine = string.IsNullOrEmpty(_MachineName) ? “.” : _MachineName;

    //Connect to the specified machine via the SMO WMI ManagedComputer object
    SmoWmi.ManagedComputer mc = new SmoWmi.ManagedComputer(machine);

    if (string.IsNullOrEmpty(_Name) && !_Default.IsPresent)
    {
        //If neither Name or Default are specified, write all the
        //server instances on specified machine
        foreach (SmoWmi.ServerInstance si in mc.ServerInstances)
            WriteServerObject(si);

        return;
    }

    string instanceName = _Default.IsPresent ? “MSSQLSERVER” : _Name;

    if (mc.ServerInstances.Contains(instanceName))
        WriteServerObject(mc.ServerInstances[instanceName]);
    else
        WriteDebug(“The specified SQL instance does not exist”);
}

//Helper method to create a SMO Server object from a
//SMO WMI ServerInstance object and write it to the pipeline
private void WriteServerObject(SmoWmi.ServerInstance si)
{
    if (si.Name == “MSSQLSERVER”)
        WriteObject(new Smo.Server(si.Parent.Name));
    else
        WriteObject(new Smo.Server(si.Parent.Name + “\” + si.Name));
}

Perusing Powershell Part 1: Get-SQLServer

I wrote this morning that I’ve shifted my new language focus from F# to PowerShell. I did this for a variety of reasons, but primarily because PowerShell is the future of Microsoft administration while F# is a research project. The thing that interests me most about F# is its support for hybrid OO/functional programing. Turns out, PS uses a different approach, but accomplishes much of the same goal.

In OO, most of the focus is on objects, naturally. However, administrators (i.e. the target audience of PS) tend to be much more task or action focused than object focused. Most OO languages don’t have actions as a first class citizens within the language. C# and Java don’t even allow stand alone functions – they always have to be at least static members of a class.

I’m fairly sure there are many reasons why strongly typed OO languages aren’t popular among administrators. I’m not going to go down the static/dynamic typing rat hole here, but I would guess the object/action language tradeoff is almost as important as the typing tradeoff. What’s nice about PowerShell is that while it has strong object support, it also has strong action support as well. In PS, actions are called Cmdlets. While I’m not a big fan of the name, having first class support for them in PS is one of the things I find most interesting.

PS is designed to be extended. And while there is support for defining functions in PS directly, for the most part PS is designed to be extended in a .NET OO language like C#. I have mixed feeling on this. Languages like F# and Ruby allow for these sorts of extensions to be built within the language itself. On the other hand, having a strong separation between scripting the shell and extending the shell simplifies the scripting experience without sacrificing capability of building extensions.

Here’s a simple cmdlet I wrote called Get-SQLServer. SQL Server already comes with a robust object oriented administration library, but no support for PS (no surprise, since PS just shipped). I imagine future versions of SQL will have PS support, but to me this represents a great opportunity to get deep understanding of PS as well as focus on PS cmdlet design without having to do much of the grunt work.

using System;
using System.Management.Automation;
using Microsoft.SqlServer.Management.Smo.Wmi;
using Microsoft.SqlServer.Management.Smo;

[Cmdlet(VerbsCommon.Get, "SQLServer")]
public class GetSqlServerCommand : Cmdlet
{
  private string _Name;
  [Parameter]
  public string Name
  {
    get { return _Name; }
    set { _Name = value; }
  }

  private string _MachineName;
  [Parameter]
  public string MachineName
  {
    get { return _MachineName; }
    set { _MachineName = value; }
  }

  private SwitchParameter _Default;
  [Parameter]
  public SwitchParameter Default
  {
    get { return _Default; }
    set { _Default = value; }
  }

  protected override void ProcessRecord()
  {
    string machine = string.IsNullOrEmpty(_MachineName) ? "." : _MachineName;

    if (string.IsNullOrEmpty(_Name) && !_Default.IsPresent)
    {
      //write all server instances on specified machine
      //if _machineName is null or empty, the local machine is used
      ManagedComputer mc =  new ManagedComputer(machine);

      foreach (ServerInstance si in mc.ServerInstances)
      {
        if (si.Name == "MSSQLSERVER")
          WriteObject(new Server(machine));
        else
          WriteObject(new Server(machine + "\\" + si.Name));
      }

      return;
    }

    if (!string.IsNullOrEmpty(_Name) && _Default.IsPresent)
    {
      WriteError(
        new ErrorRecord(
          new ArgumentException("Default and Name parameters can't both be specified"),
          "DefaultAndName",
          ErrorCategory.InvalidArgument,
          null));

      return;
    }

    if (_Default.IsPresent)
      WriteObject(new Server(machine));
    else
      WriteObject(new Server(machine + "-" + _Name));
  }
}

As you can see, it’s fairly simple. The cmdlet takes three parameters – Name, MachineName and Default. MachineName represents the windows server machine the SQL server instance is running on. Name is a common PS parameter, and here is used to specify the SQL instance name you’re interested in. However, since the default instance of SQL on a given server doesn’t have a name, I had to add a Default flag. Since the cmdlet can return a collection of SMO Server objects, I needed a way to distinguish between “Give me the default instance on a machine” and “Give me all instances on a machine”. I couldn’t use a null or empty Name parameter to mean both. If neither Name or Default are specified, it means the user wants a collection. If both are specified, it’s an error. Otherwise, the cmdlet returns a single Server object – either the default or a named instance as specified.

Using the cmdlet is fairly straight forward. If you simply specify “Get-SQLServer”, it gives you a collection of all the SQL Server instances on the local machine. If you specify “Get-SQLServer -Default”, it gives you just the default SQL Server instance on the local machine. And if you specify “Get-SQLServer -Name sqlexpress”, it gives you just the SQL Express instance on the local machine. Using the -MachineName parameter allows you to connect to a remote SQL server box, but is otherwise the same.

Of course, this is a very simple cmdlet. It doesn’t even change the current state of the system. But now that we have a reference to a SQL Server instance, we can call methods on that instance. In the next post (whenever that is), I’ll build some cmdlets to let me create and drop databases on that instance.

Morning Coffee 23

  • My Binding Across States post made it to the home page of DotNetKicks, so at last six other people liked it. I wonder if I’ll be able to detect and traffic increase from that.
  • I wrote yesterday that I had ordered a PCMCIA Smart Card reader for my laptop. I ordered it around 11:30pm on Wednesday and it arrived yesterday around 2pm.That’s good service! And so much more convenient than the USB smart card reader.
  • I also mentioned yesterday that I had moved my laptop over to Vista. I’m not sure why, but my battery life has gotten significantly better. Maybe it’s because these days I’m primarily using my laptop to remote into my desktop so I’m not exercising the local system much.
  • I was checking out Windows PowerShell Quick Reference from O’Reilly (on Safari) and discovered this PS offers the numeric constants of gb, mb, and kb to represent gigabytes, megabytes, and kilobytes. Example: $downloadTime = (1gb + 250mb) / 120kb. That’s pretty cool.
  • Speaking of PS, I stumbled across PowerSMO! from Dan Sullivan. Instead of building native PS support for SQL administration, PowerSMO! makes it easy to access SMO objects in PS. Instead of having to call new-object Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer, you call goGet-SMO\_ManagedComputer. Even more interestingly, PowerSMO! uses metaprograming techniques to generate all the Get_SMO* methods. It iterates over all the SMO types – about 1000 types in total – and generates the associated Get-SMO functions into a temp script file. Once the temp file is created, it can be invoked like any other script. Must noodle on this approach further.