PowerTab 0.93 PowerShell Tab Expansion scripts library
PowerTab 0.93 is released
PowerTab093.Zip Download or get it from the Overview Page !
If you are using PowerTab for the first time with this version , as there is a lot of functionality added to the standard tab completion in PowerShell to make best use of it, be sure to check out the rest of the series !,
For more information about the PowerTab suite see the PowerTab Overview Page where you allways can find the latest version for download, or you can use the TagList PowerTab to get a list of all former posts about the PowerTab library.
* Upgraders note * , from version 0.92 you can just replace the files :
and a lengthy Excuse for posting this version ;-)
Just when I, just as Jeffrey Snover at a former stage in the PowerTab evolution , did think the PowerTab library was getting at feature complete level. I thought the main tab expansion functionality coverage of PowerTab was becoming pretty complete, my feature wish and idea list was mostly empty, and hence I expected not much more big functionality changes soon.
A lot of new functionality was added to the PowerTab library lately , hence the code is in need of a good cleaning up and I have a lot of re-factoring to-do's on my list for the next version to make the code more clear and improve the performance. I mostly focused on the features lately and the development method I use for the PowerTab library is primary "Dog Fooding" .I run the latest version on my laptop and all my work and home computers. To make changes I basically edit the running version of PowerTab on-the-fly while working with it for small changes. If the change to much work for a direct fix or needs to be refined I implement or complete it later when I get the chance. I do this independent of which computer I'm using at that moment and I keep the versions on the other machines in sync on every change I make by updating the scripts first next time I use them.
History of PowerTab
The possibility to customize Tab Expansion in PowerShell was added in Monad Beta 2 ( see The new TabExpansion feature... on the PowerShell team blog ). I made my first addition to the Tab Expansion function a short time later when I added Tab-completion for static methods and properties on .NET types ( see : PowerShell Tab Completion on my old blog.) This was my first customization to this function and over the last year, this first simple addition to the standard TabExpansion function, has grown into the current Powertab library.
I use my own TabExpansion function exclusively for over a year now, it was under constant development often patched and changed on the fly using notepad and copying blocks of code. This way of development works great for prototyping and self use (my-ware) but it also tends make a mess of the Code over time, and the PowerTab library could use some cleaning at the moment.
So I planned a refactoring round as the first planned action for the next version of PowerTab , the functionality added and usage scenarios covered by PowerTab did grow fast and are getting so massive, hence it can take a while for a user to find all the functionality it offers and to get most out the the PowerTab library, so I'm working on a quick-sheet and more usage examples also
The library scripts are also very basic, I added most of this library scripts more as an examples and starting point for learning about the workings of PowerTab and how to tune exactly to your needs by customizing the Tab Expansion library. but most functions are very simple only a couple of lines and good for learning this way this was not very high on my list.
Added Functionality
But it went a bit different, when I started with Microsoft Solution Accelerator for Business Desktop Deployment 2007 from PowerShell
see also :PowerTab 0.93 and BDD 2007 teaser and PowerTab 0.93 and BDD 2007 teaser Part 2
I did find an area I did not cover in PowerTab 0.93 , Tab Completion on static Methods and Properties where not supported yet.
Then , when I did work with BDD, PowerShell and script a colleague wrote, I found some other scenarios I did not cover yet with PowerTab 0.92, and I got errors loading the BDD types into that TabExpansion database so instead of cleaning up, I added more functionality in a quick-and-Dirty fashion.
But as I resolved the error ( not sure if it really was a bug in PowerTab or in the BDD assembly, as this is the first time a had this problem with adding types from the assembly of a external managed DLL loaded into PowerShell ) and to enable PowerShell users interested in working with BDD to try the examples for them self , after the teaser and the Ben Hunter I could not wait till I had time to clean it up so I posted my own current version as 0.93. As the needed changes are more cosmetic I do not have the time to do the cleaning soon and I think that the added value for 0.93 is enough to an upgrade, so here it is
But it's a promise, I will do some cleaning work for next version, Updates for version 0.93
Expansion of variables to text
when loading the DLL I wanted to "walk" to the DLL using tabcompletion but as I used a environment variable to "find" the program files directory I could not use tabcompletion so I decided to fix this.
In 0.92 I added already some shortcuts like this to for example resolve the $profile Path on \[tab] , but I think most people will not even know about them and I do not think I even mentioned them as a feature when I did add them but I like them a lot :
#'.*\$PsHome.*' {$matches[0] -replace '\$PsHome',$pshome}
Now I wanted this functionality for a environment variable ( in this case $env:ProgramFiles ) As a lot but not all environment variables contain a Path, I did not want more hard coded shortcuts
So to keep it simple I decided to use the \ and then TAB to enable expansion of ALL variables to there text version"ToString()" and used this RegEx for it :
'.*(\$+*)\\$'
I did think before I added it that it might give other unwanted side-effects, but till now it seems to work ok, I'm not sure if it is a function the general PowerTab user will use much or will be excited about, but for me for me this functionality is very useful works great and I do really like it !
Keeping the variable is better for use in a script but this resolving is great for interactive use when creating a path, or this method can be used to generate the complete path to generate the script line interactive like this and then we can add the variable again to the script later.
In the Flash example here : PowerTab 0.93 and BDD 2007 teaser you can see this in action and how great it fits in with the other PowerTab functions used to almost completely create the following line by using PowerTab TabExpansion typing only a few letters and [TAB].
[System.Reflection.Assembly]::LoadFile("$env:ProgramFiles\BDD 2007\bin\Microsoft.BDD.ConfigManager.dll")
Error on loading TypeInfo of the BDD assembly
When loading the types into PowerTab 0.92 after importing the DDL using Update-TabExpansionTypes, I got an error like in the example below (using the new function Get-Assembly I made while this troubleshooting this error and added it to the PowerTab 0.93 library
PoSH> Get-Assembly bdd
GAC Version Location
--- ------- --------
False v2.0.50727 F:\Program Files\BDD 2007\bin\Microsoft.BDD.ConfigManager.dll
PoSH> (Get-Assembly bdd).GetTypes()
Exception calling "GetTypes" with "0" argument(s): "Unable to load one or more of the requested typ
es. Retrieve the LoaderExceptions property for more information."
At line:1 char:28
+ (Get-Assembly bdd).GetTypes( <<<< )
PoSH> (Get-Assembly bdd).GetExportedTypes() | select -First 5
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False PEManager System.Object
False True PEVersionEnum System.Enum
False True ComponentEnum System.Enum
False True StatusDelegate System.MulticastDelegate
False False StatusEventArgs System.EventArgs
PoSH>
Using PowerTab tabcompletion I found the GetExportedTypes() method so I tried to use that method instead and it did work
I changed GetTypes() into GetExportedTypes() also for the Update-TabExpansionTypes function so now all types get loaded this way I did not encounter this error before but for safety I changed it also as for powershell usage this might method might be better anyway (accessibility namespace gone for example )
So this was an easy fix again, but as the update-TabExpansionTypes does clear the types database first, and then does fill it again with the types of all the assembly's loaded in PowerShell at that moment, this is not always what you want as the database can contain types from assemblies that you added already and do not want to lose but that are not loaded in the current session.
Added Add-TabExpansionTypes function to add single Assembly to Tabcompletion
I noticed this already in version 0.8, but as I provided the Lib as examples to get users started ,I never updated it in the library as I did hope this would be a trigger for users to take a look a the scripts in the Library and to extend them, meanwhile learning about the workings and how to adapt the library.
I do use a couple of different TabExpansion Databases myself that I edited and that are tuned for different tasks, and after loading new types I merge in the new information myself also as the Tab Expansion database is not saved by default, the update-TabExpansion function will only affect the current session and as long as you do not run the Export-TabExpansion function the database on disk will not change so when you only need the extra type information and do not have the need to add the loaded namespaces to tabcompletion permanently, doing the complete refresh of the types database doesn't matter as you can only use the loaded assemblies anyway.
for the same reason I never added much parameters to the helper functions in the library, in spite of the fact that there are a lot of places where this would be easy and add much value, to keep the scripts as simple as possible.
but while troubleshooting the bug with reading the types from the BDD Assembly, Hence I quickly adapted the update-TabExpansion function to handle only one assembly, and created an Add-TabExpansionTypes function that provides a way to select a single Assembly and to add only that single assembly to the Tab Expansion database without a complete refresh of the current content.
As I made it anyway, for version 0.93 I also added the Add-TabExpansionTypes function to the script library, as it is created by copying the Update-Tabexpansion function, by just removing the loop and unneeded code till I had a working version for only one assembly it is very ugly code and still does a lot unneeded work, as the whole database is checked for namespaces without types, using a very ineffective method that I needed to change anyway, I made a much better way, but the current method was a quick fix I did make as I did not have the code handy and was in need of a quick fix, I did forget the specifics of what I did make before so I made a quick "anything that works", as while loading all Assemblies this was only a small part of the time used I never came to replacing it, but on the BDD Assembly only it is taking 90 % of the time that the script needs to run.
Still this is not a problem for PowerTab usage as it is not used that often, the extra time does not matter that much, but I will make a decent version for next version
Also I added the get-Assembly function I made in the Troubleshooting process to the library, that can be used to list loaded assemblies and to get a reference to the Assembly needed.
Expansion of methods and properties of static methods or properties
In PowerTab version 0.92 the variable method and property expansion was already multilevel but it did not work on static properties and methods that had properties and methods again themselves, I added tabcompletion for static methods but you could not use this multilevel, in the example of BDD to use tab completion on the OSManager object we needed to put it into a variable first
[Microsoft.BDD.ConfigManager.Manager]::OSManager
$osm = [Microsoft.BDD.ConfigManager.Manager]::OSManager
But now in PowerTab version 0.93 we can use tabcompletion again on the static property or method, and after that again multilevel as with a variable
[Microsoft.BDD.ConfigManager.Manager]::OSManager.GetDataTable()
[Microsoft.BDD.ConfigManager.Manager]::OSManager.GetDataTable().WriteXml('os.xml')
Also this did not work as you put the type itself into a variable, static Properties and methods where not supported on variables, I added this also (again quick and dirty by copying the complete code of the "normal" static method handler and then I just changed the regex.)
Now we can do things like this :
$bdd = [Microsoft.BDD.ConfigManager.Manager]
$bdd::OSManager
$bdd::OSManager.GetDataTable()
As I would never do this like this myself (I would start with object returned by the static method or property as I did in the first example with the OSmanager static property storing the Osmanager object in the $osm variable)
I did this to be complete in coverage, and make it possible for users that like this way of storing the type in a variable , to still use PowerTab tab completion.
call gettype if :: is used on object to get the type first
While testing I found that static completion on variables also can be confusing if you use it on a variable that does not contain a type but an object, you will get tabcompletion on the static members of the type but this will not work
PoSH> [string]::Join('',(1,2,3))
123
PoSH> $s = "123"
PoSH> $s::Join('',(1,2,3))
Method invocation failed because [System.String] doesn't contain a method named 'Join'.
At line:1 char:9
+ $s::Join( <<<< '',(1,2,3))
PoSH> $s = [string]
PoSH> $s::Join('',(1,2,3))
123
As static members need to be called on the type not on the object, the next line will work :
PoSH> $s.GetType()::Join('',(1,2,3))
123
that got me thinking and instead of just disabling the tabcompletion if the variable does not contain a type the getType() method is added to the completion so if the variable does not contain a type PowerTab will add the GetType automaticly, providing a shortcut to get to the type, if you do not like it you can change the if statement to return, and it will just not complete if it's not a type.
A Flash movie showing a good example of using PowerTab 0.93 with the Microsoft Solution Accelerator for Business Desktop Deployment 2007 managed DLL, to list all of the Operating Systems in BDD 2007 you can find here : PowerTab 0.93 and BDD 2007 teaser Part 2
Enjoy,
Greetings /\/\o\/\/