List all files and dirs without recursion with junctions

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.


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


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.


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