Score:0

Handle exception with long paths in Powershell

in flag
ed7

I am new here and I facing issues with my powershell script whith long paths. This script aims to get relative path and hash from files/folders and its subfolders. It works with some with others I get the following error:

Get-ChildItem : The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.

I would like to know how to handle this and avoiding to give me this error please.

I have enabled the long file paths in Windows server 2012 where I am running the script and it still does not work.

If I add this \\?\ in the path variable, it failes saying that there are Illegal characters in path even if I add -LiteralPath.

Any help would be great

This is mypowershell script:

#Message to user
  Write-Output "`nThis script will collect the FilePathName, Name, RelativePath and the Hash of the files/folders you have chosen."
               "`nAt the end, it will tell you how long it took to run the script"   
  Read-Host -Prompt "`nPress ENTER to continue or CTRL+C to quit" 
        
  #Counting the time from the beginning
  $starttime = (Get-Date)
        
  #Variables
  #Can only be added 3 paths maximum. If added more than 3 it may change the relatrive path
  $root = "C:\mypath"
        
        
  #Variable for creating the CSV File
  $report = "mycsvfile.csv"
        
        
  #Process for generating the HASH
  $hasher = [System.Security.Cryptography.SHA256]::Create()
  $AllFiles = @() 
        
  "`n"#line space
        
  Write-Host "Generating the Hash from $root" 
        
        
        
  #Getting information from directories
  foreach ($file in get-childitem $root -recurse | Select-Object FullName, Directory, Name, PSIsContainer, Length)
  {
      $acl = get-acl $file.fullname | select-object owner,accesstostring,group
      $obj = new-object psObject
        
        
  #Generating HASH File
      if(!$file.PsIsContainer)
          {
          $relativePath = $file.FullName.Substring($root.Length)
          Write-Host "Debug $relativePath" -ForegroundColor Green
        
          $inputStream = New-Object IO.StreamReader $file.fullname
          $hashBytes = $hasher.ComputeHash($inputStream.BaseStream)
          $inputStream.Close()
        
          $builder = New-Object System.Text.StringBuilder
          $hashBytes | Foreach-Object { [void] $builder.Append($_.ToString("X2")) }
        
  #Add info into CSV FILE
          $obj | Add-Member -membertype noteproperty -name FilePathandName -Value $file.FullName
          $obj | Add-Member -membertype noteproperty -name Name -Value $file.Name
          $obj | Add-Member -MemberType noteproperty -Name RelativePath -Value $relativePath #-force
          $obj | Add-Member -MemberType noteproperty -Name Hash -Value $builder.ToString()
          #$obj | Add-Member -membertype noteproperty -name CreationTime -Value $file.CreationTime
          #$obj | Add-Member -MemberType noteproperty -Name LastAccessTime -Value $file.LastAccessTime
          #$obj | Add-Member -MemberType noteproperty -Name LastWriteTime -Value $file.LastWriteTime
        
                
      #Variable to send info to CSV
      $AllFiles += $obj
      Clear-Variable relativePath
      }
  Remove-Variable obj
  }
        
  #$AllFiles += $obj
        
  #Generating CSV FILE
  $AllFiles |Export-Csv $report –NoTypeInformation
        
  "`n"
  Write-Host "$report File has been created "
        
  "`n"
  Write-Host "The script took:`n"
  $endTime = Get-Date
  New-TimeSpan -Start $startTime -End $endTime
br flag
[1] if you are using win10 or win11, you can set the OS to allow long names. ///// [2] you can also use the unicode prefix to allow long paths for just that one call. ///// for info on both, lookee ... >>> Maximum Path Length Limitation - Win32 apps | Microsoft Docs — https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd
stackprotector avatar
th flag
Can you edit your question to include a [MRE] with your actual vs. your expected output?
Score:1
ru flag

In order for the Powershell cmdlets to work properly using \\?\ You need to install the following minimum versions of these components (tested and validated on Windows Server 2012 R2):

Then, you just need to change the root path variable in your script as follow and it will work just as expected:

  #Variables
  #Can only be added 3 paths maximum. If added more than 3 it may change the relative path
  $root = "\\?\C:\mypath\"
        

There is no need to change any registry key to enable support of long paths or using the -LiteralPath parameter for any cmdlets. I've seen these claims multiple times in other articles and forums but that's not correct except for very old versions of Windows.


Now, if you cannot install these newer versions, you will have to use workarounds.

Note that in your script, the following functions are affected by this issue:

  • Get-ChildItem
  • Get-Acl
  • New-Object IO.StreamReader

One solution would be to substitute part of the path as a drive when it becomes too long and use the new drive as the root folder. I tried this using SUBST command but it should work using the New-PSDrive cmdlet. This requires to add some logic in your script but it's not too much efforts and fairly easy.

Now, if you want to get a list of all files before doing any substitution (so you can first check all path and filename lengths), you can use the following workaround:

$root = "C:\mypath\" ;
$AllFiles = cmd /c dir $root /b /s /a-d ;

This will give you the list of files (full names).

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.