【问题标题】:PowerShell Invoke-Command severe performance issuesPowerShell Invoke-Command 严重的性能问题
【发布时间】:2018-02-28 17:52:18
【问题描述】:

我在远程系统上高效地运行脚本有一段很长的时间。在本地运行时,该命令需要 20 秒。使用Invoke-Command 运行该命令需要 10 或 15 分钟 - 即使“远程”计算机是我的本地计算机。

有人可以向我解释这两个命令之间的区别以及为什么 Invoke-Command 需要这么长时间吗?

在 MACHINE 上本地运行:get-childitem C:\ -Filter *.pst -Recurse -Force -ErrorAction SilentlyContinue

在 \MACHINE 上远程运行(表现相同,而 MACHINE 是我的本地机器或远程机器:invoke-command -ComputerName MACHINE -ScriptBlock {get-childitem C:\ -Filter *.pst -Recurse -Force -ErrorAction SilentlyContinue}

注意:该命令返回5个文件对象

编辑:我认为部分问题可能是重解析点。在本地运行时get-childitem(和DIR /a-l)不要跟随连接点。当远程运行时,即使我使用-attributes !ReparsePoint 开关,它们也会这样做)

EDIT2:但是,如果我运行命令 invoke-command -ComputerName MACHINE -ScriptBlock {get-childitem C:\ -Attributes !ReparsePoint -Force -ErrorAction SilentlyContinue},我看不到连接点(即文档和设置)。因此,很明显DIR /a-lget-childitem -attributes !ReparsePoint 都不会阻止它递归到重解析点。相反,它似乎只过滤实际条目本身。

非常感谢!

【问题讨论】:

  • `-Recurse -Path C:` 这是你的问题。您正在遍历整个驱动器中的所有对象。
  • @TheIncorrigible1 本地与远程有何不同? Appleoddity - 你真的没有将任何凭据传递给调用命令吗?我想远程连接具有管理员权限,因此必须查看和搜索比本地更多的文件夹,但这仍然是一个很大的区别。
  • @TheIncorrigible1 - 这是故意的。在本地,SSD 需要 20 秒。远程需要 10 分钟或更长时间。
  • @TessellatingHeckler - 这些是我从 Powershell ISE 窗口运行的确切命令。我的帐户是域管理员。我确实注意到通过调用命令运行的 get-childitem 遵循连接点(即文档和设置),而在本地运行的 get-childitem 在到达连接点时会给出错误(没有静默继续开关)。这可能是一个原因吗?
  • @Appleoddity 您的 ISE 进程是否以管理员身份启动?

标签: powershell scripting remote-access


【解决方案1】:

看来问题是重解析点。由于某种原因,当命令在本地运行时,访问被拒绝重新解析点(如Documents and Settings)。远程运行命令后,DIRGet-ChildItem 都将递归到重解析点。

-Attributes !ReparsePoint 用于get-childitem/a-l 开关用于DIR 并不能阻止这种情况。相反,这些开关似乎只会阻止重解析点出现在文件列表输出中,但不会阻止命令递归到这些文件夹中。

相反,我必须编写一个递归脚本并自己进行目录递归。在我的机器上它有点慢。而不是本地大约 20 秒,而是大约 1 分钟。远程花费了将近 2 分钟。

这是我使用的代码: 编辑:由于 PowerShell 2.0、PowerShell 远程处理和原始代码的内存使用存在所有问题,我不得不更新我的代码,如下所示。

function RecurseFolder($path) {

    $files=@()

    $directory = @(get-childitem $path -Force -ErrorAction SilentlyContinue | Select FullName,Attributes | Where-Object {$_.Attributes -like "*directory*" -and $_.Attributes -notlike "*reparsepoint*"})
    foreach ($folder in $directory) { $files+=@(RecurseFolder($folder.FullName)) }

    $files+=@(get-childitem $path -Filter "*.pst" -Force -ErrorAction SilentlyContinue | Where-Object {$_.Attributes -notlike "*directory*" -and $_.Attributes -notlike "*reparsepoint*"})

    $files
}

【讨论】:

    【解决方案2】:

    我遇到了同样的问题。 很明显Powershell通过PSRemoting传递数组有问题。

    它演示了这个小实验(已更新):

    $session = New-PSSession localhost
    
    $arrayLen = 1024000
    Measure-Command{
      Invoke-Command -Session $session -ScriptBlock {
        Write-Host ("Preparing test array {0} elements length..." -f $using:arrayLen)
        $global:result = [Byte[]]::new($using:arrayLen)
        [System.Random]::new().NextBytes($result)
      }
    } |% {Write-Host ("Completed in {0} sec`n" -f $_.TotalSeconds)}
    
    Measure-Command{
      Invoke-Command -Session $session -ScriptBlock {
        Write-Host ("Transfer array ({0})" -f $using:arrayLen)
        return $result
      } | Out-Null
    } |% {Write-Host ("Completed in {0} sec`n" -f $_.TotalSeconds)}
    
    Measure-Command{
      Invoke-Command -Session $session -ScriptBlock {
        Write-Host ("Transfer same array nested in a single object")
        return @{array = $result}
      } 
    } |% {Write-Host ("Completed in {0} sec`n" -f $_.TotalSeconds)}
    

    我的输出(以毫秒为单位的时间):

    Preparing test array 1024000 elements length...
    Completed in 0.0211385 sec
    
    Transfer array (1024000)
    Completed in 48.0192142 sec
    
    Transfer same array nested in a single object
    Completed in 0.0990711 sec
    

    如您所见,数组传输超过一分钟。 单个对象在几秒钟内传输,尽管它们的大小

    【讨论】:

      【解决方案3】:

      尝试使用远程会话:

      $yourLoginName = 'loginname'
      $server        = 'tagetserver'
      $t = New-PSSession $server -Authentication CredSSP -Credential (Get-Credential $yourLoginName)
      cls
      "$(get-date) - Start"
      $r = Invoke-Command -Session $t -ScriptBlock{[System.IO.Directory]::EnumerateFiles('c:\','*.pst','AllDirectories')}
      "$(get-date) - Finish"
      

      【讨论】:

      • 我将-authentication 更改为Kerberos,因为我没有启用CredSSP。脚本块有效,但它仍然枚举重解析点并花费过多的时间。
      【解决方案4】:

      如果它是一个大型目录结构,并且您只需要文件的完整路径名,您应该能够通过使用旧的dir 命令而不是Get-ChildItem 来大大加快速度:

      invoke-command -ComputerName MACHINE -ScriptBlock {cmd /c dir c:\*.pst /s /b /a-d /a-l}
      

      【讨论】:

      • 这给了我希望,但我尝试了一下,得到了相同的结果。请参阅我上面关于连接点的评论。我看到dir 的行为相同。远程运行它遵循连接点,我感觉有某种循环或其他东西。关于为什么会发生这种情况或如何避免它的任何想法。它需要与 PS 2.0 兼容。
      • 这个 dir 命令有一个用于重解析点的开关。我在命令中添加了 /a-l,希望能跳过这些,但我不能保证会修复它。
      • 真的很奇怪。您提供的命令是正确的,但它仍然遵循重新分析点。如果我在 PS 3+ 中将 get-childitem 与 -attributes !ReparsePoint 开关一起使用,也会发生同样的事情。
      • 恐怕我对此没有任何解释。
      猜你喜欢
      • 2014-10-13
      • 1970-01-01
      • 2022-12-02
      • 1970-01-01
      • 1970-01-01
      • 2015-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多