Há algum commandlets no Power Shell para gerenciar fluxos de dados alternativos que estão anexados a pastas e volumes?

1

Eu sei que o parâmetro -streams permite que você faça muito com fluxos de dados alternativos anexados aos arquivos, mas não funciona em pastas e volumes.

    
por Euretta Wilson 09.03.2017 / 15:42

2 respostas

2

Parece funcionar. Aqui eu adiciono um ADS a "d:" e excluo-o.

> Set-Content -Path d:\ -Value "Hello, World" -Stream Fred
> Get-Content -Path d:\ -Stream Fred
Hello, World
> Remove-Item -Path d:\ -Stream Fred

Confirm
The item at D:\ has children and the Recurse parameter was not specified. If you continue, all children will be removed with the item. Are you sure you want to continue?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): y

E:\scratch\st> Get-Content -Path d:\ -Stream Fred
Get-Content : Could not open the alternate data stream 'Fred' of the file 'D:\'.

O aviso parece estar incorreto. Nenhuma criança foi removida no meu teste quando eu especifiquei "Y".

Cuidado: Quando você experimentar, certifique-se de especificar o parâmetro -Stream no Remove-Item , caso contrário você pode excluir tudo no volume.

    
por 13.03.2017 / 03:05
1
PS D:\PShell> Get-Command -All -ParameterName 'stream' | Format-Table -AutoSize -Wrap

CommandType Name          ModuleName                     
----------- ----          ----------                     
Cmdlet      Add-Content   Microsoft.PowerShell.Management
Cmdlet      Clear-Content Microsoft.PowerShell.Management
Cmdlet      Get-Content   Microsoft.PowerShell.Management
Cmdlet      Get-Item      Microsoft.PowerShell.Management
Cmdlet      Out-String    Microsoft.PowerShell.Utility   
Cmdlet      Remove-Item   Microsoft.PowerShell.Management
Cmdlet      Set-Content   Microsoft.PowerShell.Management

Todos os cmdlet acima devem funcionar bem com fluxos de dados alternativos associados a um arquivo, uma pasta ou um disco se você souber um nome de fluxo . Infelizmente, Get-ChildItem cmdlet não está listado, pois não permite o parâmetro -Stream . Por outro lado, pode-se enumerar fluxos de dados alternativos arquivo usando Get-Item para FileSystem que diz sobre o parâmetro -Stream :

Gets the specified alternate NTFS file stream from the file. Enter the stream name. Wildcards are supported. To get all streams, use an asterisk (*). This parameter is not valid on folders.

Sem usar um utilitário externo como streams.exe do Sysinternals , você pode enumerar todos os dados alternativos fluxos de dados na linha de comando usando o comando dir /R (Vista e superior) (e analisar a saída de . cmd /D /C dir /R no PowerShell ).

Infelizmente, dir /R não funciona junto com a opção /B . Além disso,

  • dir /R /A:-D retorna todos os fluxos (arquivos de dados regulares e nomes de anúncios) para arquivos,
  • dir /R /A:D  retorna todos os fluxos (nomes de pasta e ADS) para pastas, exceto pasta / disco raiz,
  • dir /R       retorna todos os nomes (regulares e ADSs) para arquivos e pastas exceto pasta / disco raiz .

Escrevi dois scripts .BAT que analisam dir /R e podem formatar a saída como CSV :

  • ADSdisk.bat [/CSVformat] retorna nomes de anúncios para todos os discos ativos (locais) e
  • ADSdir.bat [drive:][path][filename] [/S] [/A[[:]attributes]] [/CSVformat] retorna apenas os nomes de anúncios correspondentes aos parâmetros DIR .

Exemplo de uso no PowerShell :

PS D:\PShell> . D:\bat\ADSdisk.bat /CSVformat
"streamName",streamSize,"filePath"
"ADS_disk_root.txt",36,"D:\"
# comment:    ADS on D:\ "..:ADS_disk_root.txt:$DATA" 
# comment: no ADS on F:\
# comment: no ADS on C:\
# comment: no ADS on E:\

PS D:\PShell> (. D:\bat\ADSdisk.bat /CSVformat) | ConvertFrom-Csv

streamName                 streamSize                 filePath                 
----------                 ----------                 --------                 
ADS_disk_root.txt          36                         D:\                      



PS D:\PShell> (. D:\bat\ADSdir.bat d:\ba* /CSVformat) | ConvertFrom-Csv

streamName                 streamSize                 filePath                 
----------                 ----------                 --------                 
alternate.data.stream.txt  46                         d:\BAsoftwarelist.csv    
alternate.data.stream.txt  23                         d:\bat                   
PShell.txt                 34                         d:\bat                   
star.bat                   12                         d:\bat                   
star.txt                   23                         d:\bat                   



PS D:\PShell> 

ADSdisk.bat script :

@ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
set "_keyword=Directory"
set "_CSVformat="
set "_firstLine="
set  _filePath=%*
if defined _filePath (
    for %%G in ( %_filePath% ) do (
        if /I %%G == /CSVformat (
            set _filePath=%_filePath:/CSVformat=%
            set "_CSVformat=/CSVformat"
        )
    )  
)
set "_property=DeviceID^,DriveLetter^,DriveType^,FileSystem^,SystemName"
for /F "skip=1 tokens=1-4,*" %%G in ('
  wmic volume where "FileSystem LIKE '_%%' and DriveLetter LIKE '_:'" get %_property%
  ') do (
    if not "%%H"=="" (
      rem echo(# comment: %%H %%I %%J %%G
      set "_subFolder="
      set "_subDisk=%%~H\"
      for /F "delims=" %%g in ( 'dir /B /A:D /A /O:-N "%%~H\"') do set "_subFolder=%%~g"
      if defined _subFolder (
          call :findADSroot
          if not defined _fileName (
            call echo(# comment: no ADS on %%_subDisk%%
          ) else (
            call echo(# comment:    ADS on %%_subDisk%% "%%_fileName%%" 
          )
      ) else (
          echo(# comment: no subfoler under "%%~H\" 
      ) 
    )
)

ENDLOCAL
goto :eof

:findADSroot
set "_pass="
set "_filePath=%_subDisk%%_subFolder%"
rem echo(# comment: ===testing=== "%_filePath%\"
set "_fileName="
for /F "tokens=1,*" %%G in ('
        dir /-C /R /S /A "%_filePath%" ^| findstr /I /R "\.\.:.*:\$DATA ^.%_keyword%"
        ') do (
  set "_fileSize="
  if "%%~G"=="%_keyword%" (
      if defined _pass goto :eof
      for /F "tokens=1,*" %%g in ("%%~H") do set "_fileRoot=%%~h"
      set /A _pass +=1
  ) else (
      set "_fileSize=%%~G"
      set "_fileName=%%~H"
  )
  if defined _fileSize call :outputDisk
)
goto :eof

:outputDisk
  if defined _CSVformat (
      REM csv output:         
      if not defined _firstLine echo "streamName",streamSize,"filePath"
      for /F "tokens=1-3 delims=:" %%g in ("%_fileName%") do (
          echo "%%~h",%_fileSize%,"%_subDisk%"
      )
  ) else (
      REM alternative output: streamSize,"streamFullPath"
      echo %_fileSize% "%_subDisk%%_fileName:~2%"
  )
  set /A _firstLine += 1
goto :eof

ADSdir.bat script :

@ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
set "_keyword=Directory"
set "_CSVformat="
set "_firstLine="
set  _filePath=%*
if defined _filePath (
    for %%G in ( %_filePath% ) do (
        if /I %%G == /CSVformat (
            set _filePath=%_filePath:/CSVformat=%
            set "_CSVformat=/CSVformat"
        )
    )  
)
if not defined _filePath set "_filePath=/S "%CD%""
call :findADS

ENDLOCAL
goto :eof


:findADS
for /F "tokens=1,*" %%G in ('
        dir /-C /R %_filePath% ^| findstr /I /R ":.*:\$DATA ^.%_keyword%"
        ') do (
  set "_fileSize="
  if "%%~G"=="%_keyword%" (
      for /F "tokens=1,*" %%g in ("%%~H") do set "_fileRoot=%%~h"
      call :backslash
  ) else (
      set "_fileSize=%%~G"
      rem for /F "tokens=1,*" %%g in ("%%~G") do 
      set "_fileName=%%~H"
      call :testdots
  )
  if defined _fileSize call :output 
)
goto :eof

:backslash
  set "_backslash=%_fileRoot:~-1%"
  if "%_backslash%"=="\" (set "_backslash=") else set "_backslash=\"
  rem echo %~0 %_fileRoot:~-1%==%_backslash%
  rem pause
goto :eof

:testdots
  rem                    "." = a folder itself
  if "%_fileName:~0,2%"==".:"  set "_fileSize="
  rem                    ".." = parent folder
  if "%_fileName:~0,3%"=="..:" set "_fileSize="
goto :eof

:output
  if defined _CSVformat (
      REM csv output:         
      if not defined _firstLine echo "streamName",streamSize,"filePath"
      for /F "tokens=1-3 delims=:" %%g in ("%_fileName%") do (
          echo "%%~h",%_fileSize%,"%_fileRoot%%_backslash%%%~g"
      )
  ) else (
      REM alternative output: streamSize,"streamFullPath"
      echo %_fileSize% "%_fileRoot%%_backslash%%_fileName%"
  )
  set /A _firstLine += 1
goto :eof
    
por 13.03.2017 / 20:15