以下代码为我提供了一个PSCustomObjects数组,如何让它返回一个字符串数组?
$files = Get-ChildItem $directory -Recurse | Select-Object FullName | Where-Object {!($_.psiscontainer)}
(作为第二个问题,什么是psiscontainer部分?我从网上的例子中复制了它)
接受后编辑:两个很棒的答案,希望我能同时标记它们。已经给出了原始答案。
答案 0 :(得分:34)
您只需从对象中挑选出您想要的属性即可。在这种情况下FullName
。
$files = Get-ChildItem $directory -Recurse | Select-Object FullName | Where-Object {!($_.psiscontainer)} | foreach {$_.FullName}
编辑:Mark的解释,他问道:“foreach做了什么?枚举的内容是什么?”
Sung Meister的解释非常好,但我会在这里添加一个演练,因为它可能会有所帮助。
关键概念是管道。想象一系列乒乓球一个接一个地滚下一根细管。这些是管道中的对象。管道的每个阶段 - 由管道(|)字符分隔的代码段 - 都有一个管道进入它,管道从它出来。一级的输出连接到下一级的输入。每个阶段在对象到达时对其进行处理,对它们执行操作,并将它们发送回输出管道或发送新的替换对象。
Get-ChildItem $directory -Recurse
Get-ChildItem遍历文件系统,创建FileSystemInfo对象,代表它遇到的每个文件和目录,并将它们放入管道。
Select-Object FullName
Select-Object在每个FileSystemInfo对象到达时获取它,从中获取FullName属性(在这种情况下是一个路径),将该属性放入它创建的全新自定义对象中,并将该自定义对象放入管道。
Where-Object {!($_.psiscontainer)}
这是一个过滤器。它需要每个对象,检查它,并将其发回或根据某些条件丢弃它。顺便说一句,这里的代码有一个bug。到达此处的自定义对象没有psiscontainer属性。这个阶段实际上并没有做任何事情。 Sung Meister的代码更好。
foreach {$_.FullName}
Foreach,其长名称为ForEach-Object,在它到达时抓取每个对象,并在此处从中获取FullName属性(字符串)。现在,这里是一个微妙的部分:任何未消耗的值,即未被变量捕获或以某种方式被抑制的值,都会被放入输出管道中。作为一项实验,尝试用以下方法替换该阶段:
foreach {'hello'; $_.FullName; 1; 2; 3}
实际上尝试一下并检查输出。该代码块中有四个值。它们都没有消耗掉。请注意,它们都出现在输出中。现在试试这个:
foreach {'hello'; $_.FullName; $ x = 1; 2; 3}
请注意,其中一个值正由变量捕获。它不会出现在输出管道中。
答案 1 :(得分:21)
要获取文件名的字符串,您可以使用
$files = Get-ChildItem $directory -Recurse | Where-Object {!($_.psiscontainer)} | Select-Object -ExpandProperty FullName
-ExpandProperty
参数允许您根据指定属性的类型返回对象。
进一步测试表明,这不适用于V1,但从V2 CTP3开始,该功能已得到修复。
答案 2 :(得分:8)
问题#1
我删除了“select-object”部分 - 它是多余的并且在“foreach”之前移动“where”过滤器而不像dangph's answer - 尽快过滤,这样你只处理你所拥有的一部分内容处理下一条管道。
$files = Get-ChildItem $directory -Recurse | Where-Object {!$_.PsIsContainer} | foreach {$_.FullName}
该代码段基本上是
请注意,对于 foreach {$ _。FullName} ,在powershell中,返回脚本块({...})中的最后一个语句,在本例中为$ _。FullName of type string
如果你真的需要获得一个原始对象,那么在删除“select-object”之后你不需要做任何事情。如果您要使用Select-Object但想要访问原始对象,请使用“PsBase”,这是一个完全不同的问题(主题) - 有关该主题的更多信息,请参阅“What's up with PSBASE, PSEXTENDED, PSADAPTED, and PSOBJECT?”
问题#2
并且还通过过滤!$ _。PsIsContainer 意味着您要排除容器级别对象 - 在您的情况下,您在 Get-ChildItem > FileSystem 提供程序(您可以通过Get-PsProvider查看PowerShell提供程序),因此容器是DirectoryInfo(文件夹)
PsIsContainer 在不同的PowerShell提供商下意味着不同的东西; 例如)对于 Registry 提供程序,PsIsContainer的类型为Microsoft.Win32.RegistryKey 试试这个:
>pushd HKLM:\SOFTWARE
>ls | gm
[更新] 以下问题: foreach做了什么?什么是枚举? 为了澄清,“foreach”是“Foreach-Object”的别名 你可以找到,
get-help foreach
- 或 -
get-alias foreach
现在在我的回答中,“foreach”枚举了从前一个管道返回的类型FileInfo的每个对象实例(具有已过滤的目录)。 FileInfo 有一个名为 FullName 的属性,这就是“foreach”所枚举的内容。
并且通过名为“$ _”的特殊管道变量引用通过管道传递的对象,该变量在“foreach”的脚本块上下文中是 FileInfo 类型。
答案 3 :(得分:4)
对于V1,将以下过滤器添加到您的个人资料中:
filter Get-PropertyValue([string]$name) { $_.$name }
然后你可以这样做:
gci . -r | ?{!$_.psiscontainer} | Get-PropertyName fullname
顺便说一句,如果你使用的是PowerShell Community Extensions,那么你已经拥有了这个。
关于在V2中使用Select-Object -Expand的能力,这是一个可爱的技巧但不明显,实际上不是Select-Object和-Expand的意思。 -Expand就像LINQ的SelectMany一样扁平化,Select-Object是关于将多个属性投影到自定义对象上。