优化 PowerShell 脚本以进行远程执行和并行处理

问题描述 投票:0回答:1

我有一个 PowerShell 脚本,可以在多个服务器上远程执行脚本。该脚本检查每个服务器上是否存在特定脚本,如果存在,则远程调用该脚本。我想优化脚本的性能和内存使用情况,特别是在处理大量服务器时。以下是我当前使用的代码。

代码部分说明:

  1. 服务器列表和初始化:
    服务器列表 (

    $servers
    ) 在脚本的开头定义。它保存将执行脚本的远程服务器的名称或 IP 地址。我们还初始化了几个变量,例如
    $results
    来存储结果,
    $missingScriptServers
    用于缺少脚本的服务器,以及成功和失败的计数器(
    $successCount
    $failureCount
    )。

  2. 检查脚本是否存在:
    函数

    Check-ScriptExists
    检查每个远程服务器上是否存在指定的脚本 (
    $scriptPath
    )。它使用 PowerShell 远程处理(
    New-PSSession
    Invoke-Command
    )来检查远程服务器上是否存在脚本文件。如果脚本存在,函数返回
    $true
    ;否则,返回
    $false

  3. 远程调用脚本:

    Invoke-ScriptOnServer
    函数负责在服务器上远程执行脚本。如果脚本存在,该函数将使用
    Invoke-Command
    执行它。如果执行过程中出现错误,则返回
    1
    表示失败。

  4. 远程命令并行执行:
    该脚本检查列表中的每个服务器。对于存在脚本的服务器,它使用

    Start-Job
    创建后台作业。这允许脚本在多个服务器上并行调用远程脚本,从而无需等待每个服务器完成后再转到下一个服务器,从而提高了性能。

  5. 收集和显示结果:
    启动远程执行作业后,脚本使用

    Wait-Job
    等待每个作业完成,并使用
    Receive-Job
    检索结果。然后,它会使用
    Remove-Job
    删除作业以释放资源。结果存储在
    $results
    中,成功和失败计数相应更新。最后,脚本以表格格式输出结果并显示成功/失败计数。

    # Define the list of server names or IP addresses
    $servers = @(
        "server1",
        "server2",
        "server3"
        # Add more servers as needed
    )
    
    # Path to the script on the servers
    $scriptPath = "D:\your_script.ps1"
    
    # Initialize arrays to hold result objects and counts for success and failure
    $results = @()
    $missingScriptServers = @()
    $successCount = 0
    $failureCount = 0
    
    # Function to check if the script exists on the server
    function Check-ScriptExists {
        param (
            [string]$Server,
            [string]$ScriptPath
        )
        try {
            $session = New-PSSession -ComputerName $Server
            $exists = Invoke-Command -Session $session -ScriptBlock {
                param($ScriptPath)
                Test-Path -Path $ScriptPath
            } -ArgumentList $ScriptPath
            Remove-PSSession -Session $session
            return $exists
        } catch {
            return $false
        }
    }
    
    # Function to invoke the script on a remote server
    function Invoke-ScriptOnServer {
        param (
            [string]$Server,
            [string]$ScriptPath
        )
        try {
            $session = New-PSSession -ComputerName $Server
            $response = Invoke-Command -Session $session -ScriptBlock {
                param($ScriptPath)
                & $ScriptPath
                return $LASTEXITCODE
            } -ArgumentList $ScriptPath
            Remove-PSSession -Session $session
            return $response
        } catch {
            return 1  # Return failure exit code in case of error
        }
    }
    
    # Check for script existence and start jobs in parallel
    $jobs = @()
    foreach ($server in $servers) {
        $scriptExists = Check-ScriptExists -Server $server -ScriptPath $scriptPath
        if ($scriptExists) {
            $jobs += Start-Job -ScriptBlock {
                param($server, $scriptPath)
                Invoke-ScriptOnServer -Server $server -ScriptPath $scriptPath
            } -ArgumentList $server, $scriptPath
        } else {
            $missingScriptServers += $server
        }
    }
    
    # Wait for all jobs to complete and collect results
    foreach ($job in $jobs) {
        $job | Wait-Job
        $response = $job | Receive-Job
        $job | Remove-Job
    
        # Update success/failure count based on the response code
        if ($response -eq 0) {
            $successCount++
        } else {
            $failureCount++
        }
        $results += [pscustomobject]@{ Server = $server; Response = $response }
    }
    
    # Display the results in a table format  
    $results | Format-Table -AutoSize
    
    # Display the success and failure counts
    Write-Output "Number of servers succeeded: $successCount"
    Write-Output "Number of servers failed: $failureCount"
    
    # Display the servers where the script is missing
    if ($missingScriptServers.Count -gt 0) {
        Write-Output "The script is missing on the following servers:"
        $missingScriptServers | Format-Table -AutoSize
    } else {
        Write-Output "The script is available on all specified servers."
    }
    # Define the list of server names or IP addresses
    $servers = @(
        "server1",
        "server2",
        "server3"
        # Add more servers as needed
    )
    
    # Path to the script on the servers
    $scriptPath = "D:\your_script.ps1"
    
    # Initialize arrays to hold result objects and counts for success and failure
    $results = @()
    $missingScriptServers = @()
    $successCount = 0
    $failureCount = 0
    
    # Function to check if the script exists on the server
    function Check-ScriptExists {
        param (
            [string]$Server,
            [string]$ScriptPath
        )
        try {
            $session = New-PSSession -ComputerName $Server
            $exists = Invoke-Command -Session $session -ScriptBlock {
                param($ScriptPath)
                Test-Path -Path $ScriptPath
            } -ArgumentList $ScriptPath
            Remove-PSSession -Session $session
            return $exists
        } catch {
            return $false
        }
    }
    
    # Function to invoke the script on a remote server
    function Invoke-ScriptOnServer {
        param (
            [string]$Server,
            [string]$ScriptPath
        )
        try {
            $session = New-PSSession -ComputerName $Server
            $response = Invoke-Command -Session $session -ScriptBlock {
                param($ScriptPath)
                & $ScriptPath
                return $LASTEXITCODE
            } -ArgumentList $ScriptPath
            Remove-PSSession -Session $session
            return $response
        } catch {
            return 1  # Return failure exit code in case of error
        }
    }
    
    # Check for script existence and start jobs in parallel
    $jobs = @()
    foreach ($server in $servers) {
        $scriptExists = Check-ScriptExists -Server $server -ScriptPath $scriptPath
        if ($scriptExists) {
            $jobs += Start-Job -ScriptBlock {
                param($server, $scriptPath)
                Invoke-ScriptOnServer -Server $server -ScriptPath $scriptPath
            } -ArgumentList $server, $scriptPath
        } else {
            $missingScriptServers += $server
        }
    }
    
    # Wait for all jobs to complete and collect results
    foreach ($job in $jobs) {
        $job | Wait-Job
        $response = $job | Receive-Job
        $job | Remove-Job
    
        # Update success/failure count based on the response code
        if ($response -eq 0) {
            $successCount++
        } else {
            $failureCount++
        }
        $results += [pscustomobject]@{ Server = $server; Response = $response }
    }
    
    # Display the results in a table format  
    $results | Format-Table -AutoSize
    
    # Display the success and failure counts
    Write-Output "Number of servers succeeded: $successCount"
    Write-Output "Number of servers failed: $failureCount"
    
    # Display the servers where the script is missing
    if ($missingScriptServers.Count -gt 0) {
        Write-Output "The script is missing on the following servers:"
        $missingScriptServers | Format-Table -AutoSize
    } else {
        Write-Output "The script is available on all specified servers."
    }
    
    
powershell optimization parallel-processing scripting execution
1个回答
0
投票

作为一般规则,避免使用

+=

Invoke-Command
已经并行运行。此外,无需检查脚本是否作为单独的调用存在,只需尝试运行它并解析输出即可。也可以使用
Invoke-Command -FilePath
直接用命令执行脚本

# Define the list of server names or IP addresses
$servers = @(
    "server1",
    "server2",
    "server3"
    # Add more servers as needed
)

# Path to the script on the servers
$scriptPath = "D:\your_script.ps1"


$icmParams = @{
    ComputerName = $servers
    FilePath = $scriptPath
}
$results = Invoke-Command @icmParams

# Format, filter, and display the $results to your liking
© www.soinside.com 2019 - 2024. All rights reserved.