0

I have a situation where all the paths in the shortcut files that are located in the %AppData%\Microsoft\Windows\Start Menu\Programs folder and subfolders all point to an incorrect drive letter. This includes the Target: value, Start In: value and all the paths to the icon files as well. I'd like to change them all from X:\ to C:\

There are a couple that are correctly pointing to C:\ but there's only a handful of them.

Here is the code I was working with. I am able to change the TargetPath but not the WorkingDirectory value. I've tried removing the comment on line 20 but that creates an error about $null-valued expression. I've also tried duplicating the bit for TargetPath to WorkingDirectory but it does not change:

$folder = "C:\Temp\Shortcuts" 
[string]$from = "X:\" 
[string]$to = "C:\" 
$list = Get-ChildItem -Path $folder -Recurse  | Where-Object { $_.Attributes -ne "Directory"} | select -ExpandProperty FullName 
$obj = New-Object -ComObject WScript.Shell 

ForEach($lnk in $list) 
{ 
    $obj = New-Object -ComObject WScript.Shell 
    $link = $obj.CreateShortcut($lnk) 
    [string]$path = $link.TargetPath  
    [string]$path = [string]$path.Replace($from.tostring(),$to.ToString()) 
#   [string]$path = $link.WorkingDirectory
#   [string]$path = [string]$path.Replace($from.tostring(),$to.ToString()) 

    #If you need workingdirectory change please uncomment the below line. 
    #$link.WorkingDirectory = [string]$WorkingDirectory.Replace($from.tostring(),$to.ToString()) 
    $link.TargetPath = [string]$path 
    $link.Save() 
}
Lance U. Matthews
  • 15,725
  • 6
  • 48
  • 68
Jim Dandy
  • 3
  • 2
  • Did you tried something on your own. Do you have some code you have problems with? So is not a code writing service – guiwhatsthat Sep 20 '18 at 05:54
  • try to short your code and show us your problem. Otherwise no one will help you – guiwhatsthat Sep 20 '18 at 14:46
  • It appears that the trouble I'm experiencing is related to case. In my shortcuts the TargetPath is set with upper-case drive letter, the WorkingDirectory is set using lower-case. I cannot seem to find the correct way to express case-insensitivity to the .Replace command. – Jim Dandy Sep 20 '18 at 16:52

1 Answers1

2

Line 20 in the code you posted is the trailing }, but I'm assuming this...

#$link.WorkingDirectory = [string]$WorkingDirectory.Replace($from.tostring(),$to.ToString()) 

...is the real line 20. The reason for that error is because you are trying to call .Replace() on $WorkingDirectory instead of $link.WorkingDirectory. $WorkingDirectory, if it's not set anywhere, will evaluate to $null.

With that corrected, PowerShell provides its own string replacement operators: -replace and -ireplace are case-insensitive, -creplace is case-sensitive. The first operand to all of these operators is a regular expression, and since a backslash in regex denotes a special character, you will need to escape the \ in your search pattern like this...

[string]$from = "X:\\"

You can then change the drive letter of the WorkingDirectory property with...

$link.WorkingDirectory = [string] $link.WorkingDirectory -replace $from.tostring(),$to.ToString()

...or...

$link.WorkingDirectory = [string] $link.WorkingDirectory -ireplace $from.tostring(),$to.ToString()

Note that $link.WorkingDirectory, $from, and $to are already of type [String], so the [String] cast and calls to .ToString() are unnecessary and can be removed...

$link.WorkingDirectory = $link.WorkingDirectory -replace $from,$to

One tiny optimization you might make is to add an anchor to your search pattern so it won't bother to search for the drive letter beyond the absolute beginning of the [String]...

[string]$from = "^X:\\"

Also, since you are using PowerShell 3+, instead of filtering out directories like this...

$list = Get-ChildItem -Path $folder -Recurse  | Where-Object { $_.Attributes -ne "Directory"}

...you can filter in files like this...

$list = Get-ChildItem -Path $folder -Recurse -File

Better yet, you can use the -Filter parameter to only include files with an .lnk extension, too...

$list = Get-ChildItem -Path $folder -Recurse -File -Filter '*.lnk'
Lance U. Matthews
  • 15,725
  • 6
  • 48
  • 68
  • Thanks, I really appreciate the extra information you provided, it's given me a lot of information I wasn't able to understand from the original script. Much appreciated. I do have a bit of a problem with one adjustment. The code line: `$list = Get-ChildItem -Path $folder -Recurse -File -Filter '*.lnk' ` creates the correct list but the code: `$link = $obj.CreateShortcut($lnk)` replaces the $folder with "C:\Windows\System32" so instead of a filename “C:\Temp\Shortcut\FileName.lnk” I get “C:\Windows\System32\Filename.lnk” @bacon – Jim Dandy Sep 21 '18 at 01:10
  • When you pass `$lnk` of type [`FileInfo`](https://docs.microsoft.com/dotnet/api/system.io.fileinfo) as the `String` parameter to `CreateShortcut()`, PowerShell won't know how to meaningfully convert that so it just calls [`$lnk.ToString()`](https://docs.microsoft.com/dotnet/api/system.io.fileinfo.tostring). This returns just the file name, which `.CreateShortcut()` treats as a relative path in the current directory, `C:\Windows\System32`. Instead, pass the shortcut file's path, [`$lnk.FullName`](https://docs.microsoft.com/dotnet/api/system.io.filesysteminfo.fullname), to `.CreateShortcut()`. – Lance U. Matthews Sep 21 '18 at 02:11
  • I'm glad that solved your issue. Remember that as the question author you can [upvote or downvote answers based on whether you find them helpful or not, and accept an answer that best solves your probem](https://stackoverflow.com/help/someone-answers). – Lance U. Matthews Sep 23 '18 at 18:22