1

Can someone please explain the following behaviour to me?

PS C:\Users\Kenny> $filePath = "C:\\Complicated.File.Path.That.Has.Special-Chars`[but-no.spaces`]and.definitely.exists\"
PS C:\Users\Kenny> cd $filePath
cd : Cannot find path 'C:\\Complicated.File.Path.That.Has.Special-Chars[but-no.spaces]and.definitely.exists\' because it does not exist.
At line:1 char:1
+ cd $filePath
+ ~~~~~~~~~~~~~~~~                                 
    + CategoryInfo          : ObjectNotFound: (C:\\Complicated...initely.exists\:String) [Set-Location], ItemNotFoundE
   xception
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.SetLocationCommand

PS C:\Users\Kenny> cd 'C:\\Complicated.File.Path.That.Has.Special-Chars`[but-no.spaces`]and.definitely.exists\'
PS C:\Complicated.File.Path.That.Has.Special-Chars[but-no.spaces]and.definitely.exists> cd c:
PS C:\Users\Kenny> Write-Host $filePath
C:\\Complicated.File.Path.That.Has.Special-Chars[but-no.spaces]and.definitely.exists\
PS C:\Users\Kenny> cd "$filePath"
cd : Cannot find path 'C:\\Complicated.File.Path.That.Has.Special-Chars[but-no.spaces]and.definitely.exists\' because it does not exist.
At line:1 char:1
+ cd "$filePath"
+ ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\\Complicated...initely.exists\:String) [Set-Location], ItemNotFoundE
   xception
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.SetLocationCommand

PS C:\Users\Kenny> cd ${filePath}
cd : Cannot find path 'C:\\Complicated.File.Path.That.Has.Special-Chars[but-no.spaces]and.definitely.exists\' because it does not exist.
At line:1 char:1
+ cd ${originalPath}
+ ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\\Complicated...initely.exists\:String) [Set-Location], ItemNotFoundE
   xception
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.SetLocationCommand

PS C:\Users\Kenny> cd ${$filePath}
cd : Cannot process argument because the value of argument "path" is null. Change the value of argument "path" to a
non-null value.
At line:1 char:1
+ cd ${$filePath}
+ ~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Set-Location], PSArgumentNullException
    + FullyQualifiedErrorId : ArgumentNull,Microsoft.PowerShell.Commands.SetLocationCommand

PS C:\Users\Kenny> cd $($filePath)
cd : Cannot find path 'C:\\Complicated.File.Path.That.Has.Special-Chars[but-no.spaces]and.definitely.exists\' because it does not exist.
At line:1 char:1
+ cd $($filePath)
+ ~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\\Complicated...initely.exists\:String) [Set-Location], ItemNotFoundE
   xception
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.SetLocationCommand

If I had a penny for every minute I've wasted on PowerShell's insistance that backticks, quotes and other meta-characters are just right, I would be the richest man on Earth! Somebody please save me from this madness!

And BTW, what I'm actually trying to do is recurse through a bunch of folders and delete everything that isn't a video file, like so...

Remove-Item -Path $filePath -Recurse -Exclude '*.avi','*.mkv','*.mp4'

...which doesn't work for (presumably) the same reason: not being able to pass a variable to the -Path parameter. And if someone is feeling really generous, they could also help me with this. MTIA! :D

Kenny83
  • 769
  • 12
  • 38
  • 1
    FWIW: Procmon tells that Powershell is looking for `C:\Complicated.File.Path.That.Has.Special-Chars?and.definitely.exists`. The whole bracketed part is converted as a single wildcard, `?`. – vonPryz Nov 01 '19 at 06:54
  • Why are you using CD path when all you're doing is searching for files to delete? – Scepticalist Nov 01 '19 at 07:19
  • @Scepticalist I started with the `Remove-Item...` command posted above, then after bashing my head against a brick wall with that for 1/2 an hour, tried simplifying the command as much as possible, since I knew it had to have something to do with special chars being interpreted even though I was using backticks to escape them, but wanted to verify that. – Kenny83 Nov 01 '19 at 07:21

3 Answers3

1

Use -LiteralPath instead of -Path because some of the special characters where interpreted with -Path.

Remove-Item -LiteralPath
Patrick
  • 2,128
  • 16
  • 24
  • You are the man! I thought I was taking crazy pills for a while there! +25 to you sir :D And also a big thank you and +1 to @vonPryz who also caught this. Why on Earth did the backticks before the square brackets not prevent me from wasting an hour on this?? – Kenny83 Nov 01 '19 at 07:23
  • you're welcome (I also struggled a few hours when this appears the first time to me...). No idea about the backticks. – Patrick Nov 01 '19 at 08:07
  • Hmm OK...thanks anyway. The irony of this situation is that using `-LiteralPath` now prevents me from performing a wildcard search, i.e. `Remove-Item -LiteralPath C:\my.file.[path]\* -Recurse -Exclude '*.avi','*.mkv','*.mp4'` doesn't work, since the `*` is interpreted literally lol. So now I'm looking into using `Get-ChildItem -LiteralPath C:\my.file.[path] | Where-Object ... | Remove-Item`. Hopefully **that** will finally give me a solution! – Kenny83 Nov 01 '19 at 08:15
1

Special characters are just so much fun in PS right?

-LiteralPath works exactly like Patrick explained, but they don't allow for wildcards; because they're literal.

Have you tried using single quotes ' instead of double quotes ". This allows you to escape special characters, while still evaluating wildcards. Try the commands below:

New-Item -Path 'C:\Users\username\PSScripts\bracket`[\te$t.txt'
Get-Item -Path  'C:\Users\username\PSScripts\bracket`[\*'

Also, if it helps, I use VSCode for most scripting and, if you use tab completion, it will format this properly for you.

I hope that helps!

  • I ended up finding another solution to the problem, but now wish I hadn't so I could test your theory. TYVM anyway for trying to help! Have an upvote for your trouble :D And I'd give you two more if I could for the "special characters are fun" comment LOL! About as fun as rubbing salt into an open wound right?? :P Also thanks for the VSCode tip; will definitely use it from now on! – Kenny83 Nov 01 '19 at 14:26
0

The solution to my overall problem ended up being this line of my batch script:

powershell -Command "Get-ChildItem -Recurse -LiteralPath %filePath% | Where-Object Extension -match '^(?!(\.avi|\.mkv|\.mp4)$)' | Remove-Item"

The regex was the hardest to get right, since I haven't used negative lookaheads before, but after ~2 hours of total time spent on this one line of code, it finally works!

Kenny83
  • 769
  • 12
  • 38