1

Я знаю, что параметр -streams позволяет вам многое делать с альтернативными потоками данных, прикрепленными к файлам, но он не работает с папками и томами.

2 ответа2

2

Вроде работает. Здесь я добавляю объявление в «d:\», а затем удаляю его.

> 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:\'.

Предупреждение кажется неверным. В моем тестировании не было удалено ни одного ребенка, когда я указал "Y".

Осторожно: когда вы экспериментируете, убедитесь, что вы указали параметр -Stream в Remove-Item иначе вы можете удалить все на томе.

2
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

Все вышеперечисленные командлеты должны хорошо работать с альтернативными потоками данных, связанными с файлом, папкой или диском, если вы знаете имя потока. К сожалению, командлет Get-ChildItem отсутствует в списке, поскольку он не допускает параметр -Stream . С другой стороны, можно перечислить альтернативные потоки данных файла, используя Get-Item для FileSystem, который говорит о параметре -Stream :

Получает указанный альтернативный поток файлов NTFS из файла. Введите имя потока. Подстановочные знаки поддерживаются. Чтобы получить все потоки, используйте звездочку (*). Этот параметр недопустим для папок.

Без использования внешней утилиты, такой как streams.exe из Sysinternals, вы можете перечислить все альтернативные потоки данных в командной строке с помощью команды dir /R (Vista и выше) (и проанализировать вывод из . cmd /D /C dir /R в PowerShell),

К сожалению, dir /R не работает вместе с ключом /B Более того,

  • dir /R /A:-D возвращает все потоки (обычные файлы данных и имена ADS) для файлов,
  • dir /R /A:D  возвращает все потоки (имена папок и ADS) для папок, кроме корневой папки / диска,
  • dir /R       возвращает все имена (обычные и ADS) для файлов и папок, кроме корневой папки / диска.

Я написал два .BAT которые анализируют dir /R и могут форматировать вывод как CSV:

  • ADSdisk.bat [/CSVformat] возвращает имена ADS для всех активных (локальных) дисков и
  • ADSdir.bat [drive:][path][filename] [/S] [/A[[:]attributes]] [/CSVformat] возвращает только имена ADS, соответствующие DIR подобным параметрам.

Пример использования в 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:

@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:

@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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .