I'm trying to create small script in powershell that would move files and directories to correct localizations. I made the following command:
Get-ChildItem -Path '.\list\' | ForEach-Object { if ($($_.Name) -like '*[1]*') {
$file = $($_.Name)
$path = $($_.FullName)
echo "$file ==> $path"
Move-Item -Path $path -Destination .\[1]\}}
and it detects correct files and directories, but doesn't move them.
Then I decided to modify command a bit and create hardlinks instead:
Get-ChildItem -Path '.\list\' | ForEach-Object { if ($($_.Name) -like '*[1]*') {
$file = $($_.Name)
$path = $($_.FullName)
echo "$file ==> $path"
New-Item -Path ".\``[1``]\" -Name $file -Type HardLink -Target "$path"}}
and I received the following response (cut to only 1 loop):
[1] dir1 ==> D:\test_move\list\[1] dir1
New-Item:
Line |
5 | New-Item -Path ".\``[1``]\" -Name $file -Type HardLink -Target "$path …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Cannot find path 'D:\test_move\list\[1] dir1' because it does not exist.
The same error appears both with and without administrative privileges.
What do I have to do to make it work?
Try the following:
Note: The
-WhatIfcommon parameter in the command above previews the operation. Remove-WhatIfonce you're sure the operation will do what you want.-Filter '*[1]*'prefilters theGet-ChildItemoutput to only include files whose name contains substring[1]verbatim, because the-Filterparameter uses a filesystem-native wildcard language that does not treat[and]as metacharacters.'*[1]*'would match any name that contains just1, because the[...]is interpreted as a character set or range. With the-like, the wildcard matching operator operator, you'd have to use'*`[1`]*'(escaping of the metacharacters to be interpreted verbatim with`) to find verbatim[1]substrings.-Filelimits matching items to files, because hardlinks are only supported for files, not also directories.-Path (Join-Path .\[1] $file)use only a-Pathargument - rather than a directory-path-only-Pathargument combined with a filename-only-Nameargument - which ensures that the argument is treated as a literal (verbatim) path, without interpretation of wildcard metacharacters such as[and].-Pathwith-Namecauses the-Pathargument to be interpreted as a wildcard pattern.-Forcecreates the target directory on demand, if needed, but note that it would also replace any preexisting target file.Windows PowerShell:
([WildcardPattern]::Escape($path))escapes the-Target(aka-Value) argument (target path) in order to treat it verbatim, because it is - unfortunately - interpreted as a wildcard pattern. Not performing this escaping prompted the error you saw.Caveat:
In PowerShell [Core] 7+, a breaking change was approved in GitHub proposal #13136 to - more sensibly - treat the
-Targetargument as a literal (verbatim) path, in which case you would simply use-Target $path.However, as of PowerShell 7.3.8 this change isn't implemented yet, and, unfortunately, targeting a path that contains
[and]is currently broken altogether - see GitHub issue #14534.([WildcardPattern]::Escape([WildcardPattern]::Escape($path)))Note that many, but not all, file-processing cmdlets offer a
-LiteralPathparameter to explicitly pass paths to be taken literally (verbatim), whereas the-Pathparameter - usually the implied parameter for the first positional argument - is designed to accept wildcard patterns.Therefore, your could have made your original approach with
Move-Itemwork as follows:Note: Unlike with
New-Item,Move-Item's-Forcedoes not create the target directory on demand. On the flip side,Move-Item's-Destinationmore sensibly interprets its argument literally (verbatim), unlikeNew-Item's-Targetparameter.