【问题标题】:Using Powershell To Distribute Script Level Jobs On Remote Servers使用 Powershell 在远程服务器上分发脚本级作业
【发布时间】:2016-04-07 16:25:49
【问题描述】:

更多的理论问题......

我有一个存在于三台服务器上的 powershell 脚本。在此示例中,三台服务器是:

  1. 服务器1
  2. 服务器2
  3. 服务器3

我正在使用另一台机器 server4,在指定远程时使用 Invoke-Command 远程调用脚本 C:\ExampleScript.ps1 ComputerName 参数。该脚本的最终目的是检测powershell是否正在运行,如果没有,则计算机“不忙”,可以远程打开被调用的脚本。如果计算机“忙”,则移动到下一个服务器并继续通过三台机器,直到用完所有参数值。如果所有机器都很忙,最好有办法定期检查进程并查看它们是否仍然打开。通过这种方式,脚本的执行可以在各种机器之间以一种原始的方式进行平衡。

考虑以下代码:

$servers = "server1","server2","server3"
$data = "param1", "param2", "param3", "param4", "param5", "param6"

#somehow loop through the different servers/data using the above arrays
$job = Invoke-Command $servers[0] {
$ProcessActive = Get-Process powershell -ErrorAction SilentlyContinue
if($ProcessActive -eq $null)
{
    "Running"
    Invoke-Command -ComputerName $env:computername -FilePath C:\ExampleScript.ps1 -ArgumentList $data[0]
}
else
{
     "Busy go to next machine"
}
 } -AsJob 
Wait-Job $job 
$r = Receive-Job $job 
$r 

试图实现的预期结果是尝试根据是否存在活动的 powershell 进程在机器之间对脚本进行负载平衡,如果没有则移动到下一台机器上并执行相同的测试和后续可能的执行。脚本应该遍历 $data 数组(或其他)中指定的所有值。

【问题讨论】:

  • 有趣(好)的想法,但我没有看到问题。我可以看到你要去哪里,但是有无数种方法可以做你正在寻找的事情。
  • 我想问题是如何修改代码以达到预期的效果?

标签: powershell


【解决方案1】:

我觉得这个问题很有趣,所以我想试一试。

$servers = "server1","server2","server3"

$data = New-Object System.Collections.ArrayList
$data.AddRange(@("param1", "param2", "param3", "param4", "param5", "param6"))

$jobs = New-Object System.Collections.ArrayList

do 
{
    Write-Host "Checking job states." -ForegroundColor Yellow
    $toremove = @()
    foreach ($job in $jobs)
    {
        if ($job.State -ne "Running")
        {
            $result = Receive-Job $job

            if ($result -ne "ScriptRan")
            {
                Write-Host "  Adding data back to que >> $($job.InData)" -ForegroundColor Green
                $data.Add($job.InData) | Out-Null
            }

            $toremove += $job
        }
    }

    Write-Host "Removing completed/failed jobs" -ForegroundColor Yellow
    foreach ($job in $toremove)
    {
        Write-Host "  Removing job >> $($job.Location)" -ForegroundColor Green
        $jobs.Remove($job) | Out-Null
    }

    # Check if there is room to start another job
    if ($jobs.Count -lt $servers.Count -and $data.Count -gt 0)
    {
        Write-Host "Checking servers if they can start a new job." -ForegroundColor Yellow
        foreach ($server in $servers)
        {

            $job = $jobs | ? Location -eq $server
            if ($job -eq $null)
            {
                Write-Host "  Adding job for $server >> $($data[0])" -ForegroundColor Green
                # No active job was found for the server, so add new job
                $job = Invoke-Command $server -ScriptBlock {
                    param($data, $hostname)
                    $ProcessActive = Get-Process powershell -ErrorAction SilentlyContinue
                    if($ProcessActive -eq $null)
                    {
                        # This will block the thread on the server, so the JobState will not change till it's done or fails.
                        Invoke-Command -ComputerName $hostname -FilePath C:\ExampleScript.ps1 -ArgumentList $data
                        Write-Output "ScriptRan"
                    }
                } -ArgumentList $data[0], $env:computername -AsJob
                $job | Add-Member -MemberType NoteProperty -Name InData -Value $data[0]
                $jobs.Add($job) | Out-Null
                $data.Remove($data[0])
            }
        }
    }
    # Just a manual check of $jobs
    Write-Output $jobs
    # Wait a bit before checking again
    Start-Sleep -Seconds 10
} while ($data.Count -gt 0)

基本上我创建了一个数组,并不断地为每个服务器填充一个作业。

当新作业开始时,数据会从列表中删除,如果作业失败,则会重新添加。这是为了避免服务器使用相同的数据/参数运行脚本。

目前我缺乏适当的环境来正确测试它,但明天会在工作中试一试,并在需要时更新我的​​答案。

【讨论】:

  • 我会检查一下我的环境!谢谢!
最近更新 更多