如何在这个PowerShell脚本上启用多线程?

时间:2014-07-01 19:45:15

标签: multithreading powershell

请帮助我尝试从远程计算机(在线)提取注册表信息并将其存储在日志文件中。这是3000台机器的缓慢过程,我希望有人可以帮我添加多线程来加速这个过程

    $ErrorActionPreference = "silentlycontinue"
filter Check-Online {
    trap { continue }
    . {
      $timeout = 2000
      $obj = New-Object system.Net.NetworkInformation.Ping
      $result = $obj.Send($_, $timeout)
      if ($result.status -eq 'Success') {1 }
    }
}
function Get-WebPage {
<#  
.SYNOPSIS  
   Downloads web page from site.
.DESCRIPTION
   Downloads web page from site and displays source code or displays total bytes of webpage downloaded
.PARAMETER Url
    URL of the website to test access to.
.PARAMETER UseDefaultCredentials
    Use the currently authenticated user's credentials  
.PARAMETER Proxy
    Used to connect via a proxy
.PARAMETER Credential
    Provide alternate credentials 
.PARAMETER ShowSize
    Displays the size of the downloaded page in bytes
.NOTES  
    Name: Get-WebPage
    Author: Boe Prox
    DateCreated: 08Feb2011        
.EXAMPLE  
    Get-WebPage -url "http://www.bing.com"

Description
------------
Returns the source code from bing.com -showsize
.EXAMPLE  
    Get-WebPage -url "http://www.bing.com" -ShowSize

Description
------------
Returns the size of the webpage bing.com in bytes.
#> 
[cmdletbinding(
    DefaultParameterSetName = 'url',
    ConfirmImpact = 'low'
)]
    Param(
        [Parameter(
            Mandatory = $True,
            Position = 0,
            ParameterSetName = '',
            ValueFromPipeline = $True)]
            [string][ValidatePattern("^(http|https)\://*")]$Url,
        [Parameter(
            Position = 1,
            Mandatory = $False,
            ParameterSetName = 'defaultcred')]
            [switch]$UseDefaultCredentials,
        [Parameter(
            Mandatory = $False,
            ParameterSetName = '')]
            [string]$Proxy,
        [Parameter(
            Mandatory = $False,
            ParameterSetName = 'altcred')]
            [switch]$Credential,
        [Parameter(
            Mandatory = $False,
            ParameterSetName = '')]
            [switch]$ShowSize                        

        )
Begin {     
    $psBoundParameters.GetEnumerator() | % { 
        Write-Verbose "Parameter: $_" 
        }

    #Create the initial WebClient object
    Write-Verbose "Creating web client object"
    $wc = New-Object Net.WebClient 

    #Use Proxy address if specified
    If ($PSBoundParameters.ContainsKey('Proxy')) {
        #Create Proxy Address for Web Request
        Write-Verbose "Creating proxy address and adding into Web Request"
        $wc.Proxy = New-Object -TypeName Net.WebProxy($proxy,$True)
        }       

    #Determine if using Default Credentials
    If ($PSBoundParameters.ContainsKey('UseDefaultCredentials')) {
        #Set to True, otherwise remains False
        Write-Verbose "Using Default Credentials"
        $wc.UseDefaultCredentials = $True
        }
    #Determine if using Alternate Credentials
    If ($PSBoundParameters.ContainsKey('Credentials')) {
        #Prompt for alternate credentals
        Write-Verbose "Prompt for alternate credentials"
        $wc.Credential = (Get-Credential).GetNetworkCredential()
        }         

    }
Process {    
    Try {
        If ($ShowSize) {
            #Get the size of the webpage
            Write-Verbose "Downloading web page and determining size"
            "{0:N0}" -f ($wr.DownloadString($url) | Out-String).length -as [INT]
            }
        Else {
            #Get the contents of the webpage
            Write-Verbose "Downloading web page and displaying source code" 
            $wc.DownloadString($url)       
            }

        }
    Catch {
        Write-Warning "$($Error[0])"
        }
    }   
}  

Function Get-RemoteRegistry {
    #This Function is read remote registry
    param(
        [string]$computer = $(Read-Host "Remote Computer Name")
       ,[string]$Path     = $(Read-Host "Remote Registry Path (must start with HKLM,HKCU,etc)")
       ,[string[]]$Properties
       ,[switch]$Verbose
    )
    if ($Verbose) { $VerbosePreference = 2 } # Only affects this script.

       $root, $last = $Path.Split("\")
       $last = $last[-1]
       $Path = $Path.Substring($root.Length + 1,$Path.Length - ( $last.Length + $root.Length + 2))
       $root = $root.TrimEnd(":")

       #split the path to get a list of subkeys that we will need to access
       # ClassesRoot, CurrentUser, LocalMachine, Users, PerformanceData, CurrentConfig, DynData
       switch($root) {
          "HKLM"  { $root = "LocalMachine" }
          default { return "Path argument is not valid" }
       }


       #Access Remote Registry Key using the static OpenRemoteBaseKey method.
       Write-Verbose "Accessing $root from $computer"
       #Add-Content $loglocation "Accessing $root from $computer"
       $rootkey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($root,$computer)
       if(-not $rootkey) { Write-Error "Can't open the remote $root registry hive" }

       Write-Verbose "Opening $Path"
       #Add-Content $loglocation "Opening $Path"
       $key = $rootkey.OpenSubKey( $Path )
       if(-not $key) { 
       Write-Error "Can't open $($root + '\' + $Path) on $computer"
       #Add-Content $loglocation "Can't open $($root + '\' + $Path) on $computer"
       }

       $subkey = $key.OpenSubKey( $last )

       $output = new-object object

       if($subkey -and $Properties -and $Properties.Count) {
          foreach($property in $Properties) {
             Add-Member -InputObject $output -Type NoteProperty -Name $property -Value $subkey.GetValue($property)
          }
          Write-Output $output
       } elseif($subkey) {
          Add-Member -InputObject $output -Type NoteProperty -Name "Subkeys" -Value @($subkey.GetSubKeyNames())
          foreach($property in $subkey.GetValueNames()) {
             Add-Member -InputObject $output -Type NoteProperty -Name $property -Value $subkey.GetValue($property)
          }
          Write-Output $output
       }
       else
       {
          $key.GetValue($last)
       }
}


$loglocation = Read-Host "Please input a local path to save the logs to. Ex: C:\mylog.txt"
$Computerlist = Read-Host "Please input the path to local file that contains the computer's names. Ex: C:\computernames.txt"

$webpage = Get-WebPage -url "ftp://ftp.mcafee.com/commonupdater/"
$val1 = $webpage.indexof("avvdat-") + 4
$val2 = $webpage.indexof(".zip")
$output = $webpage.substring($val1,$val2-$val1)
$output = $output.replace("at-", "")
write-host "The current DAT file version is: $output"
Add-Content $loglocation "The current DAT file version is: $output"

$servers = get-content $Computerlist #read the computers from the text file

foreach($s in $servers){ #This foreach loops through the text file of computers and performs the below actions on each computer.
    #Check if they are online
    if (($s | Check-Online) -eq 1) {     
        write-host "$s is online"
        $Regvalue = Get-RemoteRegistry $s "HKLM\SOFTWARE\Wow6432Node\McAfee\AVEngine\AVDatDate"     
        $Regvalue2 = Get-RemoteRegistry $s "HKLM\SOFTWARE\Wow6432Node\McAfee\AVEngine\AVDatVersion"     
        $Regvalue3 = Get-RemoteRegistry $s "HKLM\SOFTWARE\McAfee\AVEngine\AVDatDate"        
        $Regvalue4 = Get-RemoteRegistry $s "HKLM\SOFTWARE\McAfee\AVEngine\AVDatVersion" 

        $aValue = $Regvalue
        $bValue = $Regvalue2
        if($Regvalue -eq $null){
            $aValue = $Regvalue3
        }

        if($Regvalue2 -eq $null){
            $bValue = $Regvalue4
        }
        write-host $Regvalue
        write-host $Regvalue2
        write-host $Regvalue3
        write-host $Regvalue4
        Add-Content $loglocation "$s,$aValue,$bValue"
    }else{
        Write-Error "$s is offline"
    }
}

2 个答案:

答案 0 :(得分:0)

PowerShell具有可以异步运行并相应地管理/监控的作业概念。除了上面的ePO评论,我建议使用内置方法。

答案 1 :(得分:0)

如果您在所有这些系统上运行PSRemoting,您可以使用扇出方法并使用Invoke-Command远程查询所有服务器。

$Servers = Get-Content Servers.txt
Invoke-Command -ScriptBlock {#Code to run} -Computername $Servers -AsJob -Throttle 20
Get-Job | Wait-Job | Receive-Job