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()
}
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'