Cleaning up shortcuts with Powershell

I maintain a set of scripts for deploying Firefox ESR to my organization, as well as necessary internal CAs and an autoconfig bundle. During testing, a system was encountered that for some reason had residual shortcuts for Firefox 16.

These shortcuts, found in the user-specific start menu path, pointed at the old Firefox installer. User tries to launch Firefox, user sees a failed installation process. It's probably related to MSI deployment, which I've moved away from because a) I don't fully understand the mechanisms, and b) Mozilla provides .exe installers, not MSIs, and it's more comfortable not getting the binaries through a third party.

Shortcut Objects

Anyway, on to the code. It turns out that Powershell has a mechanism for object-izing shortcuts, making them quite simple to operate on.

> $link = ".\Mozilla Firefox.lnk"
> $shell = New-Object -COM WScript.Shell
> $shortcut = $shell.CreateShortcut($link)

Okay, now we have a shortcut object set up. Let's take a look at the properties of the object, and see what we can do with it.

> $shortcut

FullName         : i:\Mozilla Firefox.lnk
Arguments        :
Description      : Run Mozilla Firefox (Version 16.0.1.0).
Hotkey           :
IconLocation     : C:\Windows\Installer\{3DF21514-3096-40DD-B6ED-E5B0256DAC32}\firefox.16.0.1.0.ico.exe,0
RelativePath     :
TargetPath       : C:\Windows\Installer\{3DF21514-3096-40DD-B6ED-E5B0256DAC32}\firefox.16.0.1.0.ico.exe
WindowStyle      : 1
WorkingDirectory : C:\Program Files\Mozilla Firefox\

Lots of options to play with here. We can change the icon, which currently is set to "The first icon embedded in the declared target" to something else by pointing to a file with embedded icons, and specifying the icon of choice:

$shortcut.IconLocation = "%SystemRoot%\system32\SHELL32.dll,14
$shortcut.save()

Similarly, you can change the tooltip that appears when hovering over the shortcut:

$shortcut.Description = "Mozilla Firefox, YourOrg edition"
$shortcut.save()

Operating on the other properties would work much the same way; give $shortcut.TargetPath a path, and so on.

Comparing Properties

Playing with icons and descriptions is fun, but in an unattended script, I want to be able to assess the properties and act accordingly. Conditionals with comparisons are simple, too:

if ( ($shortcut.FullName -like "\*firefox\*") -and ($shortcut.TargetPath -like "\*firefox\*") ) {
    # do stuff
    }

Note that -like makes a sloppy match. It isn't case sensitive, even, just a basic string comparison. If you want to be precise, you have to actually build regex for it, and I'm not covering that here.

Seek and Destroy

In my case, I want to find any shortcut in any user's home directory that appears to be related to firefox, and points to the awkward Windows Installer path, and remove it. Here's what something like that might look like:

$shell = New-Object -COM Wscript.shell
$FirefoxLinks = Get-Childitem -Path C:\Users -recurse -Filter "*firefox*link*"
$FirefoxLinks | ForEach-Object {
    $link = $_.FullName
    $shortcut = $shell.CreateShortcut($link)
    if ( $shortcut.TargetPath -like "*installer*" ) {
        rm $shortcut.FullName
        }
    }

Comments

Comments powered by Disqus