Listar todos os arquivos e diretórios sem recursão com junções


4

Existe uma ferramenta nativa portátil que pode me dar um unicode ou uma lista compatível com o sistema local de todos os arquivos e diretórios em um caminho recursivamente , sem recursão em pontos de junção ou links, no Windows?

Por exemplo, os dir takedown icaclscomandos internos são executados em um loop infinito com o diretório Application Data ( 1 ).

EDIT Eu gostaria de ser capaz de obter um arquivo de texto ou pelo menos uma transferência fácil da área de transferência como uma saída.


Eu gostaria de evitar o uso de uma linguagem de script (por exemplo, python os.walk), porque eu preferiria uma solução mais facilmente portátil (por exemplo, uma ferramenta de arquivo único menor)
n611x007

Ah, e a ferramenta deve lidar com caminhos com espaços . :)
n611x007

Observe que o arquivo de texto não precisa ser 'simples', pode ser xml, csv, tsv ou qualquer texto.
n611x007

2
Eu acredito que você poderia fazer isso com o robocopy, usando o /Lsinalizador para impedir que ele realmente faça qualquer cópia.
Harry Johnston

@HarryJohnston de fato, com robocopy /XJ /L /E <dir> <dummy-target>, a /XJbandeira pula as junções e as /Lcausas para listar apenas! /Eé para recursão. Problema: muito detalhado. Mas ele pode ser feito um pouco melhor com uma compilação win32 do grep da GNU: robocopy /XJ /L /E <dir> <dummy-target> | grep -i "new dir\|new file". Ainda precisa "aplicar" o diretório de contenção para cada arquivo.
n611x007

Respostas:


5

Esta foi de alguma forma uma questão difícil. Mesmo o StackOverflow tem apenas soluções sofisticadas .
Mas aqui está um simples para listar todos os arquivos recursivamente sem loops de pastas de junção.

Use o PowerShell e teste cada arquivo se ele contiver o atributo "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. Cole o código em um arquivo de texto e salve-o como script do PowerShell (.ps1)
  2. Coloque o script dentro da pasta desejada para listar todos os arquivos + pasta de forma recursiva
  3. Execute o script com o PowerShell. Um novo arquivo chamado outputlist.txtno mesmo local aparecerá

Comparação rápida entre o script Powershell e um comando em lote comum

powershell  - good, no indefinite loops

insira a descrição da imagem aqui

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

insira a descrição da imagem aqui


Para testá-lo, acabei de criar uma junção com a ferramenta sysinternals junction.exeem uma pasta para si mesma e, infelizmente, para mim , entrei Directory List & Printem recursão.
n611x007

@naxa Uma resposta tardia. Mas é melhor tarde, depois nunca.
nixda

Eu amo o fato de você ter resolvido isso, e isso simplesmente funciona! Obrigado nixda! Como meu problema original foi embora (e eu não tenho a tendência de manter um powershell em casa), levei muito tempo, mas finalmente testei e funciona como eu queria! Além disso, eu gosto muito mais tarde do que nunca. :)
n611x007

1
Para iniciantes powerhell como eu, powershell -ExecutionPolicy Unrestricted -File <yourfilename-here.ps1>irá executar o script (minha associação de arquivos foi definida para o bloco de notas :)).
n611x007

Bem, na verdade, agora que penso nisso, acho que meu problema original nunca terminou ... chegou a um ponto, mas agora está realmente em espera. Obrigado, agora posso terminar o projeto. : D
n611x007

2

Usando o powershell de forma mais sucinta:

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

Para colocar tudo isso em um arquivo de texto, basta colocar a coisa toda entre parênteses e enviá-la para fora do arquivo.

( $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
você não precisa de um $ no início e | out-file? ou é essa versão do powershell diff?
colin lamarre

1

O problema aqui é que alguém removeu a anti-recursão da pasta Application Data.

Ele precisa ter um DENY para TODOS para Listar Pasta / Ler Dados.

Se você quiser entrar, use a pasta AppData, que é onde ela aponta.

Existem dois pontos de junção - um em %userprofile%e outro em %userprofile%\local.


1
Então, como se resolve esse problema? Você disse ao autor qual é o problema, mas não como corrigi-lo. Uma resposta aceitável contém ambos.
Ramhound

Ele pode descobrir se isso precisa de algo para dar. O cartaz sabotou seu sistema.
gatilho

@trigger informação legal! Eu ainda preciso do diretório walk que evita os entroncamentos porque os dados do aplicativo eram apenas um exemplo. Demora muito tempo para detectar todos os possíveis problemas. Então você precisa do seu programa de travessia para pular recursing para os links simbólicos. Eu dei um +1 para o conhecimento no entanto!
n611x007

Eu tenho que concordar com Ramhound . Vendo como a pessoa que respondeu isso parece não estar disposta a fornecer uma solução completa, esperamos que outra pessoa forneça ambas em outra resposta para que esta possa ser removida. Além disso, não tenho certeza se o comentário sobre o cartaz sabotando seu sistema deve implicar que a maioria das instalações do Windows não permite que nenhuma ferramenta de listagem de diretório recorra aos pontos de junção WinVista +% userprofile% compatíveis com versões anteriores, mas na minha conta experimentar isso depende muito do aplicativo fazendo a recursão.
user66001

1

O original link simbólico para Application Datatem permissões especiais e atributos para evitar Everyonede ler ou a ver o conteúdo da pasta de destino (através do link simbólico ). Isso evita que os programas sejam capturados em um loop recursivo. Você pode reaplicar facilmente as permissões e os atributos, mas tenha muito cuidado para aplicar apenas essas permissões e atributos ao link simbólico e não a arquivos ou pastas reais. O link simbólico será um ícone no Windows Explorer com uma seta de atalho na parte superior de um ícone de pasta.

  1. Abra o Windows Explorer
  2. Toque na alttecla e clique em Ferramentas , em Opções e , em seguida, clique na guia Exibir
  3. Desative a opção [ ] Hide protected operating system filese ative a opção para (x) Show hidden files, folders, or drives.
  4. Navegar para C:\Users\[user]\AppData\Local
  5. Clique com o botão direito do mouse no Application Datalink simbólico e escolha Propriedades ( certifique-se de que ele seja o link simbólico e não uma pasta real - ele deve ter uma seta de atalho como uma sobreposição na parte superior de um ícone de pasta )
  6. Clique na guia Segurança , em Avançado e em Alterar Permissões
  7. Adicione Everyonee defina os direitos para Everyone:
    • Aplicar para = esta pasta somente ( <- isso é importante )
    • Permissões = Negar pasta List / ler dados ( <- isso interrompe a recursão )
  8. Clique em OK e, em seguida, clique em Sim para o aviso de que uma regra de negação é aplicada antes de uma regra de permissão
  9. Clique em OK novamente para aplicar as alterações
  10. Clique na guia Proprietário , clique em Editar e , em seguida, clique em Outros usuários ou grupos.
  11. Digite SYSTEMe continue clicando em OK até voltar ao Windows Explorer

A recursão está agora desativada. Há mais uma coisa que você pode querer fazer. A maioria desses tipos de links simbólicos tem atributos de arquivo especiais para que eles não sejam visíveis para os usuários. Abra um prompt de comando e execute os seguintes comandos:

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

A /Lopção diz attribpara aplicar +S +H +Iao link simbólico , em vez de aplicá-lo à pasta de destino ( C:\Users\[user]\AppData\Local).

Se você errar, poderá remover facilmente o link simbólico e recriá-lo em um prompt de comando . Tenha cuidado para recriar para que aponte para a mesma pasta que antes. O dir /acomando mostrará para onde Application Dataaponta. Você deve redigitar a pasta de destino textualmente como o parâmetro final do mklinkcomando.

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"

Agora você tem um Application Datalink simbólico que tem o problema de recursão. Então, basta seguir as etapas acima para corrigir o problema de recursão.

Não se esqueça de alterar as configurações na etapa 3 de volta para seus valores originais, para que você não continue vendo os arquivos que devem estar ocultos.


1

1. Use um script pequeno, então tudo será listado, mas as junções não serão seguidas.

Funciona bem no Windows 7, ao contrário da opção abaixo nesta resposta

vamos chamá-lo dnj.cmd(como em 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
)

Primeiro FOR / DIR para saída, segundo FOR / DIR para recursão. Dessa forma, você também pode ajustar os parâmetros de saída (especificamente, os argumentos DIR e ECHO). Por exemplo, se você deseja apenas uma lista simples de arquivos na saída sem diretórios, use

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

no lugar do primeiro FOR.

Invocando: dnj.cmdpath [path [...]]

O redirecionamento de saída funciona da mesma maneira que com o DIR convencional,

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

funciona a partir do prompt do Win + R ("Executar").

2. Se você estiver no Windows 10, use DIR / S / AL

Desta forma, junções não serão listadas, nem serão retornadas com / S. No Windows 7, o DIR / S / AD-L recorre a junções. Não tenho certeza sobre 8 / 8.1.

lote com saída para arquivo de texto:

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

(caminho de passagem e argumentos DIR adicionais como argumentos em lote)

cmd.exe para área de transferência (pode ser chamado via Win + R):

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

A área de transferência é unicode por padrão, mas sem o CHCP antecipadamente, a saída DIR está na página de códigos OEM, portanto, alguns caracteres podem ser perdidos. As cotações após / C são exigidas pela sintaxe do CMD, apesar de parecer estranho com cotações internas ao redor %USERPROFILE%.


1
Ótima sugestão. Seu 'dnj' falha se um diretório terminar em ')'. Eu acho que ele está funcionando corretamente:: listDir <caminho> (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

@trindflo obrigado por apontar isso. Eu acho que a expansão atrasada é mais lenta que a normal, então excluindo ECHO %%~Fde (... o )grupo funciona de maneira melhor.
LogicDaemon

0

De um prompt do CMD:

dir / A: -L / S / B

EDIT: Enquanto isso não irá listar a junção real no diretório que reside, ele irá recuar a junção.


Não funciona se você inicializar a partir de uma imagem do WinPE: ainda vejo o diretório "Application Data" repetir até que ele trave.
trindflo

0

Esse problema pode ser devido a permissões de recursão anti sendo removidas da pasta Application Data (como pode se aplicar a qualquer Windows Vista + ponto de junção criado para compatibilidade com versões anteriores).

Esses pontos de junção devem ter DENY para TODOS em permissões de Listar Pasta / Ler Dados, o que terá precedência sobre qualquer permissão ALLOW, e esperamos que não seja contornado por nenhum programa de recursão de diretório devido à maneira como ele acessa o sistema de arquivos.

De https://msdn.microsoft.com/en-us/library/windows/desktop/bb968829(v=vs.85).aspx , parece que os pontos de junção são identificados por ter o ReparsePointatributo, juntamente com os atributos Hiddene System.

O seguinte comando Powershell é a base do que parece ser uma solução mais simples para excluir pontos de junção de recursões de diretório do que qualquer resposta anterior.

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


0

No PowerShell 3.0, há um novo parâmetro Attribute:

Lista a estrutura de diretórios sem pastas de junção:

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

Lista pastas de junção apenas de uma estrutura de diretórios:

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

Mais informações: Use o PowerShell 3.0 para filtrar arquivos com base em atributos avançados


2
O parâmetro attribute parece testar a folha, não os diretórios pai. Ao usar Get-ChildItem -Attributes! ReparsePoint parece felizmente percorrer pontos de nova análise e ainda causar o erro "caminho muito longo".
Keith Twombley

0

No PowerShell,

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

Você pode simplesmente canalizar a saída para um arquivo se quiser salvá-lo.


Deve ser -Recursenão /Recurse Boa resposta embora.
Marty Neal

Isso não responde à pergunta ou resolve o problema. O OP colocou a parte mais importante como a questão em si e repetiu em negrito. "** sem recursão em pontos de junção **". Este comando será absolutamente recursivo em junções. Apenas não irá listar o link simbólico em uma linha por si só. Por exemplo: Com um link simbólico chamado "mysim" apontando para uma pasta com um arquivo chamado "myfile", a saída gerada não seria incluída, <path>\mysimmas seria recursiva e mostrada <path>\mysim\myfile.
Pilha de Panquecas

0

Isso pode não ser uma ferramenta nativa, mas pode ser útil para alguém com o Windows 7, há um programa chamado FileLocator Pro que tem uma opção em Advanced / Junction Points para desativar os pontos de junção de pesquisa.

Uma vez feito isso, você pode usar o programa de linha de comando flpsearch assim:

"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) 

Há guias literais lá depois dos ecos e delims, portanto, certifique-se de que o editor de texto não esteja convertendo guias em espaços.

Espero que isso possa ser útil para um usuário do Win7 ou dois.

Ofc as opções de powershell também são boas, mas o DOS é outra história.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.