7

Is there a native|portable tool that can give me a unicode or a system local-compatible list of all files and directories under a path recursively, without recursing into junction points or links, in Windows?

For example, the built-in dir takedown icacls commands run into an infinite loop with the Application Data directory (1).

EDIT I would like to be able to get a text file or at least an easy clipboard transfer as an output.

6
  • I would like to avoid using a scripting language (eg. python's os.walk), because I'd prefer a solution more easily portable (eg. a smaller single-file tool)
    – n611x007
    Jan 5, 2013 at 11:00
  • Oh, and the tool should handle paths with spaces. :)
    – n611x007
    Jan 5, 2013 at 11:13
  • Note the text file doesn't have to be 'plain', it can be xml, csv, tsv, or anything text.
    – n611x007
    Jan 5, 2013 at 11:16
  • 2
    I believe you could do this with robocopy, using the /L flag to prevent it from actually doing any copying. Jan 7, 2013 at 2:24
  • 1
    Did you try the tree command in Windows? You can pass the result of this command to a text file
    – Prasanna
    Oct 10, 2016 at 12:08

10 Answers 10

7

This was somehow a hard question. Even StackOverflow has only fancy solutions.
But here is a simple one for listing all files recursively without junction folder loops.

Use PowerShell and test each file if it contains the attribute "ReparsePoint"

function Recurse($path) {

  $fc = new-object -com scripting.filesystemobject
  $folder = $fc.getfolder($path)

  foreach ($i in $folder.files) { $i | select Path }

  foreach ($i in $folder.subfolders) {
    $i | select Path        
    if ( (get-item $i.path).Attributes.ToString().Contains("ReparsePoint") -eq $false) {        
        Recurse($i.path)
    }
  }
}

$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
$outputlist = Recurse($scriptPath) | Out-File -Filepath .\outputlist.txt 
  1. Paste the code into a text file and save it as PowerShell (.ps1) script
  2. Place the script inside your desired folder to list all files+folder recursively
  3. Execute the script with PowerShell. A new file called outputlist.txt at the same location will appear

Quick comparison between the Powershell script and a common batch command

powershell  - good, no indefinite loops

enter image description here

batch "DIR /B /S" - bad, indefinite loops through junctions points

enter image description here

5
  • To test it, I've just created a junction with sysinternals tool junction.exe in a folder to itself, and unfortunately for me Directory List & Print did get into recursion.
    – n611x007
    Jan 5, 2013 at 12:37
  • @naxa A late response. But better late, then never.
    – nixda
    Aug 18, 2013 at 17:15
  • I love the fact that you sorted it out, and it just works! Thanks nixda! As my original problem was gone (and I don't tend to keep a powershell at home), it took me too some time but I've finally tested it and it works just like I wanted!! Also, I'm absolutely fond of better late than never myself. :)
    – n611x007
    Sep 26, 2013 at 11:05
  • 1
    For powershell beginners like me, powershell -ExecutionPolicy Unrestricted -File <yourfilename-here.ps1> will execute the script (my file association was set to notepad :).)
    – n611x007
    Sep 26, 2013 at 11:06
  • Well, actually, now that I think of it, I think my original problem was never finished... it got to a point but now it's actually on hold. Hey, thanks, now I can finish the project. :D
    – n611x007
    Sep 26, 2013 at 11:15
4

The original symbolic link for Application Data has special permissions and attributes to prevent Everyone from reading or viewing the content of the target folder (via the symbolic link). This prevents programs from getting caught in a recursive loop. You can easily reapply the permissions and attributes, but be very careful to only apply these permissions and attributes to the symbolic link and not to any actual files or folders. The symbolic link will be an icon in Windows Explorer with a shortcut arrow over the top of a folder icon.

  1. Open Windows Explorer
  2. Tap the alt key, and click Tools, then Options, then click the View tab
  3. Disable the option to [ ] Hide protected operating system files, and enable the option to (x) Show hidden files, folders, or drives.
  4. Navigate to C:\Users\[user]\AppData\Local
  5. Right-click Application Data symbolic link and choose Properties (make sure it's the symbolic link and not a real folder -- it should have a shortcut arrow as an overlay on top of a folder icon)
  6. Click the Security tab, then Advanced, then Change Permissions
  7. Add Everyone, and set the rights for Everyone to:
    • Apply To = This folder only (<-this is important)
    • Permissions = Deny List folder / read data (<- this stops recursion)
  8. Click OK and then click Yes to the warning that a Deny rule is applied before an Allow rule
  9. Click OK again to apply the changes
  10. Click the Owner tab, click Edit, then click Other users or groups
  11. Type SYSTEM, and keep clicking OK until you are back at Windows Explorer

The recursion is now disabled. There is one more thing that you might want to do. Most of these types of symbolic links have special file attributes so that they won't be visible to users. Open a Command Prompt and run the following commands:

cd "%userprofile%\AppData\Local"
attrib +S +H +I /L "Application Data"

The /L option tells attrib to apply +S +H +I to the symbolic link, instead of applying it to the target folder (C:\Users\[user]\AppData\Local).

If you mess up, you can easily remove the symbolic link and recreate it from a Command Prompt. Be careful that you recreate so that it points to the same folder as it did before. The dir /a command will show you where Application Data points to. You should retype the target folder verbatim as the final parameter of the mklink command.

cd "%userprofile%\AppData\Local"
attrib -H -S -I /L "Application Data"
dir /a
rd "Application Data"
mklink /J "%userprofile%\AppData\Local\Application Data" "%userprofile%\AppData\Local"

Now you have an Application Data symbolic link that has the recursion problem. So just following the steps above to fix the recursion issue.

Don't forget to change the settings in step #3 back to their original values, so that you don't continue to see files that should be hidden.

4

1. If you're on Windows 10, use DIR /S /A-L

This way, junctions won't be listed, neither will be recurred with /S. On Windows 7, DIR /S /AD-L recurses junctions, so see an option below. Not sure about 8/8.1.

batch with output to text file:

CHCP 65001 & REM for UTF-8
DIR %* /B /S /A-L > out.txt

(pass path and additional DIR args as batch arguments)

cmd.exe to clipboard (can be invoked via Win+R):

cmd /C "CHCP 65001 & DIR "%USERPROFILE%" /B /S /A-L | CLIP"

Clipboard is unicode by default, but without CHCP beforehand, DIR output is in OEM codepage, so some characters may be lost. Quotes after /C are required by CMD syntax, despite it looks weird with inner quotes around %USERPROFILE%.

2. Use small script, so everything will be listed, but junctions won't be followed.

Works fine on Windows 7, unlike option above in this answer

let's call it dnj.cmd (like in Dir No Junctions)

@(ECHO OFF
    SETLOCAL ENABLEEXTENSIONS
    CHCP 65001>NUL
    IF "%~1"=="" (CALL :listDir .) ELSE CALL :listDir %*
    EXIT /B
)
:listDir <path>
FOR /F "usebackq delims=" %%F IN (`DIR /B /A "%~1"`) DO ECHO %~1\%%~F
(
    IF EXIST "%~1\*.*" FOR /F "usebackq delims=" %%F IN (`DIR /B /AD-L "%~1"`) DO CALL :listDir "%~1\%%~F"
    IF "%~2"=="" EXIT /B
    SHIFT
    GOTO :listDir
)

First FOR/DIR for output, second FOR/DIR for recursion. This way, you can also adjust output parameters (specifically, DIR and ECHO arguments). For example, if you only want flat list of files in output without directories, use

FOR /F "usebackq delims=" %%F IN (`DIR %1 /B /A-D`) DO ECHO %%~F

in place of first FOR.

Invoking: dnj.cmd path [path [...]]

Output redirection works same way as with conventional DIR, so

cmd /C "dnj.cmd "%USERPROFILE%" | CLIP"

works from Win+R ("Run") prompt.

3
  • 1
    Great suggestion. Your 'dnj' fails if a directory ends in ')'. I think I have it working properly: :listDir <path> ( FOR /F "usebackq delims=" %%F IN (DIR %1 /B /A) DO (SET I="%~1\%%F" SET J=!I:"=! ECHO !J! ) FOR /F "usebackq delims=" %%F IN (DIR %1 /B /AD-L) DO (SET I="%~1\%%F" CALL :listDir !I! ) EXIT /B )
    – trindflo
    May 8, 2019 at 16:14
  • @trindflo thanks for pointing it out. I find delayed expansion way slower than normal run, so just excluding ECHO %%~F from (...) group works way better IMO. May 9, 2019 at 6:48
  • 1
    Answer 2 here is perfect, though I wish it were its own answer. OP requested DIR, and the built-in one-liner /A-L option works great. Appreciate the caveat on win7/8, but this is the whole answer in 2021.
    – davenpcj
    Jul 22, 2021 at 13:44
2

Using powershell more succinctly:

$items = @(pwd);
while($items){ $newitems = $items | Get-ChildItem | Where-Object -Property Attributes -NotLike *ReparsePoint*; $newitems; $items = $newitems | Where-Object -Property Attributes -Like *Directory* }

To get this all into a text file, just surround the whole thing with parenthesis and pipe it into out-file.

( $items = @(pwd); while($items){ $newitems = $items | gci | where -Property Attributes -NotLike *ReparsePoint*; $newitems; $items = $newitems | where -Property Attributes -Like *Directory* } ) | out-file myfile.txt
1
  • 2
    dont u need a $ at the beginning and | out-file? or is that cuz powershell version diff? Dec 11, 2017 at 13:00
1

This may not be a native tool but could be useful to someone with windows 7, there's a program called FileLocator Pro which has an option under Advanced/Junction Points to turn off searching junction points.

Once that's done you can use the command line program flpsearch like this:

"C:\Program Files\Mythicsoft\FileLocator Pro\flpsearch.exe" -o c:\biglist.txt -d c:\;d:\;e:\ -ofbs -f *

Echo Started cleanup

for /F "tokens=1-2 delims=  " %%i in (c:\biglist.txt) do if "!prevx!" neq "%%i" (ECHO %%i >> c:\big.txt & (if /i "%%j" neq "on" echo        %%j >> c:\big.txt) & set prevx=%%i) else (if /i "%%j" neq "on" echo     %%j >> c:\big.txt) 

There's literal tabs in there after the echo's and delims so make sure your text editor isn't converting tabs to spaces.

Hope this might be useful to a Win7 user or two.

Ofc the powershell options are good too, but DOS batch is another story.

0

From a CMD prompt:

dir /A:-L /S /B

EDIT: While this won't list the actual junction in the directory it resides, it will recurse down the junction.

1
  • Does not work if you boot from a WinPE image: I still see the "Application Data" directory repeat until it crashes.
    – trindflo
    May 8, 2019 at 16:20
0

The problem here is that someone has removed the anti recursion from Application Data folder.

It needs to have a DENY to EVERYONE to List Folder/Read Data.

If you want to go into it use the AppData folder which is where it points.

There are two junction points - one in %userprofile% and another in %userprofile%\local.

4
  • 1
    So how does one fix this problem. You have told the author WHAT the problem is but not HOW to fix it. An acceptable answer contains both.
    – Ramhound
    Jun 7, 2015 at 18:51
  • He can work out him/herself that if it needs something to give it. The poster sabotaged their system.
    – trigger
    Jun 7, 2015 at 18:53
  • @trigger nice information! I still need the directory walk that avoids the junctions because the Application Data was just an example. It takes too much time to detect all the possible problems. So you need your traversal program to skip recursing into the symlinks. I gave a +1 for the knowledge however!
    – n611x007
    Jun 8, 2015 at 9:43
  • I have to agree with Ramhound. Seeing as the person who answered this seems unwilling to provide a complete solution, hopefully someone else will provide both in another answer so that this one can be removed. Also, not sure if the comment about the poster sabotaging their system is supposed to imply that the majority of Windows installs out there don't allow any directory listing tools to recurse into the backwards-compatible WinVista+ %userprofile% junction points, but in my experience this very much depends on the application doing the recursing.
    – user66001
    May 4, 2016 at 18:41
0

This problem might be due to anti recursion permissions being removed from the Application Data folder (like may apply to any Windows Vista+ Junction Point created for backward-compatibility).

These junction points should have DENY to EVERYONE on List Folder/Read Data permissions, which will take precedence over any ALLOW permissions, and hopefully not be circumvented by any directory recursing program due to the way it accesses the File system.

From https://msdn.microsoft.com/en-us/library/windows/desktop/bb968829(v=vs.85).aspx it would appear Junction points are identified by having the ReparsePoint attribute, alongside the Hidden and System attributes.

The following Powershell command is the basis of what seems to be a simpler solution to excluding Junction Points from directory recursions, than any previous answer.

get-childitem $RootDirectoryForRecusion -recurse -force | where-object {-not ($_.Attributes -match "ReparsePoint" -and $_.Attributes -match "Hidden" -and $_.Attributes -match "System")}

-1

In PowerShell 3.0 there is a new parameter Attribute:

Lists directory structure without junction folders:

Get-ChildItem -Path $RootDirectory -Attributes !ReparsePoint -Recurse -Force -ErrorAction SilentlyContinue

Lists junction folders only from a directory structure:

Get-ChildItem -Path $RootDirectory -Attributes ReparsePoint -Recurse -Force -ErrorAction SilentlyContinue

More info: Use PowerShell 3.0 to Filter Files Based on Advanced Attributes

1
  • 2
    The attribute parameter seems to test the leaf, not the parent directories. When using Get-ChildItem -Attributes !ReparsePoint it seems to happily dive through reparse points and still cause the "path too long" error. Jun 6, 2017 at 20:01
-1

In PowerShell,

Get-ChildItem /Recurse <path> |
Where-Object { $_.Mode -notlike 'd*l' } |
ForEach-Object { $_.FullName};

You can just pipe the output to a file if you want to save it.

2
  • Should be -Recurse not /Recurse Good answer though.
    – Marty Neal
    Nov 6, 2017 at 17:23
  • This does not answer the question or solve the problem. The OP put the most important part as the question itself, and repeated it in bold text. "**without recursing into junction points **". This command will absolutely recurse into junctions. It just won't list the symlink on a line by itself. For example: With a symlink named "mysim" pointing to a folder with a file named "myfile", the output generated would not include <path>\mysim but it WOULD recurse and show <path>\mysim\myfile. Aug 1, 2018 at 16:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .