【问题标题】:Making a script more efficient with -asjob使用 -asjob 使脚本更高效
【发布时间】:2012-03-23 23:48:00
【问题描述】:

我有一个大约 1000 行脚本,它循环遍历 AD 中的所有服务器。 如果 ping=ok,该脚本会 ping 每个服务器并执行一系列 WMI 查询。 我的脚本将结果存储在我在脚本末尾输出到 CSV 的哈希表中。 这行得通,但它是sloooow ..我们谈了将近两个小时。我一直在研究如何提高效率,我认为 -asjob 听起来是个好主意。

但是我可以将其作为并发作业执行吗?我的服务器会处理负载吗?是 -asjob 的方式吗?

在等待我的脚本运行它的循环时希望得到一些输入..

编辑

我的观点是脚本等待测试连接(ping)返回真或假。我想同时运行多个 ping。

编辑 2

(注意: 我已经开始了一个单独的问题,因为我觉得我的原始问题已经得到解答。无论如何我都包含我当前的代码,因为这是已请求的。谢谢大家的参与!new question here!)

感谢大家到目前为止的帮助!我被要求列出我的代码,以提供我正在尝试做的真实示例。

这是我的代码的一小段但有效的摘录:

# List 4 servers (for testing)
$servers = Get-QADComputer -sizelimit 4 -WarningAction SilentlyContinue -OSName *server*,*hyper*

# Create list
$serverlistlist = @()

# Loop servers
foreach($server in $servers) {

    # Fetch IP
    $ipaddress = [System.Net.Dns]::GetHostAddresses($Server.name)| select-object IPAddressToString -expandproperty IPAddressToString

    # Gather OSName through WMI
    $OSName = (Get-WmiObject Win32_OperatingSystem -ComputerName $server.name ).caption

    # Ping the server
    if (Test-Connection -ComputerName $server.name -count 1 -Quiet ) {
        $reachable = "Yes"
    }

    # Save info about server
    $serverInfo = New-Object -TypeName PSObject -Property @{
        SystemName = ($server.name).ToLower()
        IPAddress = $IPAddress
        OSName = $OSName
    }
    $serverlistlist += $serverinfo | Select-Object SystemName,IPAddress,OSName
}

注意事项: 我在脚本末尾将 $serverlist 输出到 csv 文件 我在我的完整脚本中列出了大约 500 个服务器。

【问题讨论】:

  • 首先您需要确定哪些部分速度较慢,然后在您的问题中发布这些部分,以便我们提出改进建议。
  • 如果您在循环的每次迭代中使用Test-Connection,并且如果这是最慢的事情,您需要重新处理逻辑以同时运行 ping 测试,因为您首先需要一个服务器列表,然后您可以同时测试与它们的连接。你不必一次做所有的服务器,你可以一次做 10-20 个。
  • 谢谢安迪!是否可以将服务器列表上的整个 foreach 重新工作为开始工作?或者那不是那么聪明? :)
  • 取决于你所有的循环在做什么。请记住,后台作业在单独的 PowerShell.exe 实例中运行,因此它们无权访问您当前实例中的对象。他们必须自己创建对象。您可以通过 ArgumentList 将简单类型(字符串、整数等)传递给它们。

标签: powershell jobs


【解决方案1】:

我建议编写一个处理所有服务器验证(ping、WMI 等)的函数,然后将其封装在 Start-Job 命令中。为避免服务器资源过载,我建议在您的任务周围包装某种“作业管理器”。

foreach ($Server in $ServerList) {
    while ((Get-Job -State Running).Count -ge 20) {
       Start-Sleep -Seconds 5;
    }
    # Start-Job here
}

【讨论】:

  • 谢谢特雷弗!所以你的 sn-p 不会做超过 20 个并发作业?这听起来很聪明。但是我如何跟踪返回的内容?
  • 您好 Sune,您将使用 Receive-Job cmdlet 来接收每个作业的结果。您可以在它们完成时执行此操作,在 foreach 循环中(或者更好的是,在 while 循环中,while(哈哈)您正在等待其他作业完成),或者在 foreach 循环之后,当所有作业都完成时。
【解决方案2】:

您是否考虑过仅在您的第一个 wmi 请求失败时执行 ping 操作?如果故障很少见,那么这应该可以将这部分工作量排除在外”

ping 将作为您排查 wmi 请求失败原因的第一步。

我会将此与启动多个并发作业结合起来。

您究竟是如何 ping 的?你能分享那段代码吗?那里也可能有优化。

【讨论】:

  • 我没有看到任何对测试连接本身的明显改进建议。
  • 将整个脚本块作为一项工作怎么样?
【解决方案3】:

测试连接和 ping 总是很慢,我有一个类似的脚本。获取域中的所有服务器,并从每个服务器收集统计数据,proc util、ram util、disk free、所有 nic stats 等

我找到了一个测试端口功能,不记得我在哪里找到的,但端口测试只有大约 0.3 秒,如果成功,我运行测试连接。

对于所有服务器测试端口 135,对于 dc 的测试端口 389

function Verify_SinglePort{  ## returns True or false - avoids local host
Param ($CPUNAME, $port)
# This works no matter in which form we get $host - host name or ip address
If($ScriptMachineFQDN -eq $CPUNAME){ 
    ## not a good idea to test a port to and from the same machine
    return $true
}
try {
    $ip = [System.Net.Dns]::GetHostAddresses($CPUNAME) | select-object IPAddressToString -expandproperty  IPAddressToString
    if($ip.GetType().Name -eq "Object[]")
    {
        #If we have several ip's for that address, let's take first one
        $ip = $ip[0]
    }
} catch {
    #Write-Host "Possibly $CPUNAME is wrong host name or IP"
    return $false
}
$t = New-Object Net.Sockets.TcpClient
# We use Try\Catch to remove exception info from console if we can't connect
try
{
    $t.Connect($ip,$port)
} catch {}
if($t.Connected)
{
    $t.Close()
    $msg = "Port $port is operational"
    return $true
}
else
{
    $msg = "Port $port on $ip is closed, "
    $msg += "You may need to contact your IT team to open it. "  
    return $false
}
#Write-Host $msg

}

【讨论】:

    猜你喜欢
    • 2018-03-08
    • 2013-05-01
    • 2018-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-03
    相关资源
    最近更新 更多