PowerShell Cookbook

Search

Categories

 

On this page

Outlook Automation in PowerShell - Calendar Scrubbing
TechTalk Interview Posted
Getting Started with PowerShell
Add Custom Methods and Properties to Types in PowerShell
Scripting Network / TCP Connections in PowerShell
PowerShell Prompt Here PowerToy
Download the Official Windows PowerShell 1.0 Release!
A New Virtual Earth Mashup in Born
Mathematical Pumpkins
Writing PowerShell Cmdlets vs. Writing PowerShell Providers

Archive

Blogroll

Disclaimer
I work for Microsoft.

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

RSS 2.0 | Atom 1.0 | CDF

Send mail to the author(s) E-mail

Total Posts: 220
This Year: 20
This Month: 0
This Week: 0
Comments: 533

Sign In

 Wednesday, December 13, 2006
Thursday, December 14, 2006 7:45:39 AM (Pacific Standard Time, UTC-08:00) ( )

Here's one thing you might have noticed happening to your Outlook calendar. As time goes on, the calendar titles get obscured by the ugly meeting barnacles such as "FW: " and "Updated: ". I don't know anybody that cares about that meta-data, but it lives on -- and I'd like to remove it.

Omar Shahine mentioned that he wrote an Outlook addin to do this once. Since I've been doing some mail management tasks with PowerShell lately (more on that in future posts,) I thought it might be a useful thing to demonstrate via Outlook's Outlook.Application COM object.

The script below is quite simple. Run "Set-CalendarTitles," watch the pretty progress bar, and enjoy your newly clean calendar.

##############################################################################
## Set-CalendarTitles.ps1
##
## Clean calendar titles to remove:
## "FW: ", "Updated: "
##############################################################################

function main
{
    ## Create the outlook application object, and connect to the calendar
    ## folder
    $olApp = new -com Outlook.Application
    $namespace = $olApp.GetNamespace("MAPI")
    $fldCalendar = $namespace.GetDefaultFolder(9)

    "Gathering calendar items"
    $items = $fldCalendar.Items

    ## Visit each item, updating progress as we go
    $counter = 0
    foreach($item in $items)
    {
        $status = "Processing item {0} of {1}: {2}" -f $counter,$items.Count,$item.Subject
        Write-Progress "Processing calendar items" $status -PercentComplete ($counter / $items.Count * 100)

        ## Remove the extra text
        cleanItem $item "FW: "
        cleanItem $item "Updated: "

        $counter++
    }
}

## Clean the title of a calendar entry if it matches
## searchString
function cleanItem($item, $searchString)
{
    if($item.Subject -match $searchString)
    {
        $item.Subject = $item.Subject -replace $searchString,""
        $item.Save()
    }
}

. main
Comments [5] | | # 
 Sunday, December 10, 2006
Monday, December 11, 2006 3:36:34 AM (Pacific Standard Time, UTC-08:00) ( )

If you missed the TechTalk radio interview (but wanted to hear it,) I've uploaded it here: http://www.leeholmes.com/projects/techtalk/techtalk_12-10-2006.mp3. Thanks, Tom, for an interesting interview!

 

Comments [0] | | # 
 Thursday, December 07, 2006
Friday, December 08, 2006 12:31:30 AM (Pacific Standard Time, UTC-08:00) ( )
One of the more common questions we get from people interested in PowerShell is "how do I get started?" They see  examples of PowerShell weilding its considerable strength, and are often intimidated by a perceived learning curve. It doesn't have to be that way, though — PowerShell is easy to start playing with, and easy to continue learning.

First of all, you’ll want to download PowerShell. If you visit http://www.microsoft.com/PowerShell, you’ll get to the PowerShell homepage that lists an enormous number of resources. One of the first resources is a link to the download location.

Next, just start the shell and start exploring. The DOS commands you may (or may not) be used to still work: dir, cd, ipconfig, etc. Many of the UNIX commands you may (or may not) be used to  still work: ls, cd, ps, etc.

Then, take a dip into the awesome documentation that PowerShell ships with. The PowerShell menu on your start menu links to them directly:

  • Getting started: A 32-page overview of PowerShell and its core concepts
  • Quick reference: A 2-page summary of PowerShell’s scripting language
  • User Guide: A 116-page user guide for PowerShell. Perhaps unbelievable but true, it is a really useful book that we include for free with the product.
  • Help content: A large amount of help is available through the Get-Help cmdlet  -- see both the Getting Started documentation and User Guide for more information about this powerful command.

However, some people just like to sit back and have their learning delivered to them. You’re in good company there, too, as there are plenty of those resources.

Ars Technica wrote probably the best online overview, back when PowerShell was called "Monad": http://arstechnica.com/guides/other/msh.ars/

There are also interviews, videos, screencasts, and more:

Once you start exploring deeper, there is a fantastic opportunity for continual learning:

And, did I mention that this hasn’t cost you a thing yet?

If you want books or individualized training, you continue to have many options:

  • O’Reilly’s PowerShell Cookbook: http://www.leeholmes.com/blog/PowerShellCookbookNowAvailable.aspx
    584 pages of PowerShell recipes that focus squarely on showing you how to use PowerShell to get your job done. It builds on a huge base of distilled knowledge, and includes:
    • Solutions to the most popular and searched-for TechNet / Script Center topics
    • Scripts that address the most common community, newsgroup, and new user questions
    • Scripts that wrap around and hide the complexity of advanced (but very useful) PowerShell scripting techniques
    • Task-based introduction to all of PowerShell’s major features
  • Bruce Payette's PowerShell in Action: http://www.amazon.com/Windows-Powershell-Action-Bruce-Payette/dp/1932394907
    The best in-depth book for the scripting language you could ask for, from one of its co-designers.
  • O’Reilly’s PowerShell Quick Reference: http://www.leeholmes.com/blog/OReillyPowerShellQuickReferenceNowAvailable.aspx
    My 120-page guide (in PDF format) that provides the essential reference material for your day-to-day use of PowerShell.  With a concise explanation at your fingertips, there is no need to memorize esoteric topics like regular expressions and string formatting specifiers. Aside from its straight factual reference material, the Quick Reference also provides an enormous amount of value by distilling large bodies of practical knowledge into their most usable forms, including: the most useful classes from the .NET Framework, useful WMI classes, and useful COM automation objects.
  • More books: http://www.amazon.com/s/?url=search-alias%3Dstripbooks&field-keywords=PowerShell
  • Internet serach for “PowerShell  training”

So, jump in and enjoy the revolution!

Comments [4] | | # 
 Monday, December 04, 2006
Monday, December 04, 2006 8:29:19 AM (Pacific Standard Time, UTC-08:00) ( )

To give a glimpse into the writing process behind my upcoming "Windows PowerShell - The Definitive Guide" (O'Reilly,) I'll occasionally post entries "as the author sees it."  This entry discusses PowerShell's type extension files.

 

Add Custom Methods and Properties to Types

Problem

You want to add your own custom properties or methods to all objects of a certain type.¶

Solution

Use custom type extension files to add custom members to all objects of a type.

Discussion

Although the Add-Member cmdlet is extremely useful in helping you add custom members to individual objects, it requires that you add the members to each object that you want to interact with. It does not allow you to automatically add them to all objects of that type. For that purpose, PowerShell supports another mechanism custom type extension files.

Type extensions are simple XML files that PowerShell interprets. They allow you (as the administrator of the system) to easily add your own features to any type exposed by the system. If you write code (i.e.: a script or function) that primarily interacts with a single type of object, then that code might be better suited as an extension to the type, instead.

Since type extension files are XML files, ensure that your customizations properly encode the characters that have special meaning in XML files such as <, >, and &

For example, imagine a script that returns the free disk space on a given drive. That might be helpful as a script, but you might find it easier to instead make PowerShell's PsDrive objects themselves tell you how much free space they have left.¶

Getting Started

If you haven't already, the first step in creating a types extension file is to create an empty one. The best location for this is probably in the same directory as your custom profile, with the name Types.Custom.ps1xml

Example 3-2. Sample Types.Custom.ps1xml file

<?xml version="1.0" encoding="utf-8" ?>¶

<Types>¶

</Types>¶

Next, add a few lines to your PowerShell profile so that PowerShell loads your type extensions during startup:¶

$typeFile = (join-path (split-path $profile) "Types.Custom.ps1xml")¶

Update-TypeData -PrependPath $typeFile¶

By default, PowerShell loads several type extensions from the Types.ps1xml file in PowerShell's installation directory. The Update-TypeData cmdlet tells PowerShell to also look in your Types.Custom.ps1xml file for extensions. The –PrependPath parameter makes PowerShell favour your extensions over the built-in ones should there be a conflict.¶

Once you have a custom types file to work with, adding functionality becomes relatively straight forward. As a theme, we will do exactly what we alluded to earlier: add functionality to PowerShell's PsDrive type.¶

To support this, we need to extend your custom types file so that it defines additions to the System.Management.Automation.PSDriveInfo type. This is the type that the Get-PsDrive cmdlet generates.¶

<?xml version="1.0" encoding="utf-8" ?>¶

<Types>¶

  <Type>

    <Name>System.Management.Automation.PSDriveInfo</Name>

    <Members>

          add members such as <ScriptProperty> here

    </Members>

  </Type>

</Types>¶

Add a ScriptProperty

A ScriptProperty allows you to add properties (that get and set information) to types, using PowerShell script as the extension language. It consists of three child elements: the Name of the property, the Getter of the property (via the GetScriptBlock child,) and the Setter of the property (via the SetScriptBlock child.)¶

In both the GetScriptBlock and SetScriptBlock sections, the $this variable refers to the current object being extended. In the SetScriptBlock section, the $args[0] variable represents the value that the user supplied as the right-hand side of the assignment.¶

The following example adds an AvailableFreeSpace ScriptProperty to PSDriveInfo. When you access the property, it returns the amount of free space remaining on the drive. When you set the property, it outputs what changes you must make in order to obtain that amount of free space. ¶

Example 3-3. A ScriptProperty for the PSDriveInfo type

      <ScriptProperty>

        <Name>AvailableFreeSpace</Name>

        <GetScriptBlock>

          ## Ensure that this is a FileSystem drive

          if($this.Provider.ImplementingType -eq

             [Microsoft.PowerShell.Commands.FileSystemProvider])

          {

             ## Also ensure that it is a local drive

             $driveRoot = $this.Root

             $fileZone = [System.Security.Policy.Zone]::CreateFromUrl($driveRoot).SecurityZone

             if($fileZone -eq "MyComputer")

             {

                $drive = New-Object System.IO.DriveInfo $driveRoot

                $drive.AvailableFreeSpace

             }

          }

        </GetScriptBlock>

        <SetScriptBlock>

          ## Get the available free space

          $availableFreeSpace = $this.AvailableFreeSpace

 

          ## Find out the difference between what is available, and what they

          ## asked for.

          $spaceDifference = (([long] $args[0]) - $availableFreeSpace) / 1MB

 

          ## If they want more free space than they have, give that message

          if($spaceDifference -gt 0)

          {

             Write-Host ("To obtain $args bytes of free space, free $spaceDifference " +

                "megabytes.")

          }

          ## If they want less free space than they have, give that message

          else

          {

             $spaceDifference = $spaceDifference * -1

             Write-Host ("To obtain $args bytes of free space, use up $spaceDifference " +

                "more megabytes.")

          }

        </SetScriptBlock>

      </ScriptProperty>

Add an AliasProperty

An AliasProperty provides an alternative name (alias) for a property. The referenced property does not need to exist when PowerShell processes your type extension file, as the property might be added later by mechanisms such as the Add-Member cmdlet.¶

The following example adds a Free AliasProperty to PSDriveInfo. When you access the property, it returns the value of the AvailableFreeSpace property. When you set the property, it sets the value of the AvailableFreeSpace property. ¶

Example 3-4. An AliasProperty for the PSDriveInfo type

      <AliasProperty>

        <Name>Free</Name>

        <ReferencedMemberName>AvailableFreeSpace</ReferencedMemberName>

      </AliasProperty>

Add a ScriptMethod

A ScriptMethod allows you to define an action on an object, using PowerShell script as the extension language. It consists of two child elements: the Name of the property, and the Script

In the script element, the $this variable refers to the current object being extended. Like a stand-alone script, the $args variable represents the arguments to the method. Unlike stand-alone scripts, ScriptMethods do not support parameters (via the param statement.)¶

The following example adds a Remove ScriptMethod to PSDriveInfo. When you call this method with no arguments, the method simulates removing the drive (through the –WhatIf option to Remove-PsDrive.) If you call this method with $true as the first argument, it actually removes the drive from the PowerShell session.¶

Example 3-3. A ScriptMethod for the PSDriveInfo type

      <ScriptMethod>

        <Name>Remove</Name>

        <Script>

          $force = [bool] $args[0]

 

          ## Remove the drive if they use $true as the first parameter

          if($force)

          {

             $this | Remove-PSDrive

          }

          ## Otherwise, simulate the drive removal

          else

          {

             $this | Remove-PSDrive -WhatIf

          }

        </Script>

      </ScriptMethod>

Add other extension points

PowerShell supports several additional features in the types extension file, including CodeProperty, NoteProperty, CodeMethad, and MemberSet. Although not generally useful to end-users, developers of PowerShell providers and cmdlets will find these features helpful. For more information about these additional features, see the Windows PowerShell SDK, or MSDN documentation.¶

Comments [4] | | # 
 Wednesday, November 29, 2006
Thursday, November 30, 2006 2:04:06 AM (Pacific Standard Time, UTC-08:00) ( )

Awhile back, I introduced a script that allows you interact with remote TCP ports (such as Telnet.) While useful, it worked only interactively. It would be even more useful if you were able to script a network or TCP connection.

Let me introduce Connect-Computer.ps1 v2, which allows exactly that:

First, a simple scripted HTTP session:

$http = @"
GET / HTTP/1.1
Host:search.msn.com
`n`n
"@

$http | Connect-Computer search.msn.com 80

 

Second, a scripted POP3 session (Parse-TextObject comes from here: http://www.leeholmes.com/blog/parsetextObjectAWKWithAVengeance.aspx):

if(-not (test-path Variable:\mailCredential))
{
   $mailCredential = Get-Credential
}
$address = $mailCredential.UserName
$password = $mailCredential.GetNetworkCredential().Password
$pop3Commands = "USER $address","PASS $password","STAT","QUIT"
$output = $pop3Commands | Connect-Computer mail.leeholmes.com 110
$inbox = $output.Split("`n")[3]
$status = $inbox | Parse-TextObject -PropertyName "Response","Waiting","BytesTotal","Extra"
"{0} messages waiting, totaling {1} bytes." -f $status.Waiting,$status.BytesTotal

 

Now, here is Connect-Computer.ps1

## Connect-Computer.ps1
## Interact with a service on a remote TCP port
param(
        [string] $remoteHost = "localhost",
        [int] $port = 80,
        [string] $inputObject,
        [int] $commandDelay = 100
     )

[string] $output = ""

$currentInput = $inputObject
if(-not $currentInput)
{
    $SCRIPT:currentInput = @($input)
}
$scriptedMode = [bool] $currentInput

function Main
{
    ## Open the socket, and connect to the computer on the specified port
    if(-not $scriptedMode)
    {
        write-host "Connecting to $remoteHost on port $port"
    }

    trap { throw "Could not connect to remote computer: $_"; exit }
    $socket = new-object System.Net.Sockets.TcpClient($remoteHost, $port)

    if(-not $scriptedMode)
    {
        write-host "Connected.  Press ^D followed by [ENTER] to exit.`n"
    }

    $stream = $socket.GetStream()
    $writer = new-object System.IO.StreamWriter($stream)

    ## Create a buffer to receive the response
    $buffer = new-object System.Byte[] 1024
    $encoding = new-object System.Text.AsciiEncoding


    while($true)
    {
        ## Receive the output that has buffered so far
        $SCRIPT:output += GetOutput

        ## If we're in scripted mode, send the commands,
        ## receive the output, and exit.
        if($scriptedMode)
        {
            foreach($line in $currentInput)
            {
                $writer.WriteLine($line)
                $writer.Flush()
                Start-Sleep -m $commandDelay
            }

            $SCRIPT:output += GetOutput

            break
        }
        ## If we're in interactive mode, write the buffered
        ## output, and respond to input.
        else
        {
            if($output) 
            {
                foreach($line in $output.Split("`n"))
                {
                    write-host $line
                }
                $SCRIPT:output = ""
            }

            ## Read the user's command, quitting if they hit ^D
            $command = read-host
            if($command -eq ([char4)) { break; }

            ## Otherwise, Write their command to the remote host     
            $writer.WriteLine($command)
            $writer.Flush()
        }
    }

    ## Close the streams
    $writer.Close()
    $stream.Close()

    ## If we're in scripted mode, return the output
    if($scriptedMode)
    {
        $output
    }
}

## Read output from a remote host
function GetOutput
{
    $outputBuffer = ""
    $foundMore = $false 

    ## Read all the data available from the stream, writing it to the
    ## output buffer when done.
    do
    {
        ## Allow data to buffer for a bit
        start-sleep -m 1000

        ## Read what data is available
        $foundmore = $false
        while($stream.DataAvailable) 
        {
            $read = $stream.Read($buffer, 01024)   
            $outputBuffer += ($encoding.GetString($buffer, 0, $read)) 
            $foundmore = $true
        }
    } while($foundmore)

    $outputBuffer
}

. main
[Edit: Thanks to Marco for pointing out a few issues that come up when you try to retrieve massive amounts of data (such as a newsgroup listing). I've updated the script to fix those.]
Comments [2] | | # 
 Monday, November 20, 2006
Monday, November 20, 2006 9:12:44 PM (Pacific Standard Time, UTC-08:00) ( )

Today, we have a guest post from Michael Murgolo. He's developed a PowerShell Prompt Here powertoy (like the one we all know and love,) but this one doesn't suffer from the uninstall bug that the current CMD Prompt Here powertoy (or its derivatives) do. And the explanation is awesome, to boot.

 

An Old PowerToy is New Again

by Michael Murgolo

PowerShell PowerToys Download

One of the most popular Windows PowerToys is the venerable Command (or CMD) Prompt Here.  This PowerToy is still available as part of the Microsoft PowerToys for Windows XP or the Windows Server 2003 Resource Kit Tools.  With this PowerToy installed, you can right click on a folder or drive in Windows Explorer and select CMD Prompt Here from the context menu.  This will open a command prompt with the selected folder as the current directory.

Because this is so handy, I use this PowerToy numerous times as day.  As I was trying to learn and use Windows PowerShell, I found myself wishing for the same functionality in PowerShell.  So I grabbed the Setup Information (INF) File for CMD Prompt Here, cmdhere.inf, from the Windows Server 2003 Resource Kit Tools and modified it to create a PowerShell Prompt Here context menu.  This INF file is included in the PowerShell PowerToys Download.  To install it, right click on the INF file and select Install.

In the course of creating the PowerShell version, I discovered that the original CMD Prompt Here PowerToy had a bug that would leave behind a dead context menu entry when it was uninstalled.  I have provided an updated version of cmdhere.inf for you convenience also in the PowerShell PowerToys Download. 

How it works

Both of these PowerToys take advantage of the fact that these context menu entries are configured in the Windows Registry under keys associated with the Directory and Drive object type.  This is done in the same way that context menu actions are associated with file types.

For example, when you right click on a .txt file in Explorer, you get several actions at the top of the list like Open, Print, and Edit.  To find out how these items are configured, let’s take a short journey through the HKEY_CLASSES_ROOT Registry hive.  If you open the Registry Editor and expand the HKEY_CLASSES_ROOT branch you will see keys that are named for file types like .doc, .txt, etc.  If you click on the .txt key, you will see the (Default) value is txtfile.

This is the object type associated with a .txt file.  If you scroll down and expand the txtfile key, then expand the shell key under that, you will see keys named for some of the context menu entries for a .txt file.  (You will not see all of them because there are other methods for creating context menus.)  Under each of these is a command key.  The (Default) value under the command key is the command line that Windows executes when you select that context menu item.

The PowerToys for both the CMD prompt and PowerShell prompt use this technique to configure the CMD Prompt Here and PowerShell Prompt Here context menu entries. There are no file types associated with drives and directories, but there is a Drive and a Directory key under HKEY_CLASSES_ROOT associated with those object types.

The PowerShellHere.ps1 script (in the attached file) shows how to set the same Registry entries as PowerShellHere.inf. This can be used in the case where an entry is Add/Remove Programs to uninstall the PowerToy is not desired.

To remove these entries you can use RemovePowerShellHere.ps1, also included in the PowerShell PowerToys Download.

  

 

Michael Murgolo is a Senior Infrastructure Consultant for Microsoft Consulting Services. He is focused in the areas of operating systems, deployment, network services, active directory, systems management, automation, and patch management.

Comments [4] | | # 
 Tuesday, November 14, 2006
Tuesday, November 14, 2006 10:37:33 AM (Pacific Standard Time, UTC-08:00) ( )

A few minutes ago, Bob Muglia and Jeffrey Snover at IT Forum announced something at we've long been waiting for – the official Release to Web (RTW) of Windows PowerShell v1.0!

In late December of 2002, PowerShell entered the public eye when a Slashdot reader stumbled upon a job posting for "Microsoft's Next Generation Shell". About a year later, we officially announced the project (code-named "Monad") at the 2003 Microsoft Professional Developer's Conference. Things started to really pick up steam when we released our first really public preview in September of 2004 – a fact not missed by the ever vigilant Slashdot.
Since then, we've shipped incremental previews frequently, gaining enormous benefit from all of you – a passionate and active community of devoted beta enthusiasts:

"Monad" Beta 1 - 06/17/2005
"Monad" Beta 2 - 09/13/2005
"Monad" Beta 3 - 01/10/2006
"Monad" Beta 3.1 - 03/09/2006
Windows PowerShell RC1 - 04/25/2006
Windows PowerShell RC2 - 09/27/2006
Windows PowerShell RTW – 11/14/2006

Each release added features, fixed bugs, and incorporated heaps of changes initiated by feedback from the community.

This has been a long and adventurous journey – something that's truly been worth relishing. Whether you are an old or new participant in the PowerShell community, you should feel proud of your contributions – and for a job well done.

You can find pointers to the official release at http://www.microsoft.com/powershell -- so go install it, and enjoy the revolution!

Comments [6] | | # 
 Thursday, November 09, 2006
Thursday, November 09, 2006 8:28:08 AM (Pacific Standard Time, UTC-08:00) ( )

About 8 months ago, I wrote a Virtual Earth mashup to display commute times to Microsoft in and around the Seattle area. It's been very successful, and solves a big problem for many people looking to buy a house (amongst other things.)


http://www.leeholmes.com/projects/commute

About 3 or 4 months after posting the mashup, the Virtual Earth team changed a bunch of the APIs, which pretty much broke every existing mashup – including mine. I patched it up a bit some time later, but couldn't spend the time to fully restore its functionality. For example, the zooming controls were broken, as were the panning controls.

Neither writing the mashup (nor living through the breaking changes) were terribly pleasant experiences. The Virtual Earth map control was simply too basic. With not much effort, you get a map that scrolls, but nothing else. No UI, no support for panning, zooming, or anything else.

Want to make it interactive and snazzy? In my case, that meant copying tons of Virtual Earth infrastructure scripts, html, images, and other random junk in order to make something presentable.

However, the end result was definitely exciting despite all of that.

I checked on the APIs tonight to get a gauge on how much work was in front of me to fix it completely again, and was stunned. The Virtual Earth team has done a truly amazing job at focusing on making the job of a "masher" as easy as possible. Their programming model has matured significantly, placing a much cleaner boundary between your application and the Virtual Earth implementation details. It feels like a real API now, as opposed to forcing you into an invasive, parasitic implementation.

One innovation I'm immensely impressed with is their new interactive SDK. It takes cues from the cookbook / task-based approach to learning. First, you click on a node to say, "I want to --> Use pushpins --> Add a custom pushpin." Then, the SDK shows you – through an interactive working view, example code, and reference page -- exactly how to do it.

In the end, I didn't patch my old code back into working condition. I reused my support code, but rewrote the UI and interface to Virtual Earth again from scratch. In just a few hours I was done:

  • My index page has gone from 11k to 3k
  • My custom Javascript has gone from 6k to 5k
  • My entire project has shrunk from 391kb to 71kb
  • That furrow in my brow is gone

Kudos to the Virtual Earth team. The mashup experience is definitely a first-class citizen, and it shows.

Comments [0] | | # 
 Thursday, November 02, 2006
Thursday, November 02, 2006 7:22:44 AM (Pacific Daylight Time, UTC-07:00) ( )

Well, last night was Halloween, where I got the chance to enjoy the eerie glow of our scary pumpkin.  Well, scary if you don't like fractals, that is.

Last year, we carved out a Sierpinski Triangle -- which surprisingly only took a toothpick or two to repair isolated triangles:

This year, I wanted to stay with the fractal theme. I didn't necessarily want to attempt the Julia or Mandelbrot sets, so instead did a Sierpinski Carpet (along with a wee bit of evil, of course:)

 

Not being one to cut 64 of the level-three squares by hand, a cordless drill came in extremely handy.

Unfortunately, when I'm out trick-or-treating, there's nobody around to give candy to the little monsters.  I leave a note above a bowl on a chair -- this year, I finally realized why my calligraphy pens include red in the set!

 

Comments [0] | | # 
 Tuesday, October 31, 2006
Wednesday, November 01, 2006 12:20:46 AM (Pacific Daylight Time, UTC-07:00) ( )

A question that sometimes comes up is, "When do I write a PowerShell provider instead of a cmdlet?" To explain that, it is useful to understand how PowerShell distills management concepts for administrators.

In the pre-PowerShell world, the command-line management experience is fairly fractured. You have a huge number of awkwardly named commands, with no way to quickly determine what they mean. Many of them perform nearly identical actions, but have very different names. The image above illustrates a chaotic mix of commands that work primarily on files and directories.

The first approach that PowerShell uses to distill management concepts is to name commands with a Verb-Noun (Action, Item) pattern.

To make it easier for an administrator to learn the actions available for a new noun (such as Service or Process,) we provide strong guidance that verbs come from a standard set. The image above shows how you might name the earlier commands, while paying attention to the standardized verbs.

Now, what happens if you want to make these cmdlets work on the Registry?  How would you name them in that situation? Some of them apply exactly (but operate on a RegistryKey rather than a File,) some of them may not apply (such as the content of a registry key,) and some of them definitely do not apply (such as the list of running processes.)

Notice that some of the nouns share a lot in common, and converge to a few basic concepts. From the examples given above, you can perform actions on items, content, and locations.

The first set is clearly unmanageable, and makes life difficult for administrators.

The second set provides the main benefit of cmdlets. Consistent naming, and discoverability. Administrators can say, "I have a <Noun>, so already have a pretty good idea of what I can do with it."

The third set provides the main benefits of providers. For the major noun sets that we know about (items, content, properties, and navigation,) we make it as easy as possible for you to implement all related commands for that set. When you do, Administrators can say, "This provider supports navigation and items, so I already have a pretty good idea of what commands work with it."

So, if you want to support any of the major noun sets, you should write a provider.

As PowerShell matures, so should its list of provider types. For example, the *-Process cmdlets and *-Service cmdlets are strikingly familiar, and suggest the need for a standard lifecycle set of cmdlets.  It should also be noted that you can implement any or all of the standard provider types. For any that you implement, you get all related cmdlets for free.

[Edit: Resized images]

Comments [4] | | #