powershellhardlinknew-item

Cannot find path _ because it does not exist


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?


Solution

  • Try the following:

    Get-ChildItem -LiteralPath .\list -File -Filter '*[1]*' | ForEach-Object { 
      $file = $_.Name
      $path = $_.FullName
      "$file  ==>  $path" # implicit `echo` aka `Write-Output`
      New-Item -Force -Type HardLink `
               -Path (Join-Path .\[1] $file) `
               -Target ([WildcardPattern]::Escape($path)) ` # !! see PowerShell Core comments below
               -WhatIf
    }
    

    Note: The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.

    Note that many, but not all, file-processing cmdlets offer a -LiteralPath parameter to explicitly pass paths to be taken literally (verbatim), whereas the -Path parameter - 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-Item work as follows:

    # Ensure that the target dir. exists.
    # No escaping needed for -Path when not combined with -Name.
    $null = New-Item -Type Directory -Path .\[1] -Force 
    
    # Move the file, targeted with -LiteralPath, there.
    # No escaping needed for -Destination.
    Move-Item -LiteralPath $path -Destination .\[1]\
    

    Note: Unlike with New-Item, Move-Item's -Force does not create the target directory on demand. On the flip side, Move-Item's -Destination more sensibly interprets its argument literally (verbatim), unlike New-Item's -Target parameter.