Подтвердить что ты не робот

Как получить Select-Object для возврата необработанного типа (например, String), а не PSCustomObject?

Следующий код дает мне массив PSCustomObjects, как я могу заставить его вернуть массив строк?

$files = Get-ChildItem $directory -Recurse | Select-Object FullName | Where-Object {!($_.psiscontainer)}

(В качестве второстепенного вопроса, для чего нужна часть psiscontainer? Я скопировал это из примера в Интернете)

Редактирование после принятия: Два отличных ответа, хотелось бы отметить их обоих. Вы получили оригинальный ответ.

4b9b3361

Ответ 1

Вам просто нужно выбрать свойство, которое вы хотите от объектов. FullName в этом случае.

$files = Get-ChildItem $directory -Recurse | Select-Object FullName | Where-Object {!($_.psiscontainer)} | foreach {$_.FullName}

Изменить: Объяснение для Марка, который спрашивает: "Что делает foreach? Что это перечисляет?"

Объяснение Sung Meister очень хорошее, но я добавлю здесь пошаговое руководство, потому что это может быть полезно.

Ключевой концепцией является конвейер. Представьте серию шаров пинг-понга, катящихся по узкой трубке один за другим. Это объекты в конвейере. Каждый этап трубопровода - сегменты кода, разделенные символами трубопровода (|) - имеет трубу, входящую в нее, и труба выходит из нее. Выход одного этапа подключается к входу следующего этапа. Каждый этап принимает объекты по мере их поступления, делает что-то с ними и отправляет их обратно в выходной конвейер или отправляет новые объекты замены.

Get-ChildItem $directory -Recurse

Get-ChildItem просматривает файловую систему, создающую объекты FileSystemInfo, которые представляют каждый файл и каталог, с которыми он сталкивается, и помещает их в конвейер.

Select-Object FullName

Select-Object принимает каждый объект FileSystemInfo по мере поступления, захватывает из него свойство FullName (что в данном случае является путём), помещает это свойство в новый пользовательский объект, который он создал, и помещает этот пользовательский объект в трубопровод.

Where-Object {!($_.psiscontainer)}

Это фильтр. Он берет каждый объект, исследует его и отправляет обратно или отбрасывает его в зависимости от некоторого состояния. Кстати, у вашего кода есть ошибка. Пользовательские объекты, которые приходят сюда, не имеют свойства psiscontainer. Этот этап на самом деле ничего не делает. Код Sung Meister лучше.

foreach {$_.FullName}

Foreach, чье длинное имя ForEach-Object, захватывает каждый объект по мере его поступления и здесь захватывает свойство FullName, строку, из него. Теперь вот тонкая часть: любое значение, которое не потребляется, то есть не захватывается какой-либо переменной или не подавляется каким-либо образом, помещается в выходной конвейер. В качестве эксперимента попробуйте заменить этот этап следующим:

foreach {'hello'; $_.FullName; 1; 2; 3}

Собственно попробуйте и просмотрите вывод. В этом блоке кода есть четыре значения. Ни один из них не потребляется. Обратите внимание, что все они отображаются на выходе. Теперь попробуйте следующее:

foreach {'hello'; $_.FullName; $ x = 1; 2; 3}

Обратите внимание, что одно из значений захватывается переменной. Он не отображается в выходном конвейере.

Ответ 2

Чтобы получить строку для имени файла, вы можете использовать

$files = Get-ChildItem $directory -Recurse | Where-Object {!($_.psiscontainer)} | Select-Object -ExpandProperty FullName

Параметр -ExpandProperty позволяет вернуть объект в зависимости от типа указанного свойства.

Дальнейшее тестирование показывает, что это не работает с V1, но эта функциональность фиксирована как с V2 CTP3.

Ответ 3

Для вопроса # 1

Я удалил часть "select-object" - он избыточен и перемещен "where" фильтр перед "foreach" в отличие от dangph answer - отфильтруйте как можно скорее, чтобы вы имеете дело только с подмножеством того, что вам нужно иметь дело в следующей линии трубопровода.

$files = Get-ChildItem $directory -Recurse | Where-Object {!$_.PsIsContainer} | foreach {$_.FullName}

Этот фрагмент кода по существу читает

  • Рекурсивно получить полный путь всех файлов всех файлов (каталог Get-ChildItem $-Recurse)
  • Отфильтровать каталоги (Where-Object {! $_. PsIsContainer})
  • Возвращает только полное имя файла (foreach {$ _. FullName})
  • Сохранить все имена файлов в $files

Обратите внимание, что для foreach {$ _. FullName} в powershell возвращается последний оператор в блоке script ({...}), в этом случае $_. FullName строки типа

Если вам действительно нужно получить необработанный объект, вам не нужно ничего делать после избавления от "select-object". Если вы хотите использовать Select-Object, но хотите получить доступ к необработанному объекту, используйте "PsBase", что является совершенно другим вопросом (тема) - см. " Что с PSBASE, PSEXTENDED, PSADAPTED и PSOBJECT?" для получения дополнительной информации по этому вопросу

Для вопроса # 2

И также фильтрация с помощью! $_. PsIsContainer означает, что вы исключаете объекты уровня контейнера. В вашем случае вы делаете Get-ChildItem у поставщика FileSystem (вы можете видеть поставщиков PowerShell через Get-PsProvider), поэтому контейнер DirectoryInfo (папка)

PsIsContainer означает разные вещи у разных поставщиков PowerShell; например, для поставщика реестра, PsIsContainer имеет тип Microsoft.Win32.RegistryKey Попробуйте следующее:

>pushd HKLM:\SOFTWARE
>ls | gm

[ОБНОВЛЕНИЕ] к следующему вопросу: что делает foreach? Что это перечисляет? Чтобы уточнить, "foreach" - это псевдоним для "Foreach-Object", Вы можете узнать,

get-help foreach

- или -

get-alias foreach

Теперь в моем ответе "foreach" перечисляет каждый экземпляр объекта типа FileInfo, возвращенный из предыдущего канала (который отфильтровал каталоги). FileInfo имеет свойство FullName, и это то, что перечисляет "foreach" .
И вы ссылаетесь на объект, проходящий через конвейер через специальную переменную конвейера, называемую "$ _", которая имеет тип FileInfo в контексте блока script "foreach" .

Ответ 4

Для V1 добавьте в свой профиль следующий фильтр:

filter Get-PropertyValue([string]$name) { $_.$name }

Затем вы можете сделать это:

gci . -r | ?{!$_.psiscontainer} | Get-PropertyName fullname

Кстати, если вы используете Расширения сообщества PowerShell, у вас уже есть это.

Что касается возможности использования Select-Object -Expand в V2, это симпатичный трюк, но не очевидный и действительно не тот, для которого предназначался Select-Object или -Expand. -Expand - все о сглаживании, как LINQ SelectMany, а Select-Object - о проектировании нескольких свойств на пользовательский объект.