【问题标题】:Powershell script repeats same server multiple timesPowershell脚本多次重复同一服务器
【发布时间】:2020-05-12 16:20:50
【问题描述】:

我有一个脚本,它通过服务器运行并打印出它们是否可以连接到特定端口。问题似乎是它继续循环遍历已经完成的现有服务器......因此我看到多个服务器结果并且 CSV 文件不断被重写,因为每次迭代都会再次重新启动循环以添加到下一个服务器上。

有什么想法可以确保它一次只循环通过一台服务器而不是每次都重复同一台服务器吗?最终的 CSV 很好,因为它包含所有服务器,但需要很长时间才能到达那里。

输出如下 - 你可以看到它如何不断地重新做现有的服务器,并且每次运行时只添加一个服务器:

Destination    Port 3389 Port 445 Port 80
-----------    --------- -------- -------
10.104.122.21  Failure   Failure  Failure
10.104.122.50  Failure   Failure  Failure
10.104.125.237 Failure   Failure  Failure



Destination    Port 3389 Port 445 Port 80
-----------    --------- -------- -------
10.104.122.21  Failure   Failure  Failure
10.104.122.50  Failure   Failure  Failure
10.104.125.237 Failure   Failure  Failure
10.104.125.66  Failure   Failure  Failure



Destination    Port 3389 Port 445 Port 80
-----------    --------- -------- -------
10.104.122.21  Failure   Failure  Failure
10.104.122.50  Failure   Failure  Failure
10.104.125.237 Failure   Failure  Failure
10.104.125.66  Failure   Failure  Failure
10.104.125.95  Failure   Failure  Failure

代码如下:

Function Test-PortConnections {
    [CmdletBinding()]

    # Parameters used in this function
    Param
    (
        [Parameter(Position=0, Mandatory = $True, HelpMessage="Provide destination source", ValueFromPipeline = $true)]
        $Destination,

        [Parameter(Position=1, Mandatory = $False, HelpMessage="Provide port numbers", ValueFromPipeline = $true)]
        $Ports = "80"
    ) 

    $ErrorActionPreference = "SilentlyContinue"
    $Results = @()

    ForEach($D in $Destination){
        # Create a custom object
        $Object = New-Object PSCustomObject
        $Object | Add-Member -MemberType NoteProperty -Name "Destination" -Value $D

        Write-Verbose "Checking $D"
        ForEach ($P in $Ports){
                #write-host "Port is $p"
                $timeout=100
                $requestCallback = $state = $null
                $client = New-Object System.Net.Sockets.TcpClient
                $beginConnect = $client.BeginConnect($d,$p,$requestCallback,$state)
                Start-Sleep -milli $timeOut
                if ($client.Connected -eq "True") { $Result = "True" } else { $Result = "False" }
                    $client.Close()
                        If($Result -eq "False"){ $status = "Failure" } else { $status = "Success" }

            $Object | Add-Member Noteproperty "$("Port " + "$p")" -Value "$($status)"
        }

        $Results += $Object

If($Results){
    $date = $(get-date -f yyyy-MM-dd)
    $Results | Format-Table -AutoSize
    $Results | Export-Csv -NoTypeInformation -Delimiter "," -Path H:\MyDocuments\Scripts\server_check_$($date).csv
}
}
} 

Test-PortConnections -Destination (Get-Content -Path "H:\MyDocuments\Scripts\servers.txt") -Ports 3389,445,80

【问题讨论】:

  • 它没有,但是您在每次与$Results | Format-Table -AutoSize 交互时都会将所有先前的结果写入屏幕
  • @MathiasR.Jessen 确实如此 - 当正确取出时,该行在屏幕上没有显示任何内容,但 CSV 不断改变大小。我不能在这里显示它,但大小不断从 1KB 变为 0KB,然后是 2KB,然后是 0KB 等等……这意味着它肯定会一次又一次地在同一台服务器上循环多次。
  • 是的,因为您不断累积结果并用新的总结果集覆盖同一个文件:)
  • @MathiasR.Jessen - 是的,你的权利 - 我想我现在已经通过将“Foreach”的末端括号移动到 $date 上方来解决这个问题,这似乎已经解决了。谢谢。

标签: powershell


【解决方案1】:

每次外部 foreach() 循环运行时,最后你:

  1. 将当前对象添加到现有结果中 ($Results += $object)
  2. 格式化并将ALL现有结果写入屏幕 ($Results | Format-Table -AutoSize)
  3. ALL将现有结果导出到文件 ($Results | Export-Csv ...)

Export-Csv 将简单地覆盖之前写入的文件,因此您不会看到最终结果的差异。

要解决此问题,我建议您在到达循环体末尾后立即让您的函数输出$object,然后将Export-Csv 步骤移出循环:

ForEach ($D in $Destination) {
    # Create a custom object
    $Object = New-Object PSCustomObject
    $Object | Add-Member -MemberType NoteProperty -Name "Destination" -Value $D

    Write-Verbose "Checking $D"
    ForEach ($P in $Ports) {
        #write-host "Port is $p"
        $timeout = 100
        $requestCallback = $state = $null
        $client = New-Object System.Net.Sockets.TcpClient
        $beginConnect = $client.BeginConnect($d, $p, $requestCallback, $state)
        Start-Sleep -milli $timeOut
        if ($client.Connected -eq "True") { $Result = "True" } else { $Result = "False" }
        $client.Close()
        If ($Result -eq "False") { $status = "Failure" } else { $status = "Success" }

        $Object | Add-Member Noteproperty "$("Port " + "$p")" -Value "$($status)"
    }

    Write-Output $Object
    $Results += $object
}

If ($Results) {
    $date = $(Get-Date -f yyyy-MM-dd)
    $Results | Export-Csv -NoTypeInformation -Delimiter "," -Path H:\MyDocuments\Scripts\server_check_$($date).csv
}

...或使用Export-Csv-Append,此时您根本不需要$Results

$date = Get-Date -Format yyyy-MM-dd
$ExportFileName = 'H:\MyDocuments\Scripts\server_check_${date}.csv'

ForEach ($D in $Destination) {
    # Create a custom object
    $Object = New-Object PSCustomObject
    $Object | Add-Member -MemberType NoteProperty -Name "Destination" -Value $D

    Write-Verbose "Checking $D"
    ForEach ($P in $Ports) {
        #write-host "Port is $p"
        $timeout = 100
        $requestCallback = $state = $null
        $client = New-Object System.Net.Sockets.TcpClient
        $beginConnect = $client.BeginConnect($d, $p, $requestCallback, $state)
        Start-Sleep -milli $timeOut
        if ($client.Connected -eq "True") { $Result = "True" } else { $Result = "False" }
        $client.Close()
        If ($Result -eq "False") { $status = "Failure" } else { $status = "Success" }

        $Object | Add-Member Noteproperty "$("Port " + "$p")" -Value "$($status)"
    }

    Write-Output $object
    $object | Export-Csv -Append -NoTypeInformation -Delimiter "," -Path $ExportFileName
}

【讨论】:

  • 忘记了 -append!谢谢你 - 它解决了这个问题。
猜你喜欢
  • 1970-01-01
  • 2015-09-15
  • 1970-01-01
  • 2018-09-13
  • 2019-04-01
  • 2015-11-12
  • 2012-09-12
  • 2018-01-14
  • 1970-01-01
相关资源
最近更新 更多