How to speed up Powershell Get-Childitem over UNC

前端 未结 4 2070
被撕碎了的回忆
被撕碎了的回忆 2020-11-28 10:33

DIR or GCI is slow in Powershell, but fast in CMD. Is there any way to speed this up?

In CMD.exe, after a sub-second delay, this responds a

4条回答
  •  不知归路
    2020-11-28 11:15

    Here's an interactive reader that parses cmd /c dir (which can handle unc paths), and will collect the 3 most important properties for most people: full path, size, timestamp

    usage would be something like $files_with_details = $faster_get_files.GetFileList($unc_compatible_folder)

    and there's a helper function to check combined size $faster_get_files.GetSize($files_with_details)

    $faster_get_files = New-Module -AsCustomObject -ScriptBlock {
        #$DebugPreference = 'Continue' #verbose, this will take figuratively forever
        #$DebugPreference = 'SilentlyContinue'
        $directory_filter = "Directory of (.+)"
        $file_filter = "(\d+/\d+/\d+)\s+(\d+:\d+ \w{2})\s+([\d,]+)\s+(.+)" # [1] is day, [2] is time (AM/PM), [3] is size,  [4] is filename
        $extension_filter = "(.+)[\.](\w{3,4})" # [1] is leaf, [2] is extension
        $directory = ""
        function GetFileList ($directory = $this.directory) {
            if ([System.IO.Directory]::Exists($directory)) {
                # Gather raw file list
                write-Information "Gathering files..."
                $files_raw = cmd /c dir $directory \*.* /s/a-d
    
                # Parse file list
                Write-Information "Parsing file list..."
                $files_with_details = foreach ($line in $files_raw) {
                    Write-Debug "starting line {$($line)}"
                    Switch -regex ($line) {
                        $this.directory_filter{
                            $directory = $matches[1]
                            break
                        }
                        $this.file_filter {
                            Write-Debug "parsing matches {$($matches.value -join ";")}"
                            $date     = $matches[1]
                            $time     = $matches[2] # am/pm style
                            $size     = $matches[3]
                            $filename = $matches[4]
    
                            # we do a second match here so as to not append a fake period to files without an extension, otherwise we could do a single match up above
                            Write-Debug "parsing extension from {$($filename)}"
                            if ($filename -match $this.extension_filter) {
                                $file_leaf = $matches[1]
                                $file_extension = $matches[2]
                            } else {
                                $file_leaf = $filename
                                $file_extension = ""
                            }
                            [pscustomobject][ordered]@{
                                "fullname"  = [string]"$($directory)\$($filename)"
                                "filename"  = [string]$filename
                                "folder"    = [string]$directory
                                "file_leaf" = [string]$file_leaf
                                "extension" = [string]$file_extension
                                "date"      = get-date "$($date) $($time)"
                                "size"      = [int]$size
                            }
                            break
                        } 
                    } # finish directory/file test
                } # finish all files
                return $files_with_details
            } #finish directory exists test
            else #directory doesn't exist {throw("Directory not found")}
        }
        function GetSize($files_with_details) {
            $combined_size = ($files_with_details|measure -Property size -sum).sum
            $pretty_size_gb = "$([math]::Round($combined_size / 1GB, 4)) GB"
            return $pretty_size_gb
        }
        Export-ModuleMember -Function * -Variable *
    }
    

提交回复
热议问题