如何在UNC上加速Powershell Get-Childitem

b w*_*b w 16 powershell powershell-2.0

DIR或者GCI在Powershell中速度慢,但在CMD中速度很快.有什么方法可以加快速度吗?

在CMD.exe中,在亚秒延迟之后,响应速度与CMD窗口可以跟上的速度一样快

dir \\remote-server.domain.com\share\folder\file*.*
Run Code Online (Sandbox Code Playgroud)

在Powershell(v2)中,经过40秒以上的延迟,这会以明显的缓慢响应(可能每秒3-4行)

gci \\remote-server.domain.com\share\folder\file*.*
Run Code Online (Sandbox Code Playgroud)

我正在尝试扫描远程服务器上的日志,所以可能有更快的方法.

get-childitem \\$s\logs -include $filemask -recurse | select-string -pattern $regex
Run Code Online (Sandbox Code Playgroud)

b w*_*b w 17

好的,这就是我在做的事情,它似乎有效.

$files = cmd /c "$GETFILESBAT \\$server\logs\$filemask"
foreach( $f in $files ) {
    if( $f.length -gt 0 ) {
        select-string -Path $f -pattern $regex | foreach-object { $_ }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后$ GETFILESBAT指向这个:

@dir /a-d /b /s %1
@exit
Run Code Online (Sandbox Code Playgroud)

我正在编写并从PowerShell脚本中删除此BAT文件,因此我猜这是一个仅限PowerShell的解决方案,但它不仅使用PowerShell.

我的初步绩效指标显示这个速度要快十倍.

我测试了来自@Shawn Melton引用链接的 gci与cmd dir和FileIO.FileSystem.GetFiles .

最重要的是,对于本地驱动器的日常使用,GetFiles是最快的.到目前为止.CMD DIR很可敬.一旦你引入一个较慢的网络连接与许多文件,CMD DIR比稍快GetFiles.然后Get-ChildItem......哇,这个范围从不太糟糕到可怕,取决于所涉及的文件数量和连接速度.

一些测试运行.我在测试中移动了GCI,以确保结果一致.

扫描c:\windows\temp*.tmp文件的10次​​迭代

.\test.ps1 "c:\windows\temp" "*.tmp" 10
GetFiles ... 00:00:00.0570057
CMD dir  ... 00:00:00.5360536
GCI      ... 00:00:01.1391139
Run Code Online (Sandbox Code Playgroud)

GetFiles比CMD目录快10倍,它本身比GCI快2倍.

c:\windows\temp使用递归扫描*.tmp文件的10次​​迭代

.\test.ps1 "c:\windows\temp" "*.tmp" 10 -recurse
GetFiles ... 00:00:00.7020180
CMD dir  ... 00:00:00.7644196
GCI      ... 00:00:04.7737224
Run Code Online (Sandbox Code Playgroud)

GetFiles比CMD目录快一点,两者都比GCI快7倍.

扫描另一个域上的现场服务器以进行应用程序日志文件的10次迭代

.\test.ps1 "\\closeserver\logs\subdir" "appname*.*" 10
GetFiles ... 00:00:00.3590359
CMD dir  ... 00:00:00.6270627
GCI      ... 00:00:06.0796079
Run Code Online (Sandbox Code Playgroud)

GetFiles比CMD目录快2倍,本身比GCI快10倍.

扫描另一个域上的远程服务器以获取应用程序日志文件的一次迭代,涉及许多文件

.\test.ps1 "\\distantserver.company.com\logs\subdir" "appname.2011082*.*"
CMD dir  ... 00:00:00.3340334
GetFiles ... 00:00:00.4360436
GCI      ... 00:11:09.5525579
Run Code Online (Sandbox Code Playgroud)

CMD目录是使用许多文件进入远程服务器的最快速度,但GetFiles相当接近.另一方面,GCI慢了几千倍.

两次迭代扫描另一个域上的远程服务器以获取具有许多文件的应用程序日志文件

.\test.ps1 "\\distantserver.company.com\logs\subdir" "appname.20110822*.*" 2
CMD dir  ... 00:00:00.9360240
GetFiles ... 00:00:01.4976384
GCI      ... 00:22:17.3068616
Run Code Online (Sandbox Code Playgroud)

随着测试迭代的增加,或多或少线性增加.

一次迭代扫描另一个域上的远程服务器以获取应用程序日志文件,文件较少

.\test.ps1 "\\distantserver.company.com\logs\othersubdir" "appname.2011082*.*" 10
GetFiles ... 00:00:00.5304170
CMD dir  ... 00:00:00.6240200
GCI      ... 00:00:01.9656630
Run Code Online (Sandbox Code Playgroud)

这里的GCI并不算太差,GetFiles的速度提高了3倍,而且CMD目标也紧随其后.

结论

GCI需要一个-raw或一个-fast不试图这么做的选项.与此同时,它GetFiles是一个健康的替代品,偶尔会慢一点CMD dir,通常更快(由于产生CMD.exe?).

作为参考,这是test.ps1代码.

param ( [string]$path, [string]$filemask, [switch]$recurse=$false, [int]$n=1 )
[reflection.assembly]::loadwithpartialname("Microsoft.VisualBasic") | Out-Null
write-host "GetFiles... " -nonewline
$dt = get-date;
for($i=0;$i -lt $n;$i++){
  if( $recurse ){ [Microsoft.VisualBasic.FileIO.FileSystem]::GetFiles( $path,
      [Microsoft.VisualBasic.FileIO.SearchOption]::SearchAllSubDirectories,$filemask
    )  | out-file ".\testfiles1.txt"}
  else{ [Microsoft.VisualBasic.FileIO.FileSystem]::GetFiles( $path,
      [Microsoft.VisualBasic.FileIO.SearchOption]::SearchTopLevelOnly,$filemask
    )  | out-file ".\testfiles1.txt" }}
$dt2=get-date;
write-host $dt2.subtract($dt)
write-host "CMD dir... " -nonewline
$dt = get-date;
for($i=0;$i -lt $n;$i++){
  if($recurse){
    cmd /c "dir /a-d /b /s $path\$filemask" | out-file ".\testfiles2.txt"}
  else{ cmd /c "dir /a-d /b $path\$filemask" | out-file ".\testfiles2.txt"}}
$dt2=get-date;
write-host $dt2.subtract($dt)
write-host "GCI... " -nonewline
$dt = get-date;
for($i=0;$i -lt $n;$i++){
  if( $recurse ) {
    get-childitem "$path\*" -include $filemask -recurse | out-file ".\testfiles0.txt"}
  else {get-childitem "$path\*" -include $filemask | out-file ".\testfiles0.txt"}}
$dt2=get-date;
write-host $dt2.subtract($dt)
Run Code Online (Sandbox Code Playgroud)


Sha*_*ton 15

以下是Lee Holmes为什么Get-ChildItem变慢的一个很好的解释.如果您注意到页面底部"Anon 11 Mar 2010 11:11 AM"的评论,他的解决方案可能适合您.

Anon的代码:

# SCOPE: SEARCH A DIRECTORY FOR FILES (W/WILDCARDS IF NECESSARY)
# Usage:
# $directory = "\\SERVER\SHARE"
# $searchterms = "filname[*].ext"
# PS> $Results = Search $directory $searchterms

[reflection.assembly]::loadwithpartialname("Microsoft.VisualBasic") | Out-Null

Function Search {
  # Parameters $Path and $SearchString
  param ([Parameter(Mandatory=$true, ValueFromPipeline = $true)][string]$Path,
  [Parameter(Mandatory=$true)][string]$SearchString
  )
  try {
    #.NET FindInFiles Method to Look for file
    # BENEFITS : Possibly running as background job (haven't looked into it yet)

    [Microsoft.VisualBasic.FileIO.FileSystem]::GetFiles(
    $Path,
    [Microsoft.VisualBasic.FileIO.SearchOption]::SearchAllSubDirectories,
    $SearchString
    )
  } catch { $_ }

}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,您可以使用[`[System.IO.Directory] ​​:: EnumerateFiles()`](https://msdn.microsoft.com/en-us/library/system.io.directory.enumeratefiles(v = vs. 110).aspx)从PowerShell v3开始.该方法是在.Net Framework 4.0中引入的.这将使您不必加载VisualBasic程序集. (3认同)