Get-ChildItem -force reports "Access Denied" on My Documents folder and other junction points Get-ChildItem -force reports "Access Denied" on My Documents folder and other junction points powershell powershell

Get-ChildItem -force reports "Access Denied" on My Documents folder and other junction points


I was able to reproduce this on a Windows 7 machine with the following command logged in as an admin user named "admin", running powershell with elevated privileges, and UAC disabled:

get-childitem "c:\users\Admin\my documents"

and

cd "c:\users\admin\my documents"get-childitem

Based on the article here, it looks like My Documents, My Music, etc., are defined as junction points for backwards-compatibility with pre-Vista software. Powershell doesn't natively do well with junction points. It seems like there are a couple options here:

1) Remove the -force from the Get-ChildItem command. This is likely your best bet.

get-childitem c:\users -recurse

works without error and skips junction points and system directories like AppData.

Editor's note: Omitting -Force does solve the immediate problem, but invariably skips all hidden items, not just the hidden junction points that cause the access-denied errors.

2) If you absolutely need to use the -Force for some reason, you could programmatically recurse each subdirectory, skipping junction points. This article describes the mechanism to identify junction points. A skeleton of this in a .ps1 script file might look like:

Param( [Parameter(Mandatory=$true)][string]$startLocation )$errorActionPreference = "Stop"function ProcessDirectory( $dir ){  Write-Host ("Working on " + $dir.FullName)  # Work on the files in this folder here  $filesToProcess = ( gci | where { ($_.PsIsContainer -eq 0) } ) # and file matches the requested pattern  # process files  $subdirs = gci $dir.FullName -force | where {($_.Attributes -band [IO.FileAttributes]::ReparsePoint) -eq 0 -and ($_.PsIsContainer -eq 1) -and (![string]::IsNullOrEmpty($_.FullName))}  foreach( $subdir in $subdirs )  {      # Write-Host( $subdir.Name + ", " + $subdir.FullName )     if ( $subdir -ne $null )     {       ProcessDirectory -dir $subdir     }  }}$dirs = get-childitem $startLocation -force$dirs | foreach { ProcessDirectory -dir $_ }


mcating's helpful answer explains the problem well.

The quick fix he suggests is to omit -Force, which works, because PowerShell ignores hidden items unless -Force is used, and these system-defined junction points do have the Hidden attribute (alongside the ReparsePoint and System attributes).

If you do need -Force in order to process hidden items in general and only want to ignore these system-defined junction points, you can use Get-ChildItem's -Attributes parameter as follows:

Get-ChildItem -Force -Recurse -Attributes !Hidden, !System, !ReparsePoint

The -Attributes value excludes all items that have all of the following attributes set: Hidden, System, ReparsePoint, which is true of all system-defined junction points.
While it is technically possible to create your own junction points (or symbolic links) with these attributes, this is unlikely to occur in practice.