2015-09-19 3 views
0

У меня есть сценарий powershell, который должен перемещаться по папкам и подпапкам указанного каталога. Как только на самом низком уровне (когда больше нет подпапок, а только файлы), он будет обрабатывать файлы. Для моего примера, давайте предположим, что у меня есть следующие папки и файлы:Ошибка при попытке навигации по папке, подпапкам и файлам

C: \ Temp \ filder1 \ file1.txt

C: \ Temp \ filder2 \ file2.txt

C: \ TEMP \ filder3 \ file3.txt

Проблема возникает, когда я пытаюсь перейти из папки нижнего уровня в файлы обработки в этой папке: $ files = Get-ChildItem $ folder. Кажется, что каким-то образом папка объекта преобразуется в просто строку с именем папки. Я получаю сообщение об ошибке, которое теперь использует мой путь по умолчанию пользователя с добавленным именем папки, который, конечно же, терпит неудачу, потому что теперь такая папка существует в моем пути по умолчанию. Ошибка - это что-то вроде:

Get-ChildItem: Не удается найти путь 'C: \ Users \ my.name \ Documents \ Powershell \ Powershell_Scripts \ folder1', потому что он не существует.

Путь я бы ожидать, это «C: \ Temp \ folder1»

Вот упрощенная версия моего сценария:

Param(
    [Parameter(Position = 1)] [string] $source_share_full_path = "c:\temp\" # path to a top-level share 
) 

$folders = Get-ChildItem $source_share_full_path 

#Loop through all the folders 
ProcessAllSubfolders($folders) 

function ProcessAllSubfolders($folderCollection) { 
    foreach ($folder in $folderCollection) 
    { 
     if ($folder.Subfolders.Count -gt 0) 
     { 
      ProcessAllSubfolders($folder.SubFolders) 
     } 
     else 
     { 
      Write-Output "`nReady to process files in a folder : $folder.FullName `n " 
      $files = Get-ChildItem $folder.FullName 
      ProcessFiles($files) 
     } 
    } 
} 

function ProcessFiles($files) { 
    foreach ($file in $files) 
    { 
     Write-Output "`nReady to process file: $file `n " 
    } 
} 

Кредит для метода навигации подпапки принадлежит here

Я ценю любые указатели!

+0

Для начала, 'Get-ChildItem' возвращает 'DirectoryInfo' для папки, и у них нет свойства' .Subfolders' (если только это не было новым в PowerShell 5?), Поэтому счетчик никогда не будет больше 0. Из этого, я думаю, вы тестируете только простейший случай с одним уровнем папки под c: \ temp? Кроме того, поскольку вы вызываете функции перед их определением, я предполагаю, что вы на самом деле запускаете тело функции из * предыдущего * запуска скрипта, где вы ввели '$ folder.Name', а затем скорректировали его? Я не вижу другой отличной возможности. – TessellatingHeckler

ответ

2

Как я заметил, но я конкретизация немного здесь:

  • папки, кажется, не имеет $folder.Subfolders свойства, поэтому подсчет вложенных папок никогда не будет работать, как задумано.
  • Вы вызываете функции перед их определением, которые не будут работать должным образом (первый запуск не выполняется с неизвестной функцией, следующий запуск будет использовать предыдущее определение, и если вы запускаете только сценарий, вызывая новый PowerShell сеанс, поэтому старое определение не останется в памяти, оно никогда не будет работать)
  • Функции вызова в PowerShell не используют () для параметров, например ProcessFiles($files) должно быть ProcessFiles $files
  • В строке $folders = Get-ChildItem $source_share_full_path вы вызываете результат $folders, но они не являются папками, они являются смешанными файлами и папками.
  • Вы записываете сообщения журнала («готов к обработке») в конвейер объекта. Вероятно, это не то, что вы хотите.

Если вам не нужно рекурсию вниз по папкам самостоятельно, или планируете вернуться в другие папки позже, как о чем-то вроде:

Param(
    [Parameter(Position = 1)] [string] $root_path = "c:\temp\" 
) 


$folders = Get-ChildItem $root_path -Directory -Recurse | 
       Where {$_.GetDirectories().Count -eq 0} 


foreach ($folder in $folders) { 

    $files = Get-ChildItem $folder.FullName -File 
    foreach ($file in $files) { 
     Write-Host "Ready to process file $($file.FullName)" 
    } 

} 
+1

Это прекрасно работает и так лаконично! Спасибо! –

2

Свойство SubFolders в примере, к которому вы ссылаетесь, относится только к папкам SharePoint - его нет в объектах FileSystemInfo, что и возвращает Get-ChildItem из поставщика файловой системы.

Вы можете использовать Get-ChildItem $Path -Directory, чтобы восстановить подкаталоги $Path и Get-ChildItem.

Вы также можете добавить атрибут CmdletBinding ваших функций и объявить параметры правильно:

function ProcessAllSubfolders { 

    [CmdletBinding()] 
    param(
     [Parameter(Position = 0)] 
     [System.IO.DirectoryInfo[]]$FolderCollection 
    ) 

    foreach ($Folder in $FolderCollection) 
    { 
     $SubFolders = @(Get-ChildItem $Folder.FullName -Directory) 

     if ($SubFolders.Count -gt 0) 
     { 
      ProcessAllSubfolders -FolderCollection $SubFolders 
     } 
     else 
     { 
      Write-Verbose "Ready to process files in a folder : $($Folder.FullName)" 
      $Files = Get-ChildItem $folder.FullName 
      ProcessFiles $files 
     } 
    } 
} 

function ProcessFiles { 

    [CmdletBinding()] 
    param(
     [Parameter(Position = 0)] 
     [System.IO.FileInfo[]]$Files 
    ) 

    foreach ($File in $Files) 
    { 
     Write-Verbose "Ready to process file: $File" 
     # Do your processing on $File here 
    } 
} 

Теперь вы можете вызвать ProcessAllSubfolders с -Verbose переключатель, если вы сообщения на консоль:

$InitialFolders = Get-ChildItem $SourcePath -Directory 

#Loop through all the folders 
ProcessAllSubfolders -FolderCollection $InitialFolders 

Сохраните сценарий, и вуаля:

PS C:\> ProcessFiles.ps1 -Verbose 
VERBOSE: Ready to process files in a folder : C:\temp\text\x 
VERBOSE: Ready to process file: n_238633.log 
VERBOSE: Ready to process file: n_895226.log 
+0

Спасибо большое! Я отметил другой комментарий как ответ, потому что он настолько изящный и лаконичный, но ваш тоже замечательный, особенно объяснение правильного способа объявления типов параметров в функциях. –

Смежные вопросы