I am writing a PowerShell script to search the C:\Users directory and change all lnk files that contain \server1 to \server2 but keep the rest of the link.
What I have so far will keep changing the LNK's target path to "Computer" and then disable you from being able to edit the LNK. Can anyone explain why this is doing this?
Code:
#Folder to search
$favourites_path = "C:\Users\"
#Backup C:\Users DISABLED by Default "
# Copy-Item $favourites_path "$favourites_path`1" -Recurse
$favourites = Get-ChildItem $favourites_path -Recurse -Filter *.lnk
foreach ($favourite in $favourites) {
$shortcut = (New-Object -ComObject
'WScript.Shell').CreateShortCut($favourite.FullName)
$newpath=switch -Wildcard ($shortcut.TargetPath)
{
'"\\server1*"' { $_ -replace '"\\server1"', '"\\server2"'}
}
$shortcut.TargetPath=$newpath
$shortcut.Save()
}
Even though Explorer may show the Target:
field of a shortcut (*.lnk
file) enclosed in "..."
, accessing the equivalent field programmatically usually does not contain these enclosing double quotes.
-replace
's 1st RHS operand is a regex (regular expression), in which \
is the escape character. Therefore, to replace a literal \
, you must double it.
\\server1
with \\\server2
.Since you're recreating the shortcut file unconditionally, there is no need for a switch
statement, given that -replace
amounts to a no-op if the regex doesn't match anything.
switch
statement has only 1 branch and no default branch, so that any target that doesn't start with \\server1
(leaving the double-quoting aside) is set to $null
.The following code addresses these issues:
#Folder to search
$favourites_path = "C:\Users"
Get-ChildItem $favourites_path -Recurse -Filter *.lnk | ForEach-Object {
$shortcut = (New-Object -ComObject 'WScript.Shell').CreateShortCut($favourite.FullName)
$shortcut.Target = $shortcut.Target -replace '^\\\\server1\\', '\\server2\'
$shortcut.Save()
}
Note how the regex is anchored with ^
to the start of the string, ensuring that literal \\server1\
only matches there.
An alternative to manually doubling the \
instances is to use [regex]::Escape()
, which escapes any regex metacharacters in the input string to ensure its treatment as a literal:
$shortcut.Target = $shortcut.Target -replace ('^' + [regex]::Escape('\\server1\')), '\\server2\'
In the replacement string (2nd RHS operand), \
instances do not need escaping; there, only $
instances would need escaping, because $
-prefixed tokens refer to parts of what the regex matched (see this answer of mine for more).