Downloads
97837.zip

 Executive Summary:

The Get-Shortcut.ps1 script can be used to transform shortcut files into shortcut objects. You can then use the shortcut objects to perform shortcut-related tasks in Windows PowerShell. Some of these shortcut tasks include exporting a user’s Microsoft Internet Explorer (IE) Favorites and finding stale shortcuts.

Shortcuts can be found everywhere in Windows, and checking or fixing them occasionally crops up as an administrative task. For years, scripters have used the Windows Script Host (WSH) WshShortcut object to work with shortcuts. It turns out that this same object, packaged appropriately for use in Windows PowerShell, can work with native WSH tools to perform shortcut tasks and can even make some odd and unexpected tasks quite easy to perform. I'm going to demonstrate how you can use the PowerShell script, Get-Shortcut.ps1, to turn shortcut files into WSH shortcut objects, and then discuss how you can use the shortcut objects to accomplish various tasks such as finding paths to documents you’ve recently used and determining whether shortcuts are stale.

Using Get-Shortcut to Present Shortcut Files as Shortcut Objects
First, download the Get-Shortcut.ps1 script, shown in Listing 1, by clicking the Download the Code Here button at the top of the article page. Then, use the Get-ChildItem cmdlet to pipe paths to one or more shortcut files into the script. Each shortcut name must end in either .lnk (for a shortcut to a Windows file) or .url (for a shortcut to a Web site). If the shortcut name doesn't have one these extensions, the WScript.Shell COM object handling the shortcuts rejects it, and you get an error for that item.

You can also pass Get-Shortcut.ps1 a list of pre-existing files, such as files created from a directory listing. A couple of significant locations for finding these files are the Microsoft Internet Explorer (IE) Favorites folder and the folder containing recent documents. In Windows Server 2003 and Windows XP, the path to a user's Favorites folder is typically $home\Favorites\links, and the path to a user’s recent documents folder is typically $home\recent. In Windows Vista, the paths would be $home\favorites and $home\Appdata\Roaming\Microsoft\Windows\Recent, respectively. To get the recent document listing and view the documents as shortcuts in XP, use the command

Get-ChildItem $home\recent | Get-Shortcut

The Get-Shortcut cmdlet will pass out WshShortcut objects, which should look something like the sample output in Figure 1. As you can see, the output is in default form. Let's look at some commands that help with both the functionality and appearance of shortcuts. To simplify typing, you can omit the Get- from the Get-Shortcut name, and run the command

Get-ChildItem $home\recent | Shortcut

PowerShell will automatically add the Get- for you during its searches.

You might encounter annoying scrolling from access errors with the Get-ChildItem enumeration in user folders. In Vista, this scrolling is typically due to permissions on junction points and excessive name lengths in some AppData subfolders. Generally, you won't encounter errors if you're just listing the contents of a shortcut folder, but if you ever need to hide errors generated by a PowerShell cmdlet, you can suppress them by telling the cmdlet to continue silently when it encounters errors. The following command is an example of the Get-ChildItem cmdlet suppressing errors:

Get-ChildItem $home\recent -ErrorAction  SilentlyContinue | Shortcut <strong></strong>

This command just throws away Get-ChildItem errors. The -ErrorAction parameter is ubiquitous, meaning that every single cmdlet in PowerShell supports it. The other legitimate values that you can use with the -ErrorAction parameter are Stop, which causes execution to terminate when an error is encountered; Continue, which is the default behavior in which execution continues but errors are shown; and Inquire, which asks you whether you want to continue when errors are encountered.

To save some time and typing, it's useful to save the output of the Get-ChildItem command. If you enter the command

$lnk = Get-ChildItem $home\recent -ErrorAction  SilentlyContinue | Get-Shortcut

the shortcut objects will all be saved in the variable $lnk for later use. From here on, we'll assume you've done so. Note that using a variable containing these shortcuts also makes the later lines of code a bit easier to read.

Another trick that helps with both functionality and appearance is filtering how shortcut objects are displayed. By default, if PowerShell doesn't know anything about a particular object, it displays the object in list format, showing every single property—even if the property is empty. You can explicitly pipe the shortcut objects to the Format-List cmdlet and tell it which properties to display. You don't even have to enter the full property names; Format-List will let you use a wildcard for the names of properties to show. For example, suppose all you care to see is the actual FullName (where the shortcut file is), the TargetPath (the object pointed to), optional Arguments, the WorkingDirectory (the directory used as a home location), and the WindowStyle (whether an application runs minimized, maximized, or in a normal window). To get just these properties in your display, use the following command:

$lnk | Format-List -Property \[aftw\]*

This command says "show me all properties that begin with the letter a, f, t, or w." If you use this command, the output will be similar to that in Figure 2. Note that your property names will be identical to those property names in Figure 2, but your values will depend on the particular locations you're checking.

Exporting Your IE Favorites
Now that we have shortcut objects, let's look at how to use them to perform different tasks. Suppose you want to export all of your current IE Favorites. By default, your IE Favorites are located within the Favorites folder in user home directories and use the .url extension instead of the .lnk extension. You can export your IE Favorites to a file named favorites.csv in the current PowerShell location by including the Export-Csv cmdlet in the command:

Get-ChildItem -Path $home\favorites\links | Shortcut | Export-Csv -Path  favorites.csv

In this command, I used the Favorites location for Windows 2003 and XP. For Vista, you would change $home\favorites\links to $home\favorites. If you prefer to use the standard aliases and omit or abbreviate parameter names in PowerShell, you can shorten the command to

gci $home\favorites\links | Shortcut | epcsv  favorites.csv

You can now open the favorites.csv file in Microsoft Excel or echo its contents to the PowerShell console by running the command

Get-Content favorites.csv

Finding Paths to Documents You've Recently Used
Although Windows displays only a handful of shortcuts, the Recent Documents folder contains shortcuts that go back to your last cleanup using the Disk Cleanup Wizard or another tool that clears the cache. These shortcuts can be found in a hidden folder named Recent, which is located within user home folders.

Suppose you want to get these shortcut files and see them in the order they were used. First, you have to get the shortcut files and sort them using PowerShell's Sort-Object cmdlet. Sort-Object sorts the shortcut files from newest to oldest based on the LastWriteTime, which accurately records how recently the file was used. Earlier I demonstrated saving the shortcut objects in the variable $lnk. However, those shortcut objects don't include file data such as the last time the shortcut file was used. You must sort the shortcut files in order of use before turning them into shortcut objects. You can sort and save them in the variable $docLinks using the command

$docLinks = Get-ChildItem -Path $home\recent | Sort-Object  LastWriteTime -Descending | Shortcut

We now have the shortcut files—not the shortcut objects. To get the actual shortcut objects, run the following command:

$docLinks = $docLinks | Shortcut

At this point, the shortcut objects are stored in the variable $docLinks. Now you can use the ForEach-Object cmdlet to extract the TargetPath property (i.e., the actual path to the file) using the command

$docLinks | ForEach-Object  \{$_.TargetPath\}

If you're not familiar with the $_ notation, here's how it works: ForEach-Object takes each object it gets from the pipeline and runs the commands specified in the braces (\{ \}) against it. The $_ notation in the braces represents the current object. Therefore, as each shortcut object comes into ForEach-Object, the cmdlet extracts the object's TargetPath property. For brevity, you can use ForEach-Object’s % alias and shorten the command to

$docLinks |% \{$_.TargetPath\}

This command shows the true path to each shortcut target.

Determining Whether Shortcuts Are Stale
Shortcuts become stale all the time. Shortcuts can go stale temporarily (e.g., if shortcuts point to disconnected drives) or permanently (e.g., if a file has been removed or renamed). All you have to do is determine whether the shortcut's TargetPath exists. If it doesn't, the shortcut is stale. Because we already have a collection of shortcuts in $docLinks, we'll use those as our test set.

PowerShell's Where-Object cmdlet is useful for determining if a shortcut's TargetPath exists. Where-Object works by applying a test that you specify each time it gets an input object. If the test succeeds, the object is passed on out the pipeline; if the test fails, Where-Object drops the object.

PowerShell's Test-Path cmdlet tests paths and returns a true value if a shortcut is at the specified location. If you want to see shortcuts that are valid, run the command

$docLinks | Where-Object \{ Test-Path  $_.TargetPath\}

Because you typically want to find the paths that fail, you’ll want reverse this command. To find only the stale shortcuts, use the –not operator in the command

$docLinks | Where-Object \{ -not (Test-Path $_.TargetPath)\}

For brevity, you can use the exclamation mark (!) as the -not operator, as shown in the command

$docLinks | Where-Object \{ !(Test-Path  $_.TargetPath)\}

Because I use the Where-Object cmdlet frequently, I typically use its alias, the question mark (?), as shown in the following command:

$docLinks | ? \{ !(Test-Path  $_.TargetPath)\}

Deleting Stale Shortcuts
Now let's explore how to delete stale recent documents shortcuts, which can speed up some searching activities quite a bit. To do so, use the Remove-Item cmdlet to delete files within PowerShell. If you try to use Remove-Item directly on a shortcut, PowerShell will have no idea of what to do with the shortcut. A shortcut's FullName property, however, is a path and the Remove-Item cmdlet understands that. Therefore, to generate a list of stale shortcuts and delete each one, you'd use the command

$docLinks | ? \{ !(Test-Path  $_.TargetPath)\} | ForEach-Object \{ Remove-Item  $_.FullName\}

Once again, you can use ForEach-Object's % alias and Remove-Item's ri alias in the command

$docLinks | ? \{ !(Test-Path  $_.TargetPath)\} | % \{ ri $_.FullName\}

At this point, the only barrier to writing a script that removes stale recent document shortcuts is the variation in recent document locations based on the OS. Although explaining the technique used is beyond the scope of this article, it is possible to get the correct path for recent documents on any system by using the Shell.Application COM object. You can run the Remove-StaleRecentDocument.ps1 script, shown in Listing 2, as an ordinary user to remove these stale links.

Which Shortcuts Use Special Arguments?
It's common for applications on the Start Menu to have special arguments. These arguments can give you some insight into special operating modes for applications, including undocumented features. If you've got shortcuts from the Start Menu in the variable $lnk, you can use the Where-Object cmdlet to filter these applications down to only those that have arguments, and then display the shortcut name, target application, and its arguments using the command

$lnk | ? \{$_.Arguments\} | Format-List FullName, TargetPath, Arguments

Using Get-Shortcut.ps1 to Create New Shortcuts
You can create brand–new shortcuts by passing a valid name to the Get-Shortcut.ps1 script. For example, if you run the command

$cmd = "c:\tmp\CommandShell.lnk" | Shortcut

Get-Shortcut.ps1 will create a new shortcut named CommandShell in C:\tmp, and put the shortcut object into the $cmd variable. You can make this shortcut object into a valid shortcut if you set the target path and then save the object by running the command

$cmd.TargetPath = "C:\Windows\System32\cmd.exe"
$cmd.Save()

Note that you won’t see a shortcut file in the target directory until you call the Save method. When you create a shortcut, you’re really just creating a shortcut in memory; it doesn't become an actual file until you save it.

Managing Shortcuts
The shortcut tasks described in this article only scratch the surface of how you can use PowerShell to manage shortcuts in Windows. Now that you now know how to use the Get-Shortcut.ps1 script to make shortcut files into shortcut objects, as well as how to manage shortcuts using shortcut objects, you’ll be able to quickly and easily perform any other required shortcut tasks.