45

I've found a nasty VBS way to do this, but I'm looking for a native PoSh procedure to edit the properties of a .LNK file. The goal is to reach out to remote machines, duplicate an existing shortcut with most of the correct properties, and edit a couple of them.

If it would just be easier to write a new shortcut file, that would work too.

Doug Chase
  • 701
  • 3
  • 8
  • 15

4 Answers4

50
Copy-Item $sourcepath $destination  ## Get the lnk we want to use as a template
$shell = New-Object -COM WScript.Shell
$shortcut = $shell.CreateShortcut($destination)  ## Open the lnk
$shortcut.TargetPath = "C:\path\to\new\exe.exe"  ## Make changes
$shortcut.Description = "Our new link"  ## This is the "Comment" field
$shortcut.Save()  ## Save

Found the VB version of the code here: http://www.tutorialized.com/view/tutorial/Extract-the-target-file-from-a-shortcut-file-.lnk/18349

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
  • FYI. This Solution works fine for local files, it doesn't work for UNC paths. – iraSenthil Aug 02 '11 at 17:03
  • 1
    I did some tests and this works fine for UNC paths. I'm not sure what @iraSenthil tested. – JasonMArcher Aug 31 '11 at 20:10
  • 1
    I'm not sure why that code wouldn't work for UNC paths, I've done the same thing for years in VB-Script/JScript. Just have to have permission and access to make the change (see example paths in note on Marco Shaws posting). As for Powershell, Tobias has put everything into two nice functions, get-shortcut and set-shortcut. Found here: http://powershell.com/cs/media/p/7895.aspx – Nathan Hartley Aug 31 '11 at 20:18
  • 1
    Worked brilliantly for me. Another couple of useful attributes are $shortcut.Arguments and $shortcut.WorkingDirectory. Also worked perfectly for UNC paths – Gargravarr Jul 19 '13 at 09:06
  • Here's some documentation with examples of each property in use: http://www.computerperformance.co.uk/powershell/powershell_create_shortcut.htm. – absynce Feb 02 '16 at 19:49
  • iraSenthil possibly ran the script as a user who had UNC path restricted via Group Policy. That's the only reason I can think for it to fail. – TylerH Apr 24 '18 at 16:07
  • The PowerShell.com link above has rotted, but Tim Lewis's answer (currently below) has code derived from that page that is very, very useful. – JefferMC Dec 20 '18 at 22:55
  • 1
    The PowerShell.com page has been preserved at https://web.archive.org/web/20160421140910/http://powershell.com/cs/media/p/7895.aspx . – NewSites Nov 01 '20 at 11:36
31

Below are the functions I use for dealing with .lnk files. They are modified versions of the functions found here as mentioned by @Nathan Hartley. I've improved Get-Shortcut to handle wildcards like * by passing strings to dir to expand them into sets of FileInfo objects.

function Get-Shortcut {
  param(
    $path = $null
  )
  
  $obj = New-Object -ComObject WScript.Shell

  if ($path -eq $null) {
    $pathUser = [System.Environment]::GetFolderPath('StartMenu')
    $pathCommon = $obj.SpecialFolders.Item('AllUsersStartMenu')
    $path = dir $pathUser, $pathCommon -Filter *.lnk -Recurse 
  }
  if ($path -is [string]) {
    $path = dir $path -Filter *.lnk
  }
  $path | ForEach-Object { 
    if ($_ -is [string]) {
      $_ = dir $_ -Filter *.lnk
    }
    if ($_) {
      $link = $obj.CreateShortcut($_.FullName)

      $info = @{}
      $info.Hotkey = $link.Hotkey
      $info.TargetPath = $link.TargetPath
      $info.LinkPath = $link.FullName
      $info.Arguments = $link.Arguments
      $info.Target = try {Split-Path $info.TargetPath -Leaf } catch { 'n/a'}
      $info.Link = try { Split-Path $info.LinkPath -Leaf } catch { 'n/a'}
      $info.WindowStyle = $link.WindowStyle
      $info.IconLocation = $link.IconLocation

      New-Object PSObject -Property $info
    }
  }
}

function Set-Shortcut {
  param(
  [Parameter(ValueFromPipelineByPropertyName=$true)]
  $LinkPath,
  $Hotkey,
  $IconLocation,
  $Arguments,
  $TargetPath
  )
  begin {
    $shell = New-Object -ComObject WScript.Shell
  }
  
  process {
    $link = $shell.CreateShortcut($LinkPath)

    $PSCmdlet.MyInvocation.BoundParameters.GetEnumerator() |
      Where-Object { $_.key -ne 'LinkPath' } |
      ForEach-Object { $link.$($_.key) = $_.value }
    $link.Save()
  }
}
Jimadine
  • 998
  • 13
  • 26
Tim Lewis
  • 3,335
  • 1
  • 36
  • 26
  • 5
    I just wanted to let you know that these functions are wonderful, and I appreciate you posting them. They just saved me a ton of hassle in a Robocopy job. – Chris Martin Mar 28 '16 at 19:32
  • 3
    If you're getting blank properties like .TargetPath, be aware that CreateShortcut() needs the full UNC path to your .LNK file. It ignores the current directory and ".\myshortcut.lnk" fails too. You don't get an error, just empty properties. – Tom Cerul Feb 28 '17 at 15:49
4

A short addition to @JasonMArcher's answer..

To see available properties you can just run $shortcut after $shortcut = $shell.CreateShortcut($destination) in a PS. This will print all properties and their current values.

schtiefel
  • 63
  • 5
3

I don't think there's a native way.

There is this DOS util: Shortcut.exe.

You still need to copy the util to the remote system, then possibly call it using WMI to make the changes you're looking for.

I'm thinking the easier way will be to overwrite and/or create a new file.

Do you have access to these systems via a remote share?

Marco Shaw
  • 1,117
  • 6
  • 13
  • Hi Marco. Sure, I can access them via a remote share. – Doug Chase Jan 29 '09 at 03:47
  • Well, I don't do enough regular admin stuff like this, but I'm thinking you can simply use the share to update the lnk file remotely. – Marco Shaw Jan 29 '09 at 15:00
  • Remotely, you would use something like "\\$Computer\C$\Documents and Settings\All Users\Start Menu\Programs\The Shortcut.lnk" for 95/98/XP/2003 and "\\$Computer\C$\ProgramData\Microsoft\Windows\Start Menu\Programs\The Shortcut.lnk" for Vista/Win 7/2008. – Nathan Hartley Aug 31 '11 at 20:13