none
Get-ChildItem follows ReparsePoints in PSSessions

    Question

  • So I'm trying to write a little function which goes through each userprofile and calculates the profile size. Seemd to be an easy task, but boy, I was wrong...

    If I execute this code locally, it works as expected (checking just my own userprofile):

    $a = Get-ChildItem "C:\Users\$($env:USERNAME)" -Force -Recurse -ErrorAction SilentlyContinue |
         Where-Object {$_.Attributes -notmatch 'ReparsePoint'} | 
         Select FullName, Length
    ($a | measure length -sum).sum /1MB
    155.213445456420

    BUT(!) when I run the same command on the same computer with the same user, just in a PSSession, the commands are not working as expected: It seems in PSSessions ReparsePoints are followed, thus the script is iterating over and over every hardlink/symlink/junction (which should not happen!)

    Enter-PSSession $env:COMPUTERNAME $a = Get-ChildItem "C:\Users\$($env:USERNAME)" -Force -Recurse -ErrorAction SilentlyContinue | Where-Object {$_.Attributes -notmatch 'ReparsePoint'} | Select FullName, Length ($a | measure length -sum).sum /1MB

    2721.89250946045

    Exit-PSSession


    Any idea how to modify the remote query, so it works just like locally? (without robocopy and with good performance)

    I found many similar problems, but without any solution, eg:

    https://stackoverflow.com/questions/29763790/how-to-make-get-childitem-not-to-follow-links

    https://stackoverflow.com/questions/43462804/check-remote-profile-size


    • Edited by bsajtos Wednesday, December 27, 2017 12:51 PM
    Wednesday, December 27, 2017 12:49 PM

All replies


  • PowerShell remoting doesn't use any user profile, so $env:Userprofile will not be as you expected, 

    you can do a Write-Output $Env:Userprofile before doing Get-ChildItem

    If you are targeting remote computers, You can't use interactive remoting(1 to 1). Use Invoke-Command which can be used for multiple remote computers in a single shot.

    Get-Help Invoke-Command -Full


    Regards kvprasoon

    Wednesday, December 27, 2017 1:01 PM

  • PowerShell remoting doesn't use any user profile, so $env:Userprofile will not be as you expected, 

    you can do a Write-Output $Env:Userprofile before doing Get-ChildItem

    If you are targeting remote computers, You can't use interactive remoting(1 to 1). Use Invoke-Command which can be used for multiple remote computers in a single shot.

    Get-Help Invoke-Command -Full


    Regards kvprasoon


    Remote sessions do load a user profile.  They load the profile of the account creating the session.  Where did you see something that made you think this.

    I  think you are not understanding the issue correctly.


    \_(ツ)_/

    Wednesday, December 27, 2017 2:59 PM
  • The correct way to filter on an attribute is the following:

    $a = Get-ChildItem "C:\Users\$($env:USERNAME)" -Force -Recurse -File |
        Where-Object { -not($_.Attributes -band [System.IO.FileAttributes]::ReparsePoint) }

    Do not hide errors and return only files.

    The "Attributes" property is a flag field "System.IO.FileAttributes" and not a string.


    \_(ツ)_/


    • Edited by jrv Wednesday, December 27, 2017 3:12 PM
    Wednesday, December 27, 2017 3:08 PM
  • Your arguments doesn't help. This is not the point. You can replace $env:username with whatever existing profile you want, and of course I won't use interactive pssession in the planned function either.

    The shared code is for presentation purposes so everybody can understand what's the problem and can replicate the scenario. What you pointed out is not the problem, but thank you for looking into it.

    Wednesday, December 27, 2017 4:39 PM
  • Your arguments doesn't help. This is not the point. You can replace $env:username with whatever existing profile you want, and of course I won't use interactive pssession in the planned function either.

    The shared code is for presentation purposes so everybody can understand what's the problem and can replicate the scenario. What you pointed out is not the problem, but thank you for looking into it.

    What are you objecting to?  There are a number of posts before this and all are addressing issues that you have with your original code.

    $env:USERNAME will always return the profile of the current sessions user.

    The reparse points can only be filtered correctly by using the flags type for the attributes and "band" it it with the flags field.

    Locally reparse points are not recursed into and remotely they are.  This is by design.  To ignore reparse points you will also need to find both file and folder reparse points.  The code I posted only filters for files.  To remove folders get all folders filtered by reparse flag and then use the results to get all files in the folders.

    The code I posted is just an example of how to filter the attributes and is not necessarily what you will finally need to do.


    \_(ツ)_/

    Wednesday, December 27, 2017 4:46 PM
  • Thank you for pointing that out, knowing that I will use -bxor instead of -not & -band.

    But unfortunately, the problem persist. Locally 155MB, after entering PSSession it returnes 2700+MB.

    I have captured the exceptions which happen locally and remotely:

    $localErr | select -ExpandProperty exception
    Access to the path 'C:\Users\BigJoe\AppData\Local\Application Data' is denied.
    Access to the path 'C:\Users\BigJoe\AppData\Local\History' is denied.
    Access to the path 'C:\Users\BigJoe\AppData\Local\Temporary Internet Files' is denied.
    Access to the path 'C:\Users\BigJoe\Application Data' is denied.
    Access to the path 'C:\Users\BigJoe\Cookies' is denied.
    Access to the path 'C:\Users\BigJoe\Documents\My Music' is denied.
    Access to the path 'C:\Users\BigJoe\Documents\My Pictures' is denied.
    Access to the path 'C:\Users\BigJoe\Documents\My Videos' is denied.
    Access to the path 'C:\Users\BigJoe\Local Settings' is denied.
    Access to the path 'C:\Users\BigJoe\My Documents' is denied.
    Access to the path 'C:\Users\BigJoe\NetHood' is denied.
    Access to the path 'C:\Users\BigJoe\PrintHood' is denied.
    Access to the path 'C:\Users\BigJoe\Recent' is denied.
    Access to the path 'C:\Users\BigJoe\SendTo' is denied.
    Access to the path 'C:\Users\BigJoe\Start Menu' is denied.
    Access to the path 'C:\Users\BigJoe\Templates' is denied.
    

    Within PSSession: It gives 289 errors, all of them are:

    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.

    Wednesday, December 27, 2017 4:52 PM
  • You have to filter the folders first.

    Example:

    $folders = Get-ChildItem "C:\Users\$($env:USERNAME)" -Force -Recurse -Directory|
        Where-Object { $_.Attributes -notmatch 'ReparsePoint' } 
    
    $folders | %{$_.GetFiles() } | Measure-Object -Sum Length
    
    

    The bigger issue is that the "recurse" will still recurse into the links and will give you issue.  To prevent this you will need to discover all links and exclude them from your search.


    \_(ツ)_/

    Wednesday, December 27, 2017 4:58 PM
  • Excuse me, I intended to reply to kvprasoon's comment.

    Yeah, I thought that what seems to be a bug for me, it's by design :) 

    I understand what you mean, but I was hoping for a simpler/more elegant solution than a recursive and slow iteration to exclude reparsepoints just like you pointed out "Attributes" property is a flag field.

    So all is left is to create recursive function. :\ 


    Wednesday, December 27, 2017 5:28 PM
  • Yes.  A recursive function that does not follow reparse folders should do it.

    I think that WMI may ignore reparse points.  Check it.


    \_(ツ)_/

    Wednesday, December 27, 2017 5:38 PM
  • The following will be faster and does not follow junction/rpp.  It also handles long names correctly:

    robocopy d:\ . /l /s /xj /nc /nfl /ns /ndl


    \_(ツ)_/

    Wednesday, December 27, 2017 6:01 PM
  • My bad, I didn't give a try for this in my box, apologies for the wrong info.

    Regards kvprasoon

    Wednesday, December 27, 2017 6:31 PM
  • But this seems reparse points are recursed even locally


    Regards kvprasoon

    Wednesday, December 27, 2017 6:49 PM
  • from what i see from your code your spacing is wrong 

    code is written as such in all languages 

    aaaaaaaaaaaaaaa

        bbbbbbbbbbbbb

            ccccccccccccccccc

                ddddddddddddd

    etc for a reason uniformed code will work on the local but not across different platforms such as unix linux apple etc  

    not like 

    aaaaaaaaaaaaaaaaaaaa

    bbbbbbbbbbbbbbbbbb

    cccccccccccccccccccccc

    ddddddddddddddddddddd

    etc you will also need all of the child  entry's  

    Wednesday, December 27, 2017 6:51 PM
  • from what i see from your code your spacing is wrong 

    code is written as such in all languages 

    aaaaaaaaaaaaaaa

        bbbbbbbbbbbbb

            ccccccccccccccccc

                ddddddddddddd

    etc for a reason uniformed code will work on the local but not across different platforms such as unix linux apple etc  

    not like 

    aaaaaaaaaaaaaaaaaaaa

    bbbbbbbbbbbbbbbbbb

    cccccccccccccccccccccc

    ddddddddddddddddddddd

    etc you will also need all of the child  entry's  


    Your comment is not useful and has nothing to do with PowerShell. 

    \_(ツ)_/

    Wednesday, December 27, 2017 8:35 PM
  • My answer may be a bit late but: Use "-Attributes !ReparsePoint" right in Get-ChildItem instead of doing it AFTER Get-ChildItem in Where-Object.

    Try this variant:

    $a = Get-ChildItem "C:\Users\$($env:USERNAME)" -Force -Recurse -Attributes !ReparsePoint -ErrorAction SilentlyContinue |
         Select FullName, Length
    ($a | measure length -sum).sum /1MB
    
    Sunday, February 10, 2019 3:43 PM