Author Posts

July 11, 2014 at 5:26 am

I am a sysadmin for my network, but we are in a tiered enterprise domain. Our McAfee ePO server is controlled above us, and they are holding on to all permissions (job security). So I came up with the below script to parse through a list of computers and get their McAfee Dat version and write it to a text file.

When I run it across 3000 machines, it takes a long time. So I was hoping someone could help me convert it to multithreading.

    $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 {
 
[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"
    }
}

July 11, 2014 at 6:11 am

Maybe you should take a closer look at powershell jobs.

Take a look at this documentation:
[url]http://technet.microsoft.com/en-us/library/hh849698.aspx[/url]

July 11, 2014 at 6:30 am

I tried but it didn't work

$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 {
 
[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.
	$scriptblock={
        param($s)
        #Check if they are online
	    if (($s | Check-Online) -eq 1) {	 
            write-output "$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-output "$s= $Regvalue"
            write-output "$s= $Regvalue2"
            write-output "$s= $Regvalue3"
            write-output "$s= $Regvalue4"
            Add-Content $loglocation "$s,$aValue,$bValue"
        }else{
            Write-Error "$s is offline"
        }    
    }
    start-job -name $s -scriptblock $scriptblock -argumentlist $s
}

while (get-job -state "Running")
{
    start-sleep 1   
} 
get-job | receive-job
get-job | remove-job

July 16, 2014 at 6:57 am

Long Path Tool seems to have nothing to do with what I am asking about

July 16, 2014 at 7:01 am

I've been marking his posts regarding this "Long Path Tool" on unrelated threads as Spam. Three so far in the last few minutes. Hopefully he'll catch on.

July 16, 2014 at 7:49 am

This script [url]http://gallery.technet.microsoft.com/Powershell-to-create-many-1b4f6f37 [/url] shows an example of using Start-job, Get-job, Receive-job, Remove-job to run a PS script in several concurrently-running threads.
Notice that on this example, the number of threads = the number of vLUNs on line 11