PowerShell Invoke-Command 严重的性能问题

PowerShell Invoke-Command severe performance issues

我很忙 运行高效地在远程系统上安装脚本。当 运行 在本地时,该命令需要 20 秒。当 运行 使用 Invoke-Command 命令需要 10 或 15 分钟 - 即使 "remote" 计算机是我的本地计算机。

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

运行 在本地机器上: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}

注:命令returns5个文件对象

编辑:我认为部分问题可能是重新分析点。当 运行 本地 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 都不会阻止它递归到重新分析点。相反,它似乎只过滤实际条目本身。

非常感谢!

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

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

问题似乎出在重新分析点上。出于某种原因,当命令在本地为 运行 时,将拒绝访问重新分析点(如 Documents and Settings)。一旦远程命令 运行,DIRGet-ChildItem 都会递归到重解析点。

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

相反,我不得不编写一个递归脚本并自己执行目录递归。它在我的机器上有点慢。本地大约需要 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
}

尝试使用远程会话:

$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"

我遇到了同样的问题。 很明显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

如您所见,数组传输超过一分钟。 尽管大小

,单个对象在几秒钟内传输完毕