3
votes

I wrote a powershell script to strip R/H/S attributes off all files in a specified set of root paths. The relevant code is:

$Mask = [System.IO.FileAttributes]::ReadOnly.Value__ -bor [System.IO.FileAttributes]::Hidden.Value__ -bor [System.IO.FileAttributes]::System.Value__
Get-ChildItem -Path $Paths -Force -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
    $Value = $_.Attributes.value__
    if($Value -band $Mask) {
        $Value = $Value -band -bnot $Mask
        if($PSCmdlet.ShouldProcess($_.FullName, "Set $([System.IO.FileAttributes] $Value)")) {
            $_.Attributes = $Value
        }
    }
}

This works fine, but when processing one very large folder structure, I got a few errors like this:

Exception setting "Attributes": "Could not find a part of the path 'XXXXXXXXXX'."
At YYYYYYYYYY\Grant-FullAccess.ps1:77 char:17
+                 $_.Attributes = $Value
+                 ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], SetValueInvocationException
    + FullyQualifiedErrorId : ExceptionWhenSetting

I find this strange because the FileInfo object being manipulated is guaranteed to exist, since it comes from a file search.

I can't give the file names because they are confidential, but I can say:

  • they are 113-116 characters long
  • the unique set of characters involved are %()+-.0123456789ABCDEFGIKLNOPRSTUVWX, none of which are illegal in a file name
  • the % character is there due to URL-encoded spaces (%20)

Do you have any suggestions as to what may be causing this? I assume that if the full path was too long, or I didn't have write permissions to the file, then a more appropriate error would be thrown.

2
Are these UNC paths (\\server\share\restofpath) or local paths?Theo
@mklement0: My intention is to process directories as well as files, but thanks for the tip.Christian Hayter
@mklement0: Re the long path prefix, I do now suspect it's a long path issue. I will try that today.Christian Hayter
@Theo: The paths will always be on a local drive.Christian Hayter

2 Answers

3
votes

As stated in your own answer, the problem turned out to be an overly long path (longer than the legacy limit of 259 chars.)

In addition to enabling long-path support via Group Policy, you can enable it on a per-computer basis via the registry as follows, which requires running with elevation (as admin):

# NOTE: Must be run elevated (as admin).
# Change will take effect in FUTURE sessions.
Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem LongPathsEnabled 1

Pass 0 to turn support off.


However, even with long-path supported turned OFF (as is invariably the case on pre-Windows 10 versions) it is possible to handle long paths:

  • In Windows PowerShell (PowerShell up to version 5.1), you must use the long-path opt-in prefix, \\?\, as discussed below.

  • In PowerShell [Core] v6+, no extra work is needed, because it always supports long paths - you neither need to turn on support system-wide nor do you need the long-path prefix discussed below.

    • Caveat: While you may use \\?\ in PowerShell [Core] as well in principle, support for it is inconsistent as of v7.0.0-rc.2; see this GitHub issue.

Important: Prefix \\?\ only works under the following conditions:

  • The prefixed path must be a full (absolute), normalized path (must not contain . or .. components).

    • E.g., \\?\C:\path\to\foo.txt works, but \\?\.\foo.txt does not.
    • Furthermore, if the path is a UNC path, the path requires a different form:
      • \\?\UNC\<server>\<share>\...;
      • E.g., \\server1\share2 must be represented as \\?\UNC\server1\share2
0
votes

It did turn out to be a long path issue after all, despite the wording of the error messages. A simple Get-ChildItem search for the files produced the same errors. I finally tracked down the files mentioned in the error messages and measured their total path lengths. They were exceeding 260 characters.

I experimented with adding a \\?\ prefix to the paths, but powershell doesn't seem to like that syntax.

Fortunately, the script is being used on Windows 2016, so I tried enabling long path support in group policy. That made the whole problem go away.