【问题标题】:How to quickly check if WMI information can be pulled from a remote computer如何快速检查是否可以从远程计算机中提取 WMI 信息
【发布时间】:2014-12-29 16:32:54
【问题描述】:

我正在寻找可以快速运行的命令(IF 测试),以查看是否可以连接到计算机。我做了一个 if 测试,如果它通过了,那么我将运行一系列命令来提取我需要的信息。如果第一次测试失败,那么它不会运行命令,否则每次测试都会失败,这将花费很长时间。

以下代码可以运行,但速度很慢,如果计算机不在网络上,则会导致“GUI(无响应)”。如果失败,我正在寻找可以更快地检查的方法。

if (Test-Path "\\$PCNAME\c`$")
{
    # Slew of WMI commands go here.
}

我有时会查询大量计算机列表,如果其中大部分计算机处于关闭状态,则上述命令将需要大量时间才能完成。

【问题讨论】:

    标签: powershell remote-connection


    【解决方案1】:

    一个更好的解决方案,它使用基于:https://theolddogscriptingblog.wordpress.com/2012/05/11/wmi-hangs-and-how-to-avoid-them/ 的端口测试

    这里是那里找到的脚本的修改版本以及使用它的一种方式的示例:

    function Test-Port {   
    <#
    .SYNOPSIS
    Tests connection to port 135 on the SQL server, so I guess it is confined to M$ servers 
    .DESCRIPTION
    .PARAMETER server
    computername or IP address
    .PARAMETER port
    port defaults to 135
    .PARAMETER timeout
    in milliseconds, defaults to 1000
    .EXAMPLE
    Test-Port myserver.com
    #>
    Param(    
        [string] $server,    
        $port=135,    
        $timeout=1000, # milliseconds    
        [switch]$verbose   
     )    
     # Does a TCP connection on specified port (135 by default)    
     # Create TCP Client  https://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient(v=vs.110).aspx  
     $tcpclient = new-Object system.Net.Sockets.TcpClient    
     # Initiate an asynchronous request to machine on Port    
     $iar = $tcpclient.BeginConnect($server,$port,$null,$null)    
     # Set the wait time    
     $wait = $iar.AsyncWaitHandle.WaitOne($timeout,$false)    
     # Check to see if the connection is done    
     if(!$wait)    
     {    
     # Close the connection and report timeout    
        $tcpclient.Close()    
        if($verbose){Write-Host Connection Timeout  }    
        Return $false   
     }    
     else   
     {    
     # Close the connection and report the error if there is one    
        $error.Clear()    
        $tcpclient.EndConnect($iar) | out-Null   
        if(!$?){if($verbose){write-host $error[0]};$failed = $true}    
        $tcpclient.Close()    
     }    
     # Return $true if connection Establish else $False    
        if($failed){    
        return $false   
        } else {    
        return $true   
        }    
    } 
    #Found from using for a similar purpose that checking port 49153 was more reliable than 135 
    # also the test-connection is unnecessary and that very small timeouts, e.g., 10ms, worked on our network, which really speeds things up but you should test what works on your network
    #Use like this
    $computername = "myserver.com"
    if (Test-Port -srv $computername -port 49153 -timeout 10) {
        # Slew of WMI commands go here.
    } else {
        Write-Warning "Could ping $computername but NOT reach RPC port`n so can't use it for WMI"
    }
    

    【讨论】:

      【解决方案2】:

      总结 sdjuan 的答案以快速检查 PCNAME 是否具有 C$ 驱动器共享,并允许 WMI 查找:

      If ( (Test-Path "\\$PCNAME\c`$") -and (Get-WmiObject win32_bios -ComputerName $PCNAME) ) {
      # Slew of WMI commands go here.
      }
      

      但是,通过我的测试,CimInstance 查找速度似乎更快,所以:

      Get-CimInstance win32_bios -ComputerName $PCNAME
      

      可能会产生更好的结果,但在脚本的其余部分保持一致。

      【讨论】:

        【解决方案3】:

        有两种简单的方法可以做到这一点:

        一个是测试连接:

        Test-Connection 192.168.0.2
        Test-Connection -CompuetrName "SamsPC"
        

        这可以用作布尔表达式,或与 $?运营商:

        if (Test-Connection 192.168.0.1) {
         do stuff
        }
        

        Test-Connection 192.168.0.1
        if ($?) {
         Do Stuff
        }
        

        另一种方法使用 .NET 类。

        $Pinger = New-Object System.Net.NetworkInformation.Ping
        $pResult = $Pinger.Send("192.168.0.1")
        
        if ($pResult.Status -eq "Success") {
          Do stuff
        }
        

        【讨论】:

          【解决方案4】:

          您通常会看到 Test-Connection 用于此目的:

          if (Test-Connection $PCNAME -Quiet -Count 1)
          {
            # Slew of WMI commands go here.
          }
          

          编辑:如果远程系统支持它,我怀疑使用 CIM 可能会更好。实施细节将取决于远程系统上是否启用了远程处理。

          【讨论】:

          • 我也见过这个。我在我的代码中将其关闭,并且花了大约 45 秒的时间告诉我连接失败。我上面使用的方法只需要约 15 秒即可失败。但我正在寻找类似 5 秒后没有连接报告失败的情况。
          • 您可以使用 -Count 参数在连接失败之前减少连接尝试次数。用示例更新了答案。
          • 这是一个糟糕的测试,因为有时您可以成功地Test-Connection a.k.a ping 而不是Get-WmiObject。这是因为WMI 是在您尝试访问的远程计算机上运行的服务
          【解决方案5】:

          只需对测试连接超时脚本进行一些小的修改,您也可以测试 WMI 功能。只需用 get-wmiobject 调用替换 test-connection 即可获得完整的结果。这是一个修改后的函数:

          Function Get-WMI {
          param(
              [Parameter(Mandatory = $True)]
              [Object]$computer
          )
          $timeoutSeconds = 1 # set your timeout value here
          $j = Start-Job -ScriptBlock {
              # your commands here, e.g.
              Get-WmiObject win32_bios -ComputerName $args[0]
          } -ArgumentList $computer
          #"job id = " + $j.id # report the job id as a diagnostic only
          Wait-Job $j -Timeout $timeoutSeconds | out-null
          if ($j.State -eq "Completed")
          {
          #connection to PC has been verified and WMI commands can go here.
          $Answer = "WMI call WAS SUCCESSFULL to $computer"
          }
          elseif ($j.State -eq "Running")
          {
          #After the timeout ($timeoutSeconds) has passed and the test is      
          still running, I will assume the computer cannot be connected.
          $Answer = "WMI is not running on or could not Connect to $computer"
          }
          return $Answer
          }
          

          我希望这对某人有所帮助。

          【讨论】:

            【解决方案6】:

            我知道这是事后的事,但我找到了解决方案。我正在寻找一个 if 测试来尝试测试连接,但是当它失败时,失败需要很长时间。建立连接后,它会立即通过。

            $timeoutSeconds = 1 # set your timeout value here
            $j = Start-Job -ScriptBlock {
                # your commands here, e.g.
                Test-Connection -ComputerName $args[0] -Count 1
            } -ArgumentList $computer
            #"job id = " + $j.id # report the job id as a diagnostic only
            Wait-Job $j -Timeout $timeoutSeconds | out-null
            if ($j.State -eq "Completed")
            {
                #connection to PC has been verified and WMI commands can go here.
                $richtextbox1.Text = "Connection can be made to $computer"
            }
            elseif ($j.State -eq "Running")
            {
                #After the timeout ($timeoutSeconds) has passed and the test is still running, I will assume the computer cannot be connected.
                $richtextbox1.Text = "Could not Connect to $computer"
            }
            

            我不确定我是从哪里得到这段代码的。我想我用过-adding a timeout to batch/powershell

            我希望这对将来的某人有所帮助。

            【讨论】:

            • 这些解决方案都没有测试“WMI 信息是否可以从远程计算机中提取” FWIW:test-connection 将为 linux 计算机返回一个肯定的结果,即使您显然也不会执行 WMI可以ping通。
            • 这是真的,但是我还没有找到一种方法来完全按照我的意愿去做,所以这至少会让代码不会挂起。如果您找到解决方案,我很乐意听到它,因为它仍然有用。
            • 我输入了一个简短的答案,其中包含一个测试方法的链接,但没有意识到 stackoverflow 规则需要的不仅仅是一个链接,因此版主删除了我的答案。我已经提交了一个带有示例的扩展答案,如果它在一两天内没有出现在这里,我将把它重写为一个单独的答案
            • 我试图在扩展后取消删除我之前太短的答案,但它弹回来说它无法取消删除,所以我发布了新的扩展答案。希望对您有所帮助。
            猜你喜欢
            • 1970-01-01
            • 2010-10-09
            • 2023-04-07
            • 2013-01-04
            • 2012-04-14
            • 1970-01-01
            • 1970-01-01
            • 2014-10-17
            • 1970-01-01
            相关资源
            最近更新 更多