15

I have a script that I wrote that replaces files. I pass params to it for the name of the file, and the base location to search from. The worker lines are:

$SubLocations = Get-ChildItem -Path $Startlocation -Recurse -include $Filename -Force  | 
                Where { $_.FullName.ToUpper().contains($Filter.ToUpper())}

I set $Startlocation to "C:\Users", however, I am getting access denied when trying to recurse through other users folders. I'm full admin on the machine, and I have already tried running powershell as admin. I can access all the files via Windows explorer with no issue. Any idea?

Get-ChildItem : Access to the path 'C:\Users\jepa227\Documents\My Music' is denied.
At C:\Users\krla226\Google Drive\Documents\PowerShell\Replace-File.ps1:35 char:46
+ $SubLocations = Get-ChildItem <<<<  -Path $Startlocation -Recurse -    include $Filename -Force | 
    + CategoryInfo          : PermissionDenied: (C:\Users\jepa227\Documents\My     Music:String) [Get-ChildItem], Una 
   uthorizedAccessException
+ FullyQualifiedErrorId :  DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand

UPDATE

While I was unable to get it working via GCI, I was able to use WMI to solve my problem. For those interested:

$SubLocations = Get-WmiObject -Class cim_datafile -Filter "fileName = '$filename' AND Extension = '$extension'" | 
                            Where { $_.Name.ToUpper().contains($Filter.ToUpper()) }
mcating
  • 1,062
  • 11
  • 18
Kevin_
  • 2,916
  • 3
  • 19
  • 18
  • Is UAC enabled? I tried on a non-UAC Windows 7 box with multiple users and didn't encounter an Access Denied when trying to access other users' directories. Also, what OS/Powershell version are you using? – mcating Jun 06 '14 at 17:05
  • UAC is disabled, but I'm also in a domain. I can't remember if that will make a difference or not. Running 7 pro 64-bit and Powershell 2 – Kevin_ Jun 06 '14 at 20:13

3 Answers3

7

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 $_ }
mklement0
  • 382,024
  • 64
  • 607
  • 775
mcating
  • 1,062
  • 11
  • 18
  • This would not work for my situation, as I was trying to replace items within other users Appdata. Without -Force, it wouldn't even attempt to find their Appdata folder. – Kevin_ Jun 18 '14 at 16:09
  • 2
    Removing -force doesn't help and it has nothing to do with junction points. I has the same issue with temp files. – Suncatcher Feb 09 '17 at 19:03
  • @Suncatcher: `-Force` comes into play, because these system-defined junction points also have the _hidden_ attribute. Without `-Force`, PowerShell doesn't see hidden items. – mklement0 Jun 20 '18 at 16:07
5

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.

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

PS C:\PSScripts>

Get-ChildItem -Attributes !Hidden, !System, !ResparsePoint -Recurse -Force   "C:\Users\" 
Get-ChildItem : Cannot bind parameter 'Attributes'. Cannot convert value "System.Object[]" to type "System.Management.Automation.FlagsExpression`1[System.IO.FileAttributes]". Error: "Unable to match the identifier name ResparsePoint to a valid enumerator name. Specify 
one of the following enumerator names and try again:
ReadOnly, Hidden, System, Directory, Archive, Device, Normal, Temporary, SparseFile, ReparsePoint, Compressed, Offline, NotContentIndexed, Encrypted, IntegrityStream, NoScrubData"
At line:1 char:27
+ Get-ChildItem -Attributes !Hidden, !System, !ResparsePoint -Recurse - ...
+                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Get-ChildItem], ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.GetChildItemCommand

Have you ever tried using values like !Hidden, etc? Didn't think so. It doesn't accept these values.

Habanagold
  • 41
  • 1
  • 2
  • 8