PowerShell Cookbook

Search

Categories

 

On this page

Set-Location, and [Environment]::CurrentDirectory
PowerShell Solves a Mystery
How Do I Search the Registry for a Value in PowerShell?
“Simple Where” as a Where-Object Shortcut
Current Working Directory with PowerShell and .Net Calls
Precision Computing Turns One
Caffe Artigiano in Vancouver
SecureStrings in PowerShell
How do I learn the Dvorak keyboard layout?
Shortcut to Select the Next Edit Box in Internet Explorer

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: 218
This Year: 18
This Month: 0
This Week: 0
Comments: 529

Sign In

 Tuesday, July 18, 2006
Tuesday, July 18, 2006 11:55:01 PM (Pacific Daylight Time, UTC-07:00) ( )

One question that comes up frequently is, “Why does PowerShell not change its [System.Environment]::CurrentDirectory as I navigate around the shell?

One of the difficult aspects of this comes from the fact that PowerShell supports multiple pipelines of execution.  Although it’s not directly exposed yet, users will soon be able to suspend jobs to the background, and other concurrent tasks.

The current directory affects the entire process, so if we change the directory as you navigate around the shell, you risk corrupting the environment of jobs you have running in the background.

When you use filenames in .Net methods, the best practice is to use fully-qualified path names.  The Resolve-Path cmdlet makes this easy:

[C:\temp]
PS:37 > $reader = new-object System.Xml.XmlTextReader (Resolve-Path baseline.xml)
Suggestion: An alias for Resolve-Path is rvpa

[C:\temp]
PS:38 > $reader.BaseURI
file:///C:/temp/baseline.xml

If you wish to access a path that doesn’t already exist, use the Join-Path  cmdlet:

(Join-Path (Get-Location) newfile.txt)

Comments [1] | | # 
 Monday, July 17, 2006
Monday, July 17, 2006 5:20:54 PM (Pacific Daylight Time, UTC-07:00) ( )

One of Raymond Chen’s readers recently noticed that Google purchased AdWords for Raymond’s name.  The destination of the sponsored link?  http://www.google.com/jobs :)

This came up on our internal bloggers alias, so people started poking around to see what other bloggers / blog readership had outstanding “job offers.”  Not being one for repetitive, manual computer labour, I let PowerShell definitively answer the question.

In a temporary Outlook message, I expanded the alias so that it listed the names of all members.  I saved that into a text file, and ran the following script:

[C:\temp]
PS:6 > gc bloggers.txt -delimiter ";" |
>>    % { $_ | where { $wc.DownloadString("
http://www.google.com/search?q={0}" -f $_) -match "Want to work" } }
>>
 Brad Abrams;
 Eric Gunnerson;
 Raymond Chen;

A bit easier than searching for the 965 members of that alias by hand!

Comments [1] | | # 
 Wednesday, July 12, 2006
Wednesday, July 12, 2006 11:29:39 PM (Pacific Daylight Time, UTC-07:00) ( )

The question came up recently in an internal discussion list, “How do I search the Registry for a value in PowerShell?

In the FileSystem, we have the select-string cmdlet to do the hard work for you.  We don’t have the equivalent yet for other stores, so unfortunately the answer is to write ‘grep’ from scratch.  It’s manageable, though.

The key here is to think of registry key values like you would think of content in a file:

Directories have items, items have content.
Registry keys have properties, properties have values.

The way to get property values in PowerShell is the Get-ItemProperty cmdlet.

So:

cd HKCU:
Get-ChildItem . –rec –ea SilentlyContinue

Gets you all of the subkeys in the registry, just like you might get all of the files on your hard drive.  We then pass that into the “Get-ItemPropery” cmdlet, to get the content of the properties:

| foreach { Get-ItemProperty –Path $_.PsPath }

To check for matches, we use the –match operator:

... (Get-ItemProperty -Path $_.PsPath) -match "evr.dll"

But that just outputs a bunch of “Yes” and “No” answers.  We in fact want to output the key name if this matches, so we wrap that in an If statement and output the path:

... if( (Get-ItemProperty -Path $_.PsPath) -match "evr.dll") { $_.PsPath }


That gives us a script-like representation of:

######################################################################
##
## Search-RegistryKeyValues.ps1
## Search the registry keys from the current location and down for a
## given key value.
##
######################################################################

param([string] $searchText = $(throw "Please specify text to search for."))

gci . -rec -ea SilentlyContinue | 
   % { 
      if((get-itemproperty -Path $_.PsPath) -match $searchText)
      { 
         $_.PsPath
      } 
   } 

 

Or a “one-liner of”: 

gci . -rec -ea SilentlyContinue | % { if((get-itemproperty -Path $_.PsPath) -match "<SomeText>") { $_.PsPath} }

Comments [0] | | # 
 Wednesday, July 05, 2006
Wednesday, July 05, 2006 11:23:36 PM (Pacific Daylight Time, UTC-07:00) ( )

The Where-Object cmdlet is incredibly powerful, in that it allows you to filter your output based on arbitrary criteria.  For extremely simple filters (such as filtering based only on a comparison to a single property,) though the syntax can get a little ungainly:

get-process | where { $_.Handles -gt 1000 }

For this type of situation, it is easy to write a function to offload all of the syntax  to the function itself:

get-process | wheres Handles gt 1000
dir | wheres PsIsContainer

The following snippet implements the “simple where” functionality:

function wheres($property, $operator = "eq", $matchText = "$true")
{
   Begin { $expression = "`$_.$property -$operator `"$matchText`"" }
   Process { if(invoke-expression $expression) { $_ } }
}

Much better!

Note: although extremely simple, this solution can be improved.   Since we pass arbitrary input to the Invoke-Expression cmdlet, it is quite easy to make syntactic mistakes that foul up the call to Invoke-Expression.  Also, this function can be abused if you don’t fully trust the input that you pass it:

dir | wheres PsIsContainer eq 'False" -and (write-host "Hello") -and "'

Bruce Payette expands on this function (and problem) in his upcoming book, “PowerShell in Action.”

Comments [1] | | # 
 Monday, June 26, 2006
Monday, June 26, 2006 8:41:30 PM (Pacific Daylight Time, UTC-07:00) ( )

A question that occasionally comes up is, “Why doesn’t PowerShell change the [Environment]::CurrentDirectory while I navigate around the shell?”  This is always in the context of using a relative file path while working with the .Net framework.

One of the difficult aspects of this comes from the fact that PowerShell supports multiple pipelines of execution.  Although it’s not directly exposed yet, users will soon be able to suspend jobs to the background, and other concurrent tasks.

The current directory affects the entire process, so if we change the directory as you navigate around the shell, you risk corrupting the environment of jobs you have running in the background.

When you use filenames in .Net methods, the best practice is to use fully-qualified path names.  The Resolve-Path cmdlet makes this easy:

[C:\temp]
PS:37 > $reader = new-object System.Xml.XmlTextReader baseline.xml

[C:\temp]
PS:38 > $reader.BaseURI
file:///C:/Documents and Settings/<user>/baseline.xml

[C:\temp]
PS:37 > $reader = new-object System.Xml.XmlTextReader (resolve-path baseline.xml)

[C:\temp]
PS:38 > $reader.BaseURI
file:///C:/temp/baseline.xml

 

Comments [2] | | # 
 Thursday, June 08, 2006
Thursday, June 08, 2006 3:48:37 PM (Pacific Daylight Time, UTC-07:00) ( )

It was a year ago now that Precision Computing, in its current form, opened its doors.  I’ve been writing something blog-like for longer, but it previously involved updating the HTML by hand :)

It’s been an interesting year – one in which we’ve seen the PowerShell community blossom from a group of passionate BetaPlace users, to a much larger and more diverse community.  We’ve played with a handful of new releases, experienced a long-awaited name change,  and perhaps most importantly – learned about PowerShell’s official release plans.

At Microsoft, we have a tradition for celebrating times like this.  When their anniversary rolls around, many people place chocolate on a chair outside of their office – usually 1 lb. for every year they’ve been at Microsoft.  It’s a great tradition – the people you work with get to indulge a little, and everybody enjoys the water cooler type of conversation that tends  to happen.

I obviously can’t distribute chocolate on the internet, but I’ve been thinking for a while about how to recreate the essence of the Microsoft chocolate tradition.  Here’s the idea:

If you own a blog, add a comment with a link to what you consider your "best" post in the last year or so.  If you don’t own a blog, add a comment with a link to a blog post that you consider to be very insightful or interesting.  Then, click around and enjoy the water cooler conversation!

Now, on for another year!

Comments [7] | | # 
 Tuesday, June 06, 2006
Tuesday, June 06, 2006 4:36:55 PM (Pacific Daylight Time, UTC-07:00) ( )

On a recent trip to Vancouver, I accidentally stumbled into a cafe called Caffe Artigiano right downtown (on Hornsby street,) and was extremely impressed.  The walls are decorated with pictures of gorgeous Latte art, and the drinks are stellar.  It turns out that the place is the home of the Canadian Barista Champion for three years running!

And with drinks like this?  It makes me want to go back to working for a coffee shop :)

 


Picture taken from their blog @ http://www.dwelltime.net/, although mine looked similar!

Comments [2] | | # 
 Thursday, June 01, 2006
Thursday, June 01, 2006 6:17:47 PM (Pacific Daylight Time, UTC-07:00) ( )

When you use any string in the CLR, it retains that string so that it can efficiently reuse it later.  Unlike most.Net data, unused strings persist even through garbage collection cycles.  While this data is in memory, there is always the chance that it could get captured in a crash dump, or swapped to disk in a paging operation. Because some data (such as passwords, and other confidential information) may be sensitive, the .Net framework includes the SecureString class – a container for text data that the CLR stores in memory in an encrypted form.  Code that needs to interact with the plain text data inside of a SecureString does so as securely as possible.

When a cmdlet author asks you for sensitive data (i.e.: a password,) the best practice is to designate that password parameter as a SecureString in order to help keep your password confidential.   You can supply the parameter with a SecureString variable as input, or the host prompts you for the SecureString if you do not provide one.  We also have two cmdlets (ConvertTo-SecureString and ConvertFrom-SecureString) that allow you to round-trip this data to disk in a secure fashion.

By default, the SecureString cmlets use Windows’ Data Protection API when they convert your SecureString to and from a plain text representation.  The encryption key is based on your Windows logon credentials, so only you can decrypt the data that you’ve encrypted.  If you want the exported data to work on another system or separate user account, you can use the parameter sets that let you provide an explicit key.  PowerShell treats the data as an opaque blob – and so should you.

However, there are many instances when you may want to automatically provide the SecureString input to a cmdlet, rather than have the host prompt you for it.  In these situations, the ideal solution is to import a previously exported SecureString from disk (using ConvertTo-SecureString.)  This retains the confidentiality of your data, and still allows you to automate the input. 

If the data is highly dynamic (ie: coming from a CSV,) then the best approach is

$secureString = ConvertTo-SecureString "Kinda Secret" -AsPlainText –Force

The Cmdlet requires the Force parameter to ensure you acknowledge the fact that PowerShell cannot protect plain text data – even after you’ve put it in a SecureString.

The new –AsPlainText parameter set doesn’t exist in RC1, so the equivalent function is:

function New-SecureString([string] $plainText)
{
   $secureString = new-object System.Security.SecureString

   foreach($char in $plainText.ToCharArray())
   {
      $secureString.AppendChar($char)
   }

   $secureString
}

[Edit: Fixed typo]

Comments [3] | | # 
 Tuesday, May 23, 2006
Wednesday, May 24, 2006 6:59:46 AM (Pacific Daylight Time, UTC-07:00) ( )

Well, it looks like Scott had to go and drum us Dvorak nuts out of the ground.  It brought up a good question, though -- how do you go about learning the Dvorak keyboard layout?

The Dvorak keyboard layout, for those that do not know, was designed from the start to be maximally efficient.  It places the most common letters on the home row, and arranges the letters to maximize both the balance and alternation between hands while typing.  There are some that disagree with its effectiveness, but those looking to learn Dvorak typically aren't part of that crowd.

Advanced touch-typists (i.e.: > 60 wpm) don't typically notice much of a speed improvement in moving to the Dvorak keyboard layout, but the improved ergonomics are very noticeable.  If you don’t already touch-type (or do so slowly,) then you’ll gain significant benefits from learning the keyboard layout.

I’ve been using the Dvorak layout for about 7 or 8 years, so I thought I’d offer my advice.

One of the mistakes that many people make when learning Dvorak is to rearrange the keys on their QWERTY keyboard.  Not surprisingly, hunt-and-peck Dvorak isn’t much better than hunt-and-peck QWERTY.  The best approach, in my opinion, is to ensure that your hands learn the keyboard layout independently from your eyes.  If you glance down at the keyboard once in awhile to find a key, you will impede your touch typing skill.

Another mistake that many people make is to switch their machines at work first.  This creates an unhealthy sense of urgency (as your typing productivity temporarily plunges,) and brings with it a needless amount of stress.  Instead, I suggest using Dvorak at home (for things like your email, blog posts, etc) until your typing speed gets up to about 30 WPM.

With that in mind, this is how I taught myself the Dvorak keyboard layout:

Day 1

  1. Benchmark your current QWERTY typing speed at a site such as http://www.typingtest.com.  Do a good number of these tests so you can be confident in the measurement.  Dvorak is so much more ergonomic that you will likely feel like you are typing slower – even once you regain your original typing speed.
  2. Print off the above diagram of the keyboard, and fold it / cut it / whatever so that you can prop it against the bottom of your monitor.  Prop it against the bottom of your monitor.
  3. At home, change your keyboard layout to Dvorak, using the tools most probably built into your operating system.  By default, Windows also configures a shortcut (Control-Shift) to switch between layouts.  I disable this as it tends to interfere with using the keyboard to select text. 


  4. Log off, and log back in.  A keyboard layout change doesn’t affect currently running programs, so this gets you back to a fresh state.
  5. Open Notepad, and familiarize yourself with the keyboard layout.  Starting with your hands on the home row, go through the entire alphabet several times.  Don’t look at your fingers, but instead look at the keyboard chart.  When you make a mistake, look at the chart to see what key you pressed, and which one you should have pressed.
  6. While still in Notepad, try some other sentences, like “The quick brown fox jumped over the lazy dog.”
  7. Respond to / write some email, blog, and take part in other typing tasks. 
  8. Don’t push steps 5 / 6 / 7 past ~ 2 hours, or your return on investment will be pretty low.
  9. Sleep, and let your mind study Dvorak while you rest.

Day 2

  1. Repeat steps 5, 6, and 7, again stopping after about 2 hours.   At this point, you’re getting close to touch-typing Dvorak, but just very slowly.
  2. Check your current typing speed at the same site you used on Day 1.

Day 3 and on

  1. Keep using your home computer the way you would normally.
  2. Keep checking your typing speed.
  3. When you get to about 30 wpm, change the keyboard layout of your work machine as well.  At this point, you will quickly regain your previous typing speed.

Month 1 or 2 (and occasionally afterwards)

  1. Print out a QWERTY keyboard layout, and change all of your computers back to QWERTY. Touch type in this layout again for awhile to ensure that your skill doesn’t erode.


Caveats:

  • Some programs (such as Emacs and VI) use hotkeys so heavily that you remember them through muscle memory, and not by their individual characters.  This muscle memory becomes a slight hindrance when you learn the program in a new keyboard layout.  In addition, programs that use positional hotkeys (like cursor movement in VI) become slightly annoying to use as the keys are now scattered around the keyboard.
  • Typing with one hand (while you hold the phone with the other / etc) becomes nearly impossible.  You know only how to touch type – so the left hand has no idea what characters sit on the right hand side of the keyboard!
  • Password changes are sometimes perilous.  Be very sure which keyboard layout is active when you change your password.  It is quite difficult to figure out your effective password when you typed it in Dvorak– only to find out that the boot sequence actually recorded it in QWERTY.
  • Coworkers that attempt to use your keyboard will think you are a helpless geek, if they don’t already.

For more good resources on the Dvorak keyboard layout, check out Marcus Brooks' site, or the rest of the internet.  Good luck!


 

Comments [1] | | # 
 Monday, May 15, 2006
Tuesday, May 16, 2006 6:15:42 AM (Pacific Daylight Time, UTC-07:00) ( )

One of my pet peeves with Internet Explorer comes as I read a site or navigate the internet with the keyboard – but then have to use the mouse to click on a single, isolated edit box.  One solution is to use the ‘Tab’ key until I reach the edit box, but a page full of links can often require 50 or more presses of the ‘Tab’ key to get the edit box.

Here’s a perfect example.  You go to your search engine of choice (Win+R, www.ouhn.net or www.sfjl.net) and type in a query.  The query doesn’t give you the approximate results you hope for, so you press ‘Tab’ 15 times to get back to the edit box.

Here’s a solution that accomplishes that much more efficiently.  It has a lot of moving parts, but definitely works:

The Javascript Bookmarklet.  Bookmarklets are small snippets of Javascript that execute from your browser’s address bar.  For example, try the following in your address bar:

  • javascript:alert("hello world")
  • javascript:void(document.bgColor="#CCFFCC")

They are great, because they let you inject script into the page itself – giving you access to the content, DOM, and much more.  As far as I know, the concept originates from http://www.bookmarklets.com in 1998.  Think of them as the limited-length precursor to Firefox’s GreaseMonkey scripts.

Bookmarklets are usually published on a page as a simple Javascript link.  Rather than click it, you drag the link up to the “Links” section of your address bar.  After you accept the warning that the link may be unsafe, you can then click on the link in your “Links” bar to invoke whatever functionality the Bookmarklet surfaces.  That forms the core of the solution.

To solve the problem, we use two bookmarklets: one to set the focus to the previous editable DOM element, and one to set the focus to the next editable DOM element.  Drag the URLs below to your ‘Links’ bar in Internet Explorer to let you use these buttons to quickly focus the next text box. 

[Prev]
Content: javascript:var d = document; var e = d.all; var fc  = false; var c = e.length - 1; while(! (fc && e[c].isContentEditable)) { if(e[c].uniqueID == d.activeElement.uniqueID) if(fc) { break; } else { fc = true; } c = (c + e.length - 1) % e.length } e[c].focus()

[Next]
Content: javascript:var d = document; var e = d.all; var fc  = false; var c = 0; while(! (fc && e[c].isContentEditable)) { if(e[c].uniqueID == d.activeElement.uniqueID) if(fc) { break; } else { fc = true; } c = (c + 1) % e.length } e[c].focus()

 

 

In short, these links cycle through every element of the DOM, stopping at the first one before or after your “current” element.

The Hotkey.  We haven’t actually solved the problem yet, as you still have to click on the link button to have it focus the next edit box.  To solve that problem, use a Hotkey / Macro program that automates your keystrokes.

Since these are the only two links in my “Links” bar, I can access the “Previous” button with the following sequence of keystrokes:

  1. F10 to open the menu bar
  2. ‘A’ to open the favourites menu
  3. ‘L’ [ENTER] to open the links submenu
  4. ‘P’ to select the ‘Prev’ saved link.
  5. ALT to get the cursor out of the menu bar

To access the ‘Next’ saved link, I use ‘N’ instead in step d.

To actually automate these keystrokes, I use a program called AutoHotkey.  When I’m in Internet Explorer, I have AutoHotkey map Control+Alt+N to the the keystroke sequence for the ‘Next’ link, and Control+Alt+P to the ‘Prev’ link.

Here is its configuration script:

;;
;; Next text box in IE
;;
#IfWinActive, ahk_class IEFrame
^!n::Send {F10}al{ENTER}n{ALT}
#IfWinActive

;;
;; Previous text box in IE
;;
#IfWinActive, ahk_class IEFrame
^!p::Send {F10}al{ENTER}p{ALT}
#IfWinActive

Works like a charm.

Comments [1] | | #