如何使用PowerShell管道有效地节省资源?

时间:2015-02-23 21:38:23

标签: powershell exchange-server pipeline

我有几个PowerShell脚本用于管理中型Microsoft Exchange组织(约10,000个邮箱)。有些脚本以某种方式处理组织的所有邮箱。我在运行这些脚本时遇到的一个常见问题是资源耗尽。这些脚本最终使用千兆字节的RAM。

我的研究表明,使用管道可以避免内存消耗,因为结果在处理之前没有加载到数组中。但是,在某些情况下,Get-Mailbox似乎仍然会在尝试将这些结果传递给管道中的下一个命令之前将整个结果列表加载到内存中。

例如,我假设以下示例代码将在命令执行后立即开始列出与每个邮箱关联的移动设备:

示例1

function GetMailboxDevices
{
    process
    {
        Write-Host $_.Alias -ForegroundColor Green
        Get-MobileDevice -Mailbox $_
    }
}

Get-Mailbox -ResultSize Unlimited | GetMailboxDevices

但是,在Get-Mailbox cmdlet运行时,此代码似乎不会实时处理结果。相反,Get-Mailbox似乎需要几分钟才能运行,然后立即将所有结果传递给管道中的第二个命令。在此过程中,PowerShell会话的RAM使用率攀升至1.5 GB或更高。

尽管如此,我可以使用类似于以下内容的代码解决此问题:

示例2

function GetMailboxAliases
{ 
    process 
    {
        Write-Host $_.Alias -ForegroundColor Green
        $_.Alias
    } 
}

$aliases = Get-Mailbox -ResultSize Unlimited | GetMailboxAliases

foreach ($alias in $aliases)
{
    Get-MobileDevice -Mailbox $alias
}

在第二个示例中,Get-Mailbox确实将每个结果实时传递到管道中,而不是一次性传递(Write-Host确认这一点)并且RAM使用率没有显着增加。当然,这段代码并不像我将别名收集到数组中那样优雅,然后使用foreach语句处理数组。

如果我在函数中执行简单的操作(例如只返回每个邮箱的别名),那么管道似乎很有效,但是一旦我将另一个Exchange cmdlet引入函数(例如Get-MobileDevices),行为就会改变)。

我的问题是:为什么示例1中的代码不能有效地利用管道,但示例2呢?可以采取哪些措施来确保有效利用管道?

1 个答案:

答案 0 :(得分:0)

'我没有那么多使用Exchange,但在我的脚本中我会这样做:

function GetMailboxDevices ($mb)
{
    process
    {
        Write-Host $_.Alias -ForegroundColor Green
        Get-MobileDevice -Mailbox $mb
    }
}


Get-Mailbox -ResultSize Unlimited | Foreach-object { GetMailboxDevices $_}

Get-Mailbox -ResultSize Unlimited | % { GetMailboxDevices $_}