Generate Monkey Code Smartly with StudioShell

§ October 28, 2011 01:09 by beefarino |

There is no shortage of code generation techniques available in Visual Studio.  There are even some neat PowerShell solutions that are based on the DTE.  Let me show you an approach I’ve used a few times – it’s a fairly special case, but it’s one of those problems that requires a high volume of monkey code that I frankly don’t want to spend a lot of time on.  It also demonstrates a few automation techniques you may not have considered before – such as driving other Visual Studio extensions like ReSharper.  My hope is that it gives you some fodder for exploring your own creative automation solutions with StudioShell.

The scenario: I need to take a COM interface and wrap it in a .NET class.  Why?  Long story for another post, but it has to do with getting PowerShell format definitions working for said COM interfaces. 

imageFor example, I’ve recently been working on a PowerShell Provider around the Windows Task Scheduler.  The Task Scheduler API is COM-based and consists of a handful of about 40 interfaces that need wrapping to work in my provider framework.

My standard workflow to create one of these wrappers is fairly wrote at this point:

  1. Define the wrapper class in C#;
  2. Add a private field holding a reference to the COM interface;
  3. Initialize the field in the wrapper class constructor;
  4. Use ReSharper’s Generate Delegating Members code generation feature to recreate the COM interface implementation in C#.

Not hard, but lots of easy that needs to get done.  First I’ll show how I accomplish this manually, then at how StudioShell can take the pain out of this boring work…

Manual Workflow

Here is how I would implement the wrapper for the simple IAction interface in the Task Scheduler COM type library.  The COM interface is defined as follows in C# code:

1 public interface IAction 2 { 3 string Id 4 { 5 get; 6 set; 7 } 8 9 _TASK_ACTION_TYPE Type 10 { 11 get; 12 } 13 }

Step 1: Define the wrapper class in C#

The C# wrapper classes I create are usually named after the interfaces by replacing the “I” in the interface name with “Shell”.  So, IAction becomes “ShellAction” in implementation:

1 public class ShellAction 2 { 3 }

Step 2: Add a private field holding the COM reference

With a basic class structure in place, I add a private field holding the IAction reference:

1 using TaskScheduler; 2 3 public class ShellAction 4 { 5 IAction _item; 6 }

Step 3: Initialize the COM reference in the class constructor

The IAction _item field needs to be initialized in the class constructor:

1 public class ShellAction 2 { 3 IAction _item; 4 5 public ShellAction(IAction item) 6 { 7 _item = item; 8 } 9 }

And to be honest, I don’t write this code – I use ReSharper to generate it for me.  I hit [alt]-[insert] and ReSharper pops up a list of code generations it can perform on the class, and I select Generate Constructor, and it does the magic for me.

imageStep 4: Generate delegating members using ReSharper

Once the basic class and field code is in place, I turn again to my second-favorite Visual Studio extension.  ReSharper ships with a badass function called “Generate Delegating Members” that does exactly what the name implies – it can generate method and property calls that forward to a class member.

Using a dialog to allow me to select what members I want to create delegating calls for, and once I click Finish to run this little gem, the class is code complete:

1 public class ShellAction 2 { 3 IAction _item; 4 5 public ShellAction(IAction item) 6 { 7 _item = item; 8 } 9 10 public string Id 11 { 12 get { return _item.Id; } 13 set { _item.Id = value; } 14 } 15 16 public _TASK_ACTION_TYPE Type 17 { 18 get { return _item.Type; } 19 } 20 }

Rocket science it ain’t.  Still, I have about 39 more of these things to create.  Time to automate.  Heh.  Poetry.

Automated Workflow

In a nutshell, I want to use StudioShell to drive this four step process for each interface in the Task Scheduler type library.  So, the first thing I need is a list of every interface I can find in that type library.  This is pretty easy to do since PowerShell has access to the entire .NET underpinnings:

1 §> $t = [appdomain]::currentdomain.getassemblies()` 2 | where { $_.fullname -match 'tasksch' } ` 3 | %{ $_.gettypes() } ` 4 | where { ` 5 $_.isinterface -and $_.name -match 'i' ` 6 }


This pipeline looks complicated, but it’s pretty simple when you break it down.  In English, it reads as “From all loaded assemblies (line 1) whose fullname contains the string ‘tasksch’ (line 2) get the public types (line 3) that are interfaces and start with the letter ‘I’ (line 5).”  The goal is to get the public interfaces from the Task Scheduler type library.  The results are stored in the variable $t, which contains what we expect:

1 § >$t 2 3 IsPublic IsSerial Name 4 -------- -------- ---- 5 True False ITaskFolderCollection 6 True False ITaskFolder 7 True False IRegisteredTask 8 True False IRunningTask 9 ...

Cool.  Now we have the list of interfaces we need to wrap.  Let’s start hacking.

Step 1: Define the wrapper class in C# ( 40 times )

To keep things simple, I’m going to dump all of these generated classes into a single new code file.  I can always break them out later if I choose to.  I navigate StudioShell to the project I’m working in:

§ >cd DTE:\solution\projects\scheduledtasks

and create a new code file:

§ >new-item -type codefile -name test.cs

Then I navigate StudioShell into the code model for this new empty file:

§ >cd ./test.cs/codemodel

Time to bring the awesome.  I want a new public class for each interface in $t, and I want the class name to be the same of the interface with the initial 'I’ replaced with “Shell”:

§ >$t | foreach { new-item -type class ` -name ($_.name -replace '^I','Shell') ` -access public } Location: dte:\...\test.cs\codemodel File: test.cs Code Container: Available Operations: d+ < Kind Name ---- ---- vsCMElementClass ShellTaskFolderCollection vsCMElementClass ShellTaskFolder vsCMElementClass ShellRegisteredTask ...

Taking a quick peek at the code now in test.cs, it would seem I have my 40 classes declared:

public class ShellTaskFolderCollection { } public class ShellTaskFolder { } public class ShellRegisteredTask { } // ...

Step 2: Add a private field holding the COM reference ( 40 times )

Next item we need is the private COM reference in each class.  I can accomplish this using the standard new-item cmdlet to create private member variables inside of each class:

1 § >$t | foreach { ` 2 $c = $_.name -replace '^I','Shell'; ` 3 new-item -path $c ` 4 -name _item ` 5 -membertype $_.name ` 6 -type variable } 7 8 Location: dte:\...\test.cs\codemodel\ 9 File: test.cs 10 Code Container: Class ShellTaskFolderCollection 11 Available Operations: d+ < 12 13 14 Kind Name 15 ---- ---- 16 vsCMElementVariable _item 17 18 ...

For each interface in $t, I derive the class name using the same replace logic I used in step 1; I store this class name in the variable $c (line 2).  My current location is the code model for the test.cs file, so I can use this class name as a relative path to the new-item cmdlet to create class members.  In lines 3-6, I do just that to create a private field named “_item.”  The type of field _item is set to the name of the Task Scheduler interface being processed.

Huh, looking at the code file I can see I need to add a using statement to let the compiler resolve those TaskScheduler type library references; I’ll just do that by hand to get it done:

using TaskScheduler; public class ShellTaskFolderCollection { ITaskFolderCollection _item; } public class ShellTaskFolder { ITaskFolder _item; } public class ShellRegisteredTask { IRegisteredTask _item; } //...

So far so good.

Step 3: Initialize the COM reference in the class constructor ( 40 times )

Now things get interesting.  I need to add a constructor that initializes the value of the COM reference.  I used ReSharper to do this before, but there’s no way to automate ReSharper is there?  Um, yeah, there is.

All Visual Studio extensions (and Visual Studio itself) expose handles to their functionality in the form of Command objects.  StudioShell dutifully exposes these commands as part of the DTE: drive.  If we can find the command, we can pass it to the standard invoke-item cmdlet to make it run.

So let’s find the command.  Knowing that it’s a ReSharper command, and that it has something to do with generating constructors, I can narrow my search using intuition:

§ >ls dte:/commands | where {` $_.name -match 'resharper' ` -and ` $_.name -match 'constructor' } Location: dte:\commands Available Operations: d+ < Name ---- ReSharper.ReSharper_Constructor2FactoryMethodAction ReSharper_Generate_Constructor

Hmmm, I’m not a betting man, but I’d still put money that the ReSharper_Generate_Constructor command is the one I’m after.

Now, a little Visual Studio SDK sidebar – when a command executes, it uses the context of the current user activity.  In the case of this particular ReSharper command, it will only execute successfully if I’m currently in a code editor window working on a class.  Moreover, I need to move the cursor to the class I want the command to operate on.  Starting to sound like more trouble than its worth?

Fear not grasshopper – StudioShell has your back yet again!  One of the newer features of StudioShell is the ability to “navigate” to specific code model elements using the invoke-item cmdlet.  This is a recent feature that will be available in the upcoming 1.2 release.

So back on track, we want to invoke the ReSharper_Generate_Constructor command on each of our classes in test.cs.  So, that’s what we do:

1 § >ls -recurse | where {$_ -match 'class' } | foreach { 2 $_ |invoke-item; 3 invoke-item ` 4 dte:/commands/ReSharper_Generate_Constructor 5 }

imageLine 1 isolates the classes in test.cs; each class code item is first “invoked,” causing the containing document to activate and the cursor to move to the class code (line 2), then the ReSharper Generate Constructor command is invoked (lines 3-4). 

The result – the ReSharper Generate Constructor dialog is opened once for each class.  Unfortunately there is no way I know of to automatically select what members to initialize and then dismiss the dialog.  I’m sure there is, and I’d love to hear about it in the comments.  But right now I’d rather be more done than smart.  So, I hit [space]-[enter] 40 times like a schlep.

And the code looks right:

1 using TaskScheduler; 2 3 public class ShellTaskFolderCollection 4 { 5 ITaskFolderCollection _item; 6 7 public ShellTaskFolderCollection(ITaskFolderCollection item) 8 { 9 _item = item; 10 } 11 } 12 13 public class ShellTaskFolder 14 { 15 ITaskFolder _item; 16 17 public ShellTaskFolder(ITaskFolder item) 18 { 19 _item = item; 20 } 21 } 22 23 public class ShellRegisteredTask 24 { 25 IRegisteredTask _item; 26 27 public ShellRegisteredTask(IRegisteredTask item) 28 { 29 _item = item; 30 } 31 } 32 33 // ...

Step 4: Generate delegating members using ReSharper ( 40 times )

One last step and I’m done.  I need to run the ReSharper Generate Delegating Members command on each class.  This isn’t that different from what I had to do in step 3, and since I’ve taken the mystique out of automating ReSharper I know exactly what to do.

First, find the command.  I’ll use the same intuition that worked for me in step 3:

1 § >ls dte:/commands | where { ` 2 $_.name -match 'resharper' ` 3 -and ` 4 $_.name -match 'delegat' } 5 6 7 Location: PSDTE::dte:\commands 8 Available Operations: d+ < 9 10 Name 11 ---- 12 ReSharper_Generate_Delegating

Well lookey what we have here…  Hello there ReSharper_Generate_Delegating command!  Prepare to be automated!

This command works like the ReSharper_Generate_Constructor command – input focus has to be in a class code element in a text editor window.  But after solving step 3 this is no issue.  In fact, the solution for step 4 looks almost identical to step 3:

1 § >ls -recurse | where {$_ -match 'class' } | foreach { 2 $_ |invoke-item; 3 invoke-item ` 4 dte:/commands/ReSharper_Generate_Delegating 5 }

The only thing I had to change was the name of the command.

Again I get about 40 dialogs, one for each class, asking me what fields I want to create delegating members for, and as before I just type [space]-[enter] until the UIs disappear.

The code looks accurate:

1 using TaskScheduler; 2 3 public class ShellTaskFolderCollection 4 { 5 ITaskFolderCollection _item; 6 7 public ShellTaskFolderCollection(ITaskFolderCollection item) 8 { 9 _item = item; 10 } 11 12 public IEnumerator GetEnumerator() 13 { 14 return _item.GetEnumerator(); 15 } 16 17 public int Count 18 { 19 get { return _item.Count; } 20 } 21 22 public ITaskFolder this[object index] 23 { 24 get { return _item[index]; } 25 } 26 } 27 28 public class ShellTaskFolder 29 { 30 ITaskFolder _item; 31 32 public ShellTaskFolder(ITaskFolder item) 33 { 34 _item = item; 35 } 36 37 public ITaskFolder GetFolder(string Path) 38 { 39 return _item.GetFolder(Path); 40 } 41 42 public ITaskFolderCollection GetFolders(int flags) 43 { 44 return _item.GetFolders(flags); 45 } 46 47 // ... 48 } 49 50 public class ShellRegisteredTask 51 { 52 IRegisteredTask _item; 53 54 public ShellRegisteredTask(IRegisteredTask item) 55 { 56 _item = item; 57 } 58 59 public IRunningTask Run(object @params) 60 { 61 return _item.Run(@params); 62 } 63 64 public IRunningTask RunEx(object @params, int flags, int sessionID, string user) 65 { 66 return _item.RunEx(@params, flags, sessionID, user); 67 } 68 69 //... 70 } 71 72 // ...

 

… and it even builds (read: SHIP IT!!).  2500+ lines of monkey code created in 5 lines of powershell, all in all about 10 minutes of exploring. 

Hindsight

This little demo show some pretty powerful automation techniques – honestly I find the notion of automating other automation tools compelling.  A few things I’d like you to keep in mind as you explore your own automations:

  1. I’m automating my workflow, not my coding.  That is, my focus is on replicating the activities I do manually in Visual Studio to yield the code I want in the end.  In this case that means driving another automation tool.  I’m not looking for fancy or even “best practice” with this, I’m looking for done. 
  2. I’m not plotting a general solution I plan to reuse.  Sure I’ll employ some of the techniques again, but it’s actually easier (for me at least) to treat each new workflow as a new automation opportunity.  Moreover, trying to generalize this solution now would be a waste of time, since experience tells me that the next situation will be just different enough to force me to change my approach.
  3. I don’t focus on automation alone – that is, when I encounter a simple snag – such as the missing “using TaskScheduler;” statement in the code file, I just fix it by hand and move on instead of revisiting my automation technique to make it work perfectly.
  4. I’m automating something I’ve done manually several times.  So I have clear expectations of what needs doing and the path to follow.  My rule of thumb is not to automate until I can recite the steps I’ve taken before my memory.

Enjoy!



Automating Code Changes with StudioShell

§ October 3, 2011 04:27 by beefarino |

imageIn the last few talks I’ve given on PowerShell for Developers, I’ve focused on build, test, and code automation.  When discussing StudioShell, I’ve pulled a very effective demo from a real-life project…

After wrapping up an iteration with a client, they returned to me with a new 300,000-line code base spread over about 200 (very messy) files.  They were in the process of implementing a set of “corporate” coding standards and wanted some help getting their existing codebase to these standards.

One standard in particular was that and property that meets these criteria:

  1. is public
  2. returns a boolean

should start with “Is”.  So in this example code:

public class Demo 
{
   public bool Enabled { get;set; }
   public bool Valid { get;set; } 
   public bool IsRunning { get;set; } 
   public string Name { get;set; } 
   private bool Applied { get;set; } 
}

The properties Enabled and Valid need to be renamed to IsEnabled and IsValid (lines 3 & 4).  The IsRunning property already meets the standard (line5), the Name property returns a non-boolean type so the standard doesn’t apply (line 6), and the Applied property is private and excluded from the standard.  In the end this file needs to look as follows:

public class Demo 
{ 
   public bool IsEnabled { get;set; }
   public bool IsValid { get;set; } 
   public bool IsRunning { get;set; }
   public string Name { get;set; }
   private bool Applied { get;set; }
}

While it’s entirely possible to apply this standard by hand, the thought of scouring 300,000+ lines of code for properties that meet this criteria is not an attractive task.  FxCop can probably find these properties for us, but it can’t apply a fix – that still requires human intervention.  Best case scenario, I’m looking at days of mind-numbing monkey-on-a-keyboard work.

This is the kind of problem that screams for automation.  This is where StudioShell shines.  Here’s how I slashed through this Gordian knot…

First, I isolated a single code file in my StudioShell console, so I could work out the pipeline logic I needed without obliterating the codebase:

> cd DTE:\solution\codemodel\demoapp\program.cs

Second, I use PowerShell’s filtering capabilities to isolate all public properties in the file:

# spacing added for readability
> ls -recurse | where { 
     $_-match 'property' -and
     $_.access -match 'public' }

Location: dte:\solution\codemodel\demoapp\program... 
File: program.cs 
Code Container: Class Demo 
Available Operations: d+ < 
        Kind                         Name 
-----  ----                          --------- 
d+ < vsCMElementProperty Enabled 
d+ < vsCMElementProperty Valid 
d+ < vsCMElementProperty IsRunning 
d+ < vsCMElementProperty Name
Once I have all the properties isolated, I need to filter the properties to those that returning booleans.  This required a little investigation using get-member, but once I found the Type property of the CodeProperty class, I was home free:
 
#spacing added for readability
> ls -recurse | where { $_-match 'property' -and
    $_.access -match 'public' -and
    $_.type.asFullName -match 'bool' } 

Location: dte:\solution\codemodel\demoapp\program... 
File: program.cs 
Code Container: Class Demo 
Available Operations: d+ < 

        Kind                         Name 
        --------------              ---- 
d+ < vsCMElementProperty Enabled 
d+ < vsCMElementProperty Valid 
d+ < vsCMElementProperty IsRunning

The last factor to consider is the property name – I only need names that do not start with “Is”.  Easily done:

#spacing added for readability
> ls -recurse | where { $_-match 'property' -and
   $_.access -match 'public' -and
   $_.type.asFullName -match 'bool' -and
   $_.name -notmatch '^Is' } 

Location: dte:\solution\codemodel\demoapp\program... 
File: program.cs 
Code Container: Class Demo 
Available Operations: d+ < 
        Kind                         Name 
        -------------               ----- 
d+ < vsCMElementProperty Enabled 
d+ < vsCMElementProperty Valid
At this point, my pipeline is filtering out the correct properties – only public properties returning a boolean that do not start with “Is” are being included in the pipeline output.  The next step is to take corrective action against these offending property names.  The RenameSymbol method will execute the appropriate rename activity for me, ensuring that the new name is propagated across the entire codebase that is loaded in Visual Studio:
 
#spacing added for readability
> ls -recurse | where { $_-match 'property' -and
   $_.access -match 'public' -and
   $_.type.asFullName -match 'bool' } |
foreach { $_.RenameSymbol( "Is"+$_.Name ) } 

> ls 
Location: dte:\solution\codemodel\demoapp\program... 
File: program.cs 
Code Container: Class Demo 
Available Operations: d+ < 
        Kind                         Name 
        --------------              ---- 
d+ < vsCMElementProperty IsEnabled 
d+ < vsCMElementProperty IsValid 
d+ < vsCMElementProperty IsRunning 
d+ < vsCMElementProperty Name 
d+ < vsCMElementProperty Applied
Once I verified that this worked as expected, applying the changes across the entire code base was a trivial matter of changing the root of my recursive search to the root of the code base:
 
#spacing added for readability
> ls dte:/solution/codemodel -recurse | where { 
   $_-match 'property' -and
   $_.access -match 'public' -and
   $_.type.asFullName -match 'bool' 
} | foreach { $_.RenameSymbol( "Is"+$_.Name ) }

Done.  The total time it took me to complete the task across the 200+ files, including the necessary research, prototyping, and the full script execution: less than 30 minutes.  My input focus never moved from the StudioShell console, and my hands never left the keyboard (except when the script was running across the code base, during which time I helped my kids study their math facts).

This is why I made StudioShell – so I can scale iterative code and IDE solutions the same way an IT pro scales administrative solutions.  If a solution can be applied to a single line of your code, StudioShell can be apply it to all lines of your code.



Stupid PowerShell Tricks #1

§ September 20, 2011 07:01 by beefarino |

imageLast weekend I did two talks at SQL Saturday #89: one on StudioShell that seemed well-received, and another titled “Stupid PowerShell Tricks” that was basically an hour of laughter and learning.  Many thanks to the volunteers and sponsors, and to everyone who attended for all of their positive energy.

As I promised the attendees, this post will outline each of the techniques I demonstrated during “Stupid PowerShell Tricks.”  First though, some background…

What is a Stupid PowerShell Trick?

As I defined it in the session, a Stupid PowerShell Trick is any PowerShell element that has the potential to make your life or work easier.  These are not full solutions to exact problems, but rather small techniques you can employ in various situations.

The idea for the session came to me after going over some notes for previous PowerShell and StudioShell sessions.  I found that the most frequent and at times energetic question from the audience was:

What was that you just did there?

Most of the time this question was shouted in response to some shortcut I have built-in to my session instead of the main point of the presentation.  Turns out, I have more than enough of these little things to create a talk around them!

And the name?  It’s a derivative (read:ripoff) from David Letterman’s Stupid Human Tricks:

You may never need it, but if you ever need to stop a fan with your tongue, its empowering to know that you can.

So without further ado, here are the tricks I presented at SQL Saturday #89:

Trick #1: push-project

This is one of those personal work-habit shortcuts that integrates well with PowerShell.  I organize my work under a single Project folder in My Documents.  The name of each folder is typically the client for whom the work is being done, the name of an open-source project, etc.  This makes finding the project from the shell easy – I just navigate to the project folder and add the name of the project to the path:

1 # navigating to a project folder 2 PS> cd ~\documents\project\MyAwesomeProject

That’s an awful lot of typing though, and the only piece that changes is the name of the project.  So, I added a push-project function to my profile script that lets me navigate to these locations with less fuss and tabbing:

1 function push-project( $project ) 2 { 3 pushd ~/documents/project/$project; 4 } 5 6 New-Alias -Name pp -Value push-project;

In addition, an alias associates the shorter ‘pp’ to the push-project function, allowing me to navigate to a project with the much shorter:

1 PS> pp MyAwesomeProject

Yeah, like I said, the tricks are stupid.  But this saves me countless keystrokes a day and I move from client to client, project to project.

An Even More Stupider Trick

An audience member (can’t recall his name) had an awesome suggestion – assume $project is a pattern to match against the project names!  Turns out this no-brainer was easy as pie to pull off:

1 function push-project( $project ) 2 { 3 $path = "~/documents/project/$project" 4 if( -not( Test-Path $path ) ) 5 { 6 $path = ls ~/documents/project ` 7 -Filter "$project*" | select -First 1 ; 8 } 9 pushd $path; 10 }

Line 3 defines a full project path string using the input from the user in the $project variable.  Line 4 tests whether this path exists; if the path does not exist, it is assumed that the project name is incomplete, and lines 6-7 search the project tree for the first matching project name.  Line 9 completes the function by pushing the full project path onto the location stack.  In the end, getting to my projects has never been so tight:

1 PS> pp my

Trick #2: invoke-item

This next trick is a PowerShell gimmie – it’s built right in to the default session configuration.

There may be times when you want to open a text file, word doc, spreadsheet, etc from the console.  You can always invoke the program directly:

1 PS> excel supersecretdata.xls 2 PS> word supersecretdata.doc 3 PS> notepad supersecretdata.txt

But then you have to know what program to run; e.g., you can’t open a spreadsheet in notepad and expect to be able to read it.  So why not let PowerShell figure it out for you – use the invoke-item cmdlet to invoke the default shell action for a given file:

1 PS> invoke-item supersecretdata.xls 2 PS> invoke-item supersecretdata.doc 3 PS> invoke-item supersecretdata.txt

The example above will open each file in the appropriate application.  No fuss no muss.

“But Jim,” you say, “that’s a lot of typing!  Oh how I wish there was some way to accomplish this without all those keystrokes!”

Fear not PowerShell trickster!  There is an alias you can use:

1 PS> ii supersecretdata.txt

One of the more useful cases for this trick is when I want to open explorer at my current location in the shell.  Easily done:

1 PS> ii .

This takes advantage of the fact that the default action for a folder in Windows is to display it in explorer.  The dot in the command represents the “current path location,” which is always a folder.

Trick #3: PowerShell Here

imageThis one plays compliment to the previous trick.  Sometimes I need a PowerShell prompt open in the folder I’m looking at in explorer.  For that I use the PowerShell Here registry hack from Scott Hanselman’s blog.

This hack adds a PowerShell Prompt Here entry into the context menu for file folders.  Clicking the menu item will, as you’d expect, crack open a new PowerShell console that is pre-navigated to the correct folder. 

Super-handy to have when you need it.

Trick #4: Use VIM

imageVIM is a super-handy text editor that can run inside of your PowerShell console session.  Wait, let’s go over that again: it’s a text editor that runs inside of your PowerShell console.

VIM’s been around for … well, forever basically, in one form or another.  It’s a cross-platform port of the Unix VI tool, and it works the same in Windows, Linux, MacOS, you name it.

Mind you, I’m not at the point where VIM is my editor of choice – but when I need to make a quick edit to a file while I’m working in the shell it’s sooOOOoooo much faster to jump in and out of VIM than it is to bounce from the shell to notepad or PowerGUI and back to the console again.  My hands stay on the keyboard, which reduces the chance of my RSI coming back.

Now, VIM’s no picnic, but the juice is well worth the squeeze.  I highly recommend bookmarking the VIM docs, printing out some cheat sheets and jumping in.

Trick #5: clip

These last three tricks all have to do with pushing data someplace.

The first trick uses a built-in windows application named clip.exe to move data from PowerShell to any other application through the clipboard.  Very handy little trick:

1 PS> ls | clip

This example copies the list of files and folders in the current directory to the clipboard.  You can paste the list in any program – notepad, word, email, etc.

Of course you’re not limited to file lists – perhaps you need to add a list of event log entries in an email to some vendor support engineer:

1 PS> get-eventlog application -newest 20 | clip

Or maybe you need to copy the contents of a file:

1 PS> get-content myapplog.txt | clip

Or a list of every PowerShell variable name and value:

1 PS> dir variable: | clip

Or… oh whatever, you get the point.

Trick #6: out-gridview

Another trick to get data out of the console…

There is a handy built-in PowerShell command called out-gridview.  PowerShell n00bs tend to really like this command because it produces a UI – specifically a nice WPF grid displaying whatever data you pipe it.

Rather than show you what this does, I’d rather you play with it for yourself – take the examples from Trick #5 and replace “clip” with “out-gridview” and see what happens.

This one is really great when you want some data to hang around while you execute other commands.  The console is awesome, but the output doesn’t stick around too long. 

Trick #7: out-voice

And finally, the piece de resistance, the coup de gras, the penultimate of the first round of Stupid PowerShell Tricks – I present to you in all its glory … out-voice.

A few months back @shaylevy posted a little gem that demonstrated the use of the Microsoft Speech API from PowerShell.  I’ve already blogged a bit about it, and how using PowerShell to explore new APIs is both fun and rewarding.  This trick is basically an extension of that tweet from Shay.

One day I was working on a rather convoluted build while trying to help my daughter with some math facts.  The build took a long time to run - I wanted to give my little girl the full attention she deserved, but I also needed to get this build out.  So I rigged up a way for the computer to tell me when the build was completed.  This way, I can ignore my computer the way my daughter deserves, and still know exactly when the build has completed.

I added this code to my profile script:

1 $voice = New-Object -ComObject SAPI.SPVoice 2 $voice.Rate = -3 3 4 function invoke-speech 5 { 6 param([Parameter(ValueFromPipeline=$true)][string] $say ) 7 8 process 9 { 10 $voice.Speak($say) | out-null; 11 } 12 } 13 14 new-alias -name out-voice -value invoke-speech;

The $voice variable is set to a Speech API COM object in line 1.  Line 4 defines a function named invoke-speech; the param statement on line 6 and the process block on lines 8-11 allow this function to receive pipeline input.  The magic happens on line 10, where the input passed to the function is sent to the speech API for processing.  Line 14 aliases the command out-voice to the new function.

So how did this help me know the build was done?  Easy!  Add the above code to your session and try this:

1 PS> 'Hey beef, the build is done!' | out-voice

This is a great trick ignoring your computer during long-running processes:

1 # pretend this is a long-running process 2 sleep -seconds 5 3 "all done!" | out-voice

And, as the audience pointed out, the potential for abuse is significant.  Next time you leave for lunch, run this little quip, replacing my name with the name of your least-favorite coworker:

1 PS> while(1) { 2 sleep -seconds (get-random -min 90 -max 500); 3 'Jim, I need you over here now' | out-voice; 4 }

The ideas grow unbound from this point.  Read a file:

1 get-content myfile.txt | out-voice

Read the event log:

1 get-eventlog -log application | out-voice

… and so forth.

Conclusions

Stupid?  Maybe.

Useful?  Certainly.

Fun?  Oh yeah.  I highly anticipate you blogging on your own Stupid PowerShell Tricks; send me a link through the contact form or add a comment with a link to your blog!



Summer (and Fall) of Speaking

§ September 12, 2011 03:10 by beefarino |

SOOOOoooooOOOO… I’ve been a bit incognito lately and I thought I’d take a moment to summarize what’s been happening in the last three months,and give everyone a head’s up for the rest of the year.

May was consumed largely by two things.  The first was volunteer work at my kids’ school during EOG testing.  I was basically there for 5 hours every day for three weeks, so the teachers could administer 4 exams for each of their 24 students one-on-one as mandated by the school board.  I couldn’t stop the testing, but I did what I could to ease the pain on the school, teachers, and kids.  The second thing was prepping talks for the summer conferences – CodeStock, MADExpo, and DEVlink – and various code camps in the Carolinas and Georgia.  I headed out to CodeStock at the end of May, where I spoke about StudioShell; it was another fantastic conference experience, the highlight for me was getting to kick Charles Petzold out of the room so I could give my talk immediately after his.  I mean, freaking Charles Petzold.

June was full of CodeStock and MADExpo.  MADExpo went off rather well for a first-time conference.  The maker-esque focus is something I hope they elaborate upon next year – the sessions on netduino, robotics, and the like were a real hit across the board, and the kid’s area was a blast with snap circuits, legos, etc.  I’m considering submitting an origami session next summer, just to do something completely different…

July was comprised of work, work, work … and a vacation in the east Texas desert, during which I managed to line up a substantial contract that consumed most of August … except of course for DEVlink.  This was my first DEVlink experience and it was a good one (despite the lack of wireless and cell coverage and no, I didn’t stay at the Choo-Choo either).  I definitely made more connections – social and professional – at DEVlink than at any other conference thus far.  I did another StudioShell session there.  Jaws hit the floor, it was well-received.  I also attended PowerShell sessions by other speakers –  Sarah Dutkiewicz and Joe Webb – I love seeing how different people approach teaching this technology to others.

With the summer over and school back in session, my speaking focus is shifting back to user groups and events.  This Thursday, September 15, I’ll be speaking at the WNC .NET User Group about PowerShell for Developers.  I’ve expanded this talk to include PSake, Pester, and StudioShell; I look forward to the feedback on the new topics.

Then on Saturday, September 17th, it’s SQL Saturday #89 in Atlanta.  This will be my first SQL Saturday ever, and I’m so glad to be bringing the PowerShell and development love to the database community.  I have two sessions – the first is using StudioShell to automate Denali, and the second is a brand-spankin’ new talk titled “Stupid PowerShell Tricks”.  I got the idea from going over some of my other talks and realizing that the most frequent question I get asked is “What was that you just did there?”  I also find myself asking this question quite a bit of others – especially when I’m around admins or DBAs.  Since there is obviously much we can learn from each other, I decided to make a session out of it.  I’ll show you my stupid tricks and you show me yours, and we’ll all walk away with new ways to get stuff done!

Later this month – September 22nd to be exact - I’m heading to the Triad Developer’s Group to spread more PowerShell love to Carolina software developers.  In October it looks like I’ll be a guest on Talk TechNet (details to follow).  In November I’m heading up to the Raleigh .NET User Group to demo and discuss StudioShell.

Whew… at some point I’ll need to fit in some project work… I’ve got a couple of decent irons in the fire, some will go open-source and some won’t … more on that in another post…