1

I'm trying to run a simple icacls to a directory on my computer and I'm facing this error:


PS C:\Users\gguer\Documents> icacls.exe '.\My Digital Editions\'
.\My Digital Editions": The filename, directory name, or volume label syntax is incorrect.
Successfully processed 0 files; Failed processing 1 files

I'm using single quotes to escape the spaces as I was thought, so I don't know what is the issue here.

Mahmoud Abdelsattar
  • 1,299
  • 1
  • 15
  • 31

2 Answers2

3

To add an explanation to your own effective workaround (not including a trailing \ in your argument):

What you're seeing is a bug in Windows PowerShell with respect to how it passes arguments to external programs - this problem has been fixed in PowerShell (Core) 7+.

Behind the scenes, PowerShell (of necessity) translates your single-quoted argument containing spaces to a double-quoted form, because external CLIs can only be assumed to understand "..." quoting.

The command-line parsing rules used by most CLIs consider the sequence \" to be an escaped " character, i.e. a " character to be considered a verbatim part of the argument rather than delimiting it.

Therefore, a verbatim \ at the end of a double-quoted string must itself be escaped as \\ in order to be recognized as such - this is what Windows PowerShell neglects to do:

That is, Windows PowerShell translates your call as follows:

# Resulting command line as used behind the scenes for actual invocation.
# WinPS: BROKEN, because the \ at the end isn't escaped.
icacls.exe ".\My Digital Editions\"

When icacls.exe parses this command line, it sees verbatim .\My Digital Editions" (note the verbatim " at the end), as reflected in the error message.

PowerShell (Core), by contrast, does perform the necessary escaping:

# Resulting command line as used behind the scenes for actual invocation.
# PowerShell (Core): OK
icacls.exe ".\My Digital Editions\\"

Workarounds:

  • In a literal path, simply omit a trailing \ - which won't work for a root path, however, and it also assumes that this doesn't change the meaning of the argument from the target program's perspective (it doesn't for icacls.exe).

    • Programmatic solution:

      $path = '.\My Digital Editions\'
      icacls.exe $path.TrimEnd('\')  # !! Doesn't work for ROOT paths, e.g. "C:\"
      
  • Alternatively - which also works for root paths - manually double the trailing \

    • Quick-and-dirty programmatic solution, knowing that file-system paths may contain duplicated \ separators without ill-effects (however, it may affect path comparisons):

      icacls.exe "$path\"
      
  • A robust, cross-edition programmatic solution that doesn't modify the argument is a bit more cumbersome:

    icacls.exe $(if ($path.EndsWith('\') -and $PSVersionTable.PSEdition -ne 'Core') { "$path\" } else { $path })
    

As an aside:

A related bug that affects how " (double quotes) embedded in arguments are passed to external programs is affects PowerShell (Core) up to 7.2.x - see this answer.

mklement0
  • 382,024
  • 64
  • 607
  • 775
1

Solved! Just had to remove the last backslash. Cheers.