Prof. Powershell

Where Shell We Begin?

Customize graphical elements of the user's desktop via the Shell.Application COM object. Yes, it can be done through PowerShell.

Back in the day, when VBScript was the admin scripting tool of choice, many an administrator took advantage of the Shell.Application COM object. This object offered some handy hooks into the graphical elements of a user's desktop. PowerShell can also take advantage of that object, which means you can add graphical features to your command-line scripts.

To begin with we need to create an instance of the Shell.Application object using the New-Object cmdlet:

$shell=new-object -com "shell.application"

I'll let you pipe this to Get-Member to whet your appetite. Instead, I want to use this object to present a graphical interface so a user can select a folder. From the console the only tool we have to take user input interactively is the Read-Host cmdlet. But then the user would have to type the name correctly and we'd need validation code to verify the folder exists. A graphical folder picker would be nicer so we'll use the shell object's BrowseForFolder() method.

At a minimum you should specify a handle, 0 will suffice, a window title and an options value. Again, 0 will suffice:

$fldr=$shell.BrowseForFolder(0,"Select a Folder",0)

You can also add a parameter to indicate a starting root:

$fldr=$shell.BrowseForFolder(0,"Select a Folder",0,"c:\")

What gets a little tricky is working with the result because it is a COM object:

PS S:\> $fldr

Title                      : backup
Application                : System.__ComObject
Parent                     :
ParentFolder               : System.__ComObject
Self                       : System.__ComObject
OfflineStatus              :
HaveToShowWebViewBarricade : False
ShowWebViewBarricade       : False

What I need is a path that can be used elsewhere. The “trick” is to grab the SELF property:

PS S:\> $fldr.self

Application  : System.__ComObject
Parent       : System.__ComObject
Name         : backup
Path         : C:\backup
GetLink      :
GetFolder    : System.__ComObject
IsLink       : False
IsFolder     : True
IsFileSystem : True
IsBrowsable  : False
ModifyDate   : 12/19/2010 7:03:14 PM
Size         : 0
Type         : File folder

This property is a nested object with its own set of properties. But I can easily get the path now:

PS S:\> $fldr.self.path
C:\backup

Here's a short demonstration script that prompts the user to browse for a folder then writes a custom object to the pipeline with the number of files, the average file size and a few other goodies:

$shell=new-object -com "shell.application"
$fldr=$shell.BrowseForFolder(0,"Select a Folder to Analyze",0,"c:\")
$path=$fldr.self.path
write-host "Examining $path" -ForegroundColor Green
#filter out folders so that only files are measured
$stats=dir -Path $path -Recurse | where {-not $_.PSIsContainer} |
   Measure-Object -Property Length -sum -max -average
#write a custom object
New-Object -TypeName PSObject -Property @{
   Path=$path
   FileCount=$stats.count
   AverageSize=$stats.average
   TotalSize=$stats.Sum
  LargestFile=$stats.maximum
}

As great as you think this might be, there is one cosmetic drawback when run on x64 platforms: The BrowseForFolder() method writes event information to the console when you browse for a folder. When you run the script in the PowerShell console you'll see messages like these:

start request
signaling finishcondition
start request
signaling finishcondition
start request
signaling finishcondition

You don't see the messages when running the script in the ISE or other editor like PowerGUI or SAPIEN's PrimalScript. I also found there are no messages when run in an x86 PowerShell session on a 64-bit operating system. The script and shell object work in all cases. It's just a matter of the ugly event messages.

About the Author

Jeffery Hicks is an IT veteran with over 25 years of experience, much of it spent as an IT infrastructure consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He is a multi-year recipient of the Microsoft MVP Award in Windows PowerShell. He works today as an independent author, trainer and consultant. Jeff has written for numerous online sites and print publications, is a contributing editor at Petri.com, and a frequent speaker at technology conferences and user groups.

comments powered by Disqus
Most   Popular