Powershell提取内存消耗

时间:2019-05-23 17:55:34

标签: powershell csv scripting extract ram

我已经完成了一个小项目,该项目将从文件服务器中提取一些信息。为了执行该项目,我创建了一个脚本,该脚本在.csv文件中输出所有信息。问题在于Powershell在此过程中吞噬了我所有计算机的RAM,因为要解析的数据可能高达数百Gb。

这是我的剧本。

$folder = Get-ChildItem -Recurse 'Complete_Path' | select FullName, @{Name="Owner";Expression={(Get-Acl $_.FullName).Owner}}, CreationTime, LastWriteTime, LastAccessTime, PSIsContainer | sort FullName
$output = @()

$folder | foreach {

$type =

if ($_.PSIsContainer -eq "True") {


    Write-Output "Folder"

        }
else {


    Write-Output "File"

}


$size =

if ($_.PSIsContainer -eq "True") {

   Get-ChildItem -Recurse $_.FullName | measure -Property Length -Sum -ErrorAction SilentlyContinue | select -ExpandProperty Sum


        }
else {


    Get-Item $_.FullName | measure -Property Length -Sum -ErrorAction SilentlyContinue | select -ExpandProperty Sum

}


$hash = @{


FullName = $_.FullName
Owner = $_.Owner
CreationTime = $_.CreationTime
LastWriteTime = $_.LastWriteTime
LastAccessTime = $_.LastAccessTime
Type = $type
'Size in MB' = [math]::Round($($size/1Mb),2)

}

$output += New-Object PSObject -Property $hash
}

$output | select FullName, Owner, CreationTime, LastWriteTime, LastAccessTime, Type, 'Size in MB' | Export-Csv C:\myDOCS.csv -Delimiter ";" -NoTypeInformation -Encoding UTF8

你们是否知道我如何更快地完成工作并减少耗油量?提取可能需要几天的时间。

谢谢。

2 个答案:

答案 0 :(得分:0)

  • 使用.Net PSObject列表$output=@()替换Powershell阵列$output = [System.Collections.Generic.List[psobject]]::new(),并使用该对象的 .Add 方法添加您的物品。

    对于较小的列表,您不会注意到,但是使用Powershell数组和 + = 运算符是很大的性能下降。每次您执行+ =时,都会再创建一个数组,以完全重新创建数组。

  • 在您的初始Get-ChildItem语句中包含长度。稍后,您可以测量总和,而不必一直都通过Get-ChildItem

  • 管道在内存上的播放效果不错,但总体运行速度较慢。当性能成为问题时,我倾向于不使用管道。

这样的事情应该已经快得多了

$folder = Get-ChildItem -Recurse "$($env:USERPROFILE)\Downloads" | select FullName, @{Name = "Owner"; Expression = { (Get-Acl $_.FullName).Owner } }, CreationTime, LastWriteTime, LastAccessTime, PSIsContainer, Length | sort FullName
$output = [System.Collections.Generic.List[psobject]]::new()

foreach ($Item in $folder) {
    if ($Item.PSIsContainer) {
        $Type = 'Folder'
        $size = $folder.Where( { $_.FullName -like $item.FullName }).FullName | measure -Property Length -Sum -ErrorAction SilentlyContinue | select -ExpandProperty Sum
    }
    else {
        $Type = 'File'
        $size = $Item.Length
    }
    $size = [math]::Round($($size / 1Mb), 2)

    $hash = @{
        FullName       = $Item.FullName
        Owner          = $Item.Owner
        CreationTime   = $Item.CreationTime
        LastWriteTime  = $Item.LastWriteTime
        LastAccessTime = $Item.LastAccessTime
        Type           = $Type
        'Size in MB'   = $size
    }
    [void]($output.Add((New-Object PSObject -Property $hash)))
}


$output | select FullName, Owner, CreationTime, LastWriteTime, LastAccessTime, Type, 'Size in MB' | Export-Csv C:\myDOCS.csv -Delimiter ";" -NoTypeInformation -Encoding UTF8
  • 您仍然可以改进大小计算,因此首先计算最深的文件夹大小,然后父文件夹可以获取该值并汇总子文件夹,而无需重新计算文件

  • 另一种想法是不立即执行Get-ACl(我怀疑这执行起来很慢)并获取您的项目,执行其余操作,然后并行化Get-ACL,以便您可以在多个并行线程,并将其添加到列表中。

考虑对小批代码进行测试,然后使用Measure-Command来确定代码中最慢的操作在哪里。

我建议您看看有关该主题的一些更高级的主题。 这是一篇很好的入门指南:Slow Code: Top 5 ways to make your Powershell scripts run faster

答案 1 :(得分:0)

在一个管道中处理整个事情是否更好?

Get-ChildItem -Recurse |
select FullName, @{Name="Owner";Expression={(Get-Acl $_.FullName).Owner}},
CreationTime, LastWriteTime, LastAccessTime, PSIsContainer | sort FullName |

foreach {

  $type =
  if ($_.PSIsContainer -eq "True") {
      Write-Output "Folder"
  }
  else {
      Write-Output "File"
  }

  $size =
  if ($_.PSIsContainer -eq "True") {
     Get-ChildItem -Recurse $_.FullName | 
       measure -Property Length -Sum -ErrorAction SilentlyContinue |
       select -ExpandProperty Sum
  }
  else {
      Get-Item $_.FullName | 
        measure -Property Length -Sum -ErrorAction SilentlyContinue |
        select -ExpandProperty Sum
  }

  $hash = @{
    FullName = $_.FullName
    Owner = $_.Owner
    CreationTime = $_.CreationTime
    LastWriteTime = $_.LastWriteTime
    LastAccessTime = $_.LastAccessTime
    Type = $type
    'Size in MB' = [math]::Round($($size/1Mb),2)
  }

  New-Object PSObject -Property $hash
} | select FullName, Owner, CreationTime, LastWriteTime, LastAccessTime,
Type, 'Size in MB' | 
Export-Csv myDOCS.csv -Delimiter ";" -NoTypeInformation -Encoding UTF8