运行Get-ChildItem-Exclude时遇到一个奇怪的问题。
在运行了一个副本并比较了这两个目录之后,我一直在源位置和目标位置使用以下命令来创建一个文件阵列。它一直运行得很好。(我本来打算发布图片,但没有足够高的声誉)
$sourcefiles = @(Get-ChildItem -Recurse -path e:Homeo365.test)
当我运行此命令时,数组将填充文件的短名称。
我从文件副本中排除了PST文件,我还需要在比较中排除它们,所以我在GCI命令中添加了一个排除。
$sourcefiles = @(Get-ChildItem -Recurse -path e:Homeo365.test -Exclude *.pst)
这会返回所有正确的文件(*.pst实际上被排除在外),但它返回的是文件的全名,而不是我以前总是返回的短名称。
这导致比较对象失败,因为目标GCI没有排除(由于*.pst已从副本中排除,因此不需要)。此外,它是一个UNC路径,而且全名无论如何都不匹配。
我意识到我可以使用分路径叶子(我已经尝试过了,而且似乎有效)
$sourcefiles = @(Get-ChildItem -Recurse -path e:Homeo365.test -Exclude *.pst | Split-Path -Leaf)
但我仍然不明白为什么在GCI中添加-exclude参数会导致它更改返回的格式。
有人知道为什么会发生这种情况吗?
提前感谢您的帮助!
好吧,我无法复制您在这里看到的内容。在PowerShell中,将at符号放在操作之前实际上就是数组运算符,简单地说,将其放在带有操作的括号之前不会像您描述的那样返回单个属性。
现在,如果在括号后面放置一个属性名称,只选择一个属性,就可以实现这一点。例如:
$files = @(Get-ChildItem -path c:temp).BaseName
>LZelda.csv
>msvcr100.dll
>names-0.txt
>names-1.txt
>NOBGW00017.log
>nslookup.exe
>PolicySpy.exe
添加-Exclude括号根本不会更改输出。
$files = @(Get-ChildItem -path c:temp -exclude *.png)
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 3/18/2015 2:34 PM Android
da---- 9/10/2013 7:17 PM Bootfiles
d----- 12/13/2014 4:29 PM camera
d----- 1/6/2015 11:49 AM CFS
d----- 12/11/2014 1:08 PM ebay
d----- 2/2/2014 1:55 PM Finance
我向您展示这一点的原因是,我们得到的东西仍然是FileSystem对象。将$files减少为只包含一个属性的唯一方法,如FullName、BaseName或以下两种方法中的任何属性:
$files = @(Get-ChildItem -path c:temp -exclude *.png).BaseName
$files = @(Get-ChildItem -path c:temp -exclude *.png | Select -Expand BaseName)
两者将给出相同的输出。
这里的问题是故意的"bug";(我称之为)从Powershell开始就引入了(或者至少从PS2.0开始)。为了简化从cmd
到Powershell的转换,Get-ChildItem
被赋予了别名dir
,然后像dir
的cmd
版本一样工作(只要有必要,就可以提供类似的输出)。与cmd
一样,
PS > dir <directory path>
产生<目录路径>(当简单显示时)。在这两种情况下(cmd
和Powershell),都会使用不存在的目录路径。(当前目录)。但是,如果cmd
版本是在目录路径之后使用文件名或通配符模式调用的(同样是隐式的。如果没有目录路径),则输出是该目录中的匹配文件(以及通配符情况下的目录)(如果有)。Get-ChildItem
也这样做,所以别名dir
给出类似的输出。当提供通配符路径时,Get-ChildItem
可能会返回与该通配符路径匹配的任何目录的子目录的列表,并忽略任何匹配的文件。如果参数是纯文件名,Get-ChildItem
会抱怨提供的参数不能有子目录(而不是空目录,可以有子目录,但没有)。毕竟,如果您想匹配文件或目录本身(而不是它们的内容),您应该使用Get-Item
。事实上,在文件参数和通配符的情况下,Get-ChildItem
返回的结果与等效的Get-Item
相同。然而,Get-ChildItem
为指定目录路径的实际子级返回的结果与Get-Item
的结果略有不同。具体来说,它们有不同的ToString()
方法(即使它们都返回FileInfo或DirectoryInfo对象)。这意味着通过显式调用ToString()
或在需要字符串的表达式中使用返回的对象(例如)将对象转换为字符串
PS > dir | foreach { "$_" }
给出了不同的结果。演示,
PS > gci C:WindowsWebScreen | foreach { "$_" }
img100.jpg
img101.png
img102.jpg
img103.png
img104.jpg
img105.jpg
PS > gci C:Windowswebscreen* | foreach { "$_" }
C:Windowswebscreenimg100.jpg # note: uses argument path case.
C:Windowswebscreenimg101.png # actual directory path case is
C:Windowswebscreenimg102.jpg # C:WINDOWSWebScreen
C:Windowswebscreenimg103.png
C:Windowswebscreenimg104.jpg
C:Windowswebscreenimg105.jpg
PS > gi C:WindowsWebscreen* | foreach { "$_" }
C:WindowsWebscreenimg100.jpg
C:WindowsWebscreenimg101.png
C:WindowsWebscreenimg102.jpg
C:WindowsWebscreenimg103.png
C:WindowsWebscreenimg104.jpg
C:WindowsWebscreenimg105.jpg
PS > gci C:WindowsWebscreenimg100.jpg | foreach { "$_" }
C:WindowsWebscreenimg100.jpg
PS > gi C:WindowsWebscreenimg100.jpg | foreach { "$_" }
C:WindowsWebscreenimg100.jpg
因此,我怀疑OP正在使用隐式字符串转换来获得";name";文件和运行犯规";bug";当使用CCD_ 20时(独立于没有效果的CCD_。解决方案是不依赖于字符串转换,而是使用实际的字符串属性,无论是名称还是全名(以需要的为准)。
PS > gci C:WindowsWebScreen | foreach { "$($_.fullname)" }
C:WindowsWebscreenimg100.jpg
C:WindowsWebscreenimg101.png
C:WindowsWebscreenimg102.jpg
C:WindowsWebscreenimg103.png
C:WindowsWebscreenimg104.jpg
C:WindowsWebscreenimg105.jpg
PS > gci C:Windowswebscreen* | foreach { "$($_.name)" }
img100.jpg
img101.png
img102.jpg
img103.png
img104.jpg
img105.jpg
另一种(长期)解决方案可以是修复Get-ChildItem
,使ToString()
始终返回相同的结果。这可能被认为是一个突破性的变化,但我怀疑这";bug";已经绊倒了许多用户,甚至那些已经意识到这一点的用户。我知道我一直在忘记。甚至可以让Get-Item
和Get-ChildItem
使用相同的ToString()
,无论是哪一个
对于一个激进的(并且可能引发推论的)解决方案;"修复";Get-ChildItem
仅返回子级(或错误),并使dir
成为根据需要调用Get-ChildItem
或Get-Item
的函数。这将恢复Powershell的";cmdlet按照他们的名字所说的去做"而不是CCD_ 31有时返回子项,有时返回项目。(太大的突破性变化了,所以我没有屏住呼吸。)
使用PS 5.1.1836.2145进行的试验。