One thing that's missing from PowerShell is the ability to import foreign namespaces into the current context. That leads to a lot of typing at the interactive prompt and bloated hard-to-read lines in your scripts. For example, even if you've loaded the TFS client assemblies, you still have to write out fully-qualified type names like this:
RICBERG470> $itemSpec = new-object Microsoft.TeamFoundation.VersionControl.Client.ItemSpec ("$/foo", [Microsoft.TeamFoundation.VersionControl.Client.RecursionType]::None)
Ick!
What can we do about it? Well, the first parameter to new-object is actually a string, so we could store the string "Microsoft.TeamFoundation.VersionControl.Client" somewhere convenient and build from there.
RICBERG470> $vcc = "Microsoft.TeamFoundation.VersionControl.Client"RICBERG470> $itemSpec = new-object "$vcc.itemspec" ("$/foo", [Microsoft.TeamFoundation.VersionControl.Client.RecursionType]::None)
Better, but far from perfect.
Right! Namespaces aren't objects in PowerShell, so we can't manipulate them directly, but types are. (They're objects of type RuntimeType, to be exact.) Objects are PowerShell's bread & butter -- importing a ton of them sounds clunkier than "using <namespace>" in C#, but it's actually a cinch. I give you add-types.ps1:
param( [string] $assemblyName = $(throw 'assemblyName is required'), [object] $object)process { if ($_) { $object = $_ } if (! $object) { throw 'must pass an -object parameter or pipe one in' } # load the required dll $assembly = [System.Reflection.Assembly]::LoadWithPartialName($assemblyName) # add each type as a member property $assembly.GetTypes() | where {$_.ispublic -and !$_.IsSubclassOf( [Exception] ) -and $_.name -notmatch "event"} | foreach { # avoid error messages in case it already exists if (! ($object | get-member $_.name)) { add-member noteproperty $_.name $_ -inputobject $object } }}
Usage example:
RICBERG470> $tfs | add-types "Microsoft.TeamFoundation.VersionControl.Client"RICBERG470> $itemSpec = new-object $tfs.itemspec("$/foo", $tfs.RecursionType::none)
Much better. Not only does it work in the [] case, we don't even need the brackets anymore! Best of all, it works with tab completion. "RecursionType" above only took 3 keystrokes (and no Shift key). That's why I filter out exceptions & events, BTW -- they pollute the autocomplete list with zillions of types I'd never use in a script, much less interactively. If you disagree, feel free to yank those conditions.
TFS readers: if you're with me so far, you'll probably want to edit your copy of get-tfs.ps1. Just add this line to the end of the foreach block:
$tfs | add-types $entry[1]
edit 5/15/07: used IsSubClassOf() instead of -notmatch to filter out exceptions. Thanks to Jay Bazuzi for the suggestion.