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-l
和 get-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
)。一旦远程命令 运行,DIR
和 Get-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
如您所见,数组传输超过一分钟。
尽管大小
,单个对象在几秒钟内传输完毕
我很忙 运行高效地在远程系统上安装脚本。当 运行 在本地时,该命令需要 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-l
和 get-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
)。一旦远程命令 运行,DIR
和 Get-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
如您所见,数组传输超过一分钟。 尽管大小
,单个对象在几秒钟内传输完毕