Error handling, background jobs

Hello, having a script which will query FEP installation and Signature version on remote computers
If the computers are online and everything works, there is no problm.

How to deal with exceptions like

ItemNotFoundException, PSRemotingTransportException (Access to the server denied), PSremoting not enabled .. 

I would like to have output like

name;Product;Version;ErrorHandling 
server1;;;AccessDenied
server2;;;ItemNotFound
server3;Microsoft Forefront Endpoint Protection;1.175.2096.0;
server4;;;ItemNotFound
server5;;;ServerOffline

Param ([int]$BatchSize=20) #list of servers [array]$source = (get-adcomputer -filter {operatingsystem -like "Windows server*" -and name -like "s*exf*"}) |select -expandproperty dnshostname #scriptblock $blok = { $mycol = @() $AVSignatureVersion = Get-ItemProperty 'hklm:\SOFTWARE\Microsoft\Microsoft Antimalware\Signature Updates\' |select -Expandproperty AvSignatureVersion $ProductName = Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |?{$_.displayname -like "*Microsoft Forefront Endpoint*" -and ($_.installLocation)} |select -ExpandProperty Displayname $MyObject = New-Object PSObject -Property @{ AVSignatureVersion = $AVSignatureVersion ProductName = $ProductName ErrorHandling =

} $mycol += $MyObject $mycol } $i = 0 for ($i=0; $i -lt $itemCount;$i += $batchSize){ $activeJobCount += 1; $totalJobCount += 1; $HostList = @() $HostList += $source |select -skip $i -first $batchsize $j = invoke-command -computername $Hostlist -scriptblock $blok -asjob }

Please guide me how to these exceptions into $errorhandling variable

.. and.. i guess,  some errors are getting inside scriptblock ([ItemNotFound]) and others like [accessDenied]  outside?  So, is it possible to get the job exception into $myCol?

June 13th, 2014 5:04am

how about using try catch block?

Help about_Try_Catch_Finally -Examples

Free Windows Admin Tool Kit Click here and download it now
June 13th, 2014 5:36am

ok..

AVSignature and ProductName i  can solve by this

$AVSignatureVersion = Get-ItemProperty -ea silentlycontinue -ErrorVariable err 'hklm:\SOFTWARE\Microsoft\Microsoft Antimalware\Signature Updates\' |select -Expandproperty AvSignatureVersion
foreach ($errorRecord in $err)
{
    if ($errorRecord.Exception -is [System.Management.Automation.ItemNotFoundException])
    {
       $ErrorHandling = "Cant find registry key '$($errorRecord.TargetObject)'."
    }
    else
    {
        Write-Error -ErrorRecord $errorRecord
    }
}
But .. what about exception

Connecting to remote server someserver.dc.contoso.com failed with the following error message : WinRM cannot complete the operation. Verify that the specified computer name is valid .. which means either the name is incorrect, or PSRemoting is not enabled ...     It is generated outside scriptblock ..  how to get this exception into $errorhandling property?

June 13th, 2014 6:49am

When you need to get custom error information - Try like this

try{
$AVSignatureVersion = Get-ItemProperty -ErrorAction Stop 'hklm:\SOFTWARE\Microsoft\Microsoft Antimalware\Signature Updates\' |
select -Expandproperty AvSignatureVersion
}Catch{"Cant find registry key"}

Testing your
Free Windows Admin Tool Kit Click here and download it now
June 13th, 2014 7:18am

Please,

test whole script (change  get-adcomputer, and .. registry entry if u dont use FEP)

If its possible, solve errors meaning  "access denied, computer not available.. winRM fail.. 

The reason of error should always be in $errorhandling variable

Param ([int]$BatchSize=20)
 #list of servers
[array]$source = (get-adcomputer -filter {operatingsystem -like "Windows server*" -and ((name -like "server1") -or (name -like "server2*") -or  (name -like "server3*"))})|select -expandproperty dnshostname
 #scriptblock
$blok = {
$mycol = @()
$AVSignatureVersion = Get-ItemProperty -ea silentlycontinue -ErrorVariable err 'hklm:\SOFTWARE\Microsoft\Microsoft Antimalware\Signature Updates\' |select -Expandproperty AvSignatureVersion
foreach ($errorRecord in $err)
{
    if ($errorRecord.Exception -is [System.Management.Automation.ItemNotFoundException])
    {
       $ErrorHandling = "Cant find registry key '$($errorRecord.TargetObject)'."
    }
    else
    {
        $ErrorHandling = Write-Error -ErrorRecord $errorRecord
    }
}
$ProductName = Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |?{$_.displayname -like "*Microsoft Forefront Endpoint*" -and ($_.installLocation)} |select -ExpandProperty Displayname
$MyObject = New-Object PSObject -Property @{
  AVSignatureVersion = $AVSignatureVersion
  ProductName = $ProductName
  ErrorHandling = $errorhandling
    }
$mycol += $MyObject
$mycol
}
# JOBs scriptblock
$elapsedTime = [system.diagnostics.stopwatch]::StartNew()
$result = @()
$itemCount = 0

## checking running jobs 
if (get-job|? {$_.name -like "Script*"}){
    write-host "ERROR: There are pending background jobs in this session:" -back red -fore white
    get-job |? {$_.name -like "Script*"} | out-host
    write-host "REQUIRED ACTION: Remove the jobs and restart this script" -back black -fore yellow
    $yn = read-host "Automatically remove jobs now?"
    if ($yn -eq "y"){
        get-job|? {$_.name -like "Script*"}|% {remove-job $_}
        write-host "jobs have been removed; please restart the script" -back black -fore green
        }
    exit
    }
$i = 0

$itemCount = $source.count
Write-Host "Script will run against $itemcount servers!"

## Script start time mark
write-host "Script started at $(get-date -uFormat "%Y/%m/%d %H:%M:%S")".padright(60)             -back darkgreen -fore white
write-host "                    (contains $itemCount unique entries)" -back black -fore green
$activeJobCount = 0
$totalJobCount = 0
write-host "Submitting background jobs..." -back black -fore yellow



for ($i=0; $i -lt $itemCount;$i += $batchSize){
    $activeJobCount += 1; $totalJobCount += 1; $HostList = @()
    $HostList += $source |select -skip $i -first $batchsize
    $j = invoke-command -computername $Hostlist -scriptblock $blok -asjob
    $j.name = "Script`:$totalJobCount`:$($i+1)`:$($getHostList.count)"
    write-host "+" -back black -fore cyan -nonewline
  }

write-host "`n$totaljobCount jobs submitted, checking for completed jobs..." -back black -fore yellow
while (get-job |? {$_.name -like "Script*"}){
    foreach ($j in get-job | ? {$_.name -like "Script*"}){
        $temp = @()
        if ($j.state -eq "completed"){ 
            $temp = @()
            $temp += receive-job $j
            $result += $temp
            remove-job $j
            $ActiveJobCount -= 1
            write-host "-" -back black -fore cyan -nonewline
            }
           elseif ($j.state -eq "failed"){
            $temp = $j.name.split(":")
            if ($temp[1] -eq "R"){
                $temp = @()
                $temp += receive-job $j
                $result += $temp
                remove-job $j
                $ActiveJobCount -= 1
                write-host "-" -back black -fore cyan -nonewline
                }
            else{
                write-host "`nFailure detected in job: $($j.name)" -back black -fore red
                $temp = @()
                $temp += receive-job $j
                $result += $temp
                remove-job $j
                $ActiveJobCount -= 1
                }
            }
        }

 if ($result.count -lt $itemCount){
        sleep 3
        }
  }

write-host " "
write-host "Script finished at $(get-date -uFormat "%Y/%m/%d %H:%M:%S")".padright(60)             -back darkgreen -fore white
write-host ("   Elapsed Time : {0}" -f $($ElapsedTime.Elapsed.ToString())) -back black -fore green
$result |select PsComputerName,ProductName,AvSignatureVersion,ErrorHandling |sort ProductName,AVsignatureVersion

write-host  " Script completed all requested operations at $(get-date -uFormat "%Y/%m/%d %H:%M:%S")".padright(60) -back darkgreen -fore white
write-host ("   Elapsed Time : {0}" -f $($ElapsedTime.Elapsed.ToString())) -back black -fore green

June 13th, 2014 9:06am

The errors associated with creating the job are happening in your parent script, so they need to be handled there.  Your output from the script is a collection of custom objects created within the script blocks.  If you want the invocation errors to be included in the results, you'll probably need to create the same kind of custom object that would have been created by the script block, so your return results are consistent, otherwise it's going to be difficult to format or export:

try { $j = invoke-command -computername $Hostlist -scriptblock $blok -asjob -ErrorAction Stop } catch { New-Object PSObject -Property @{ AVSignatureVersion = $null ProductName = $Null ErrorHandling = $Error[0].Exception.TransportMessage }

}

Free Windows Admin Tool Kit Click here and download it now
June 13th, 2014 10:27am

Added your suggestion to script..

Param ([int]$BatchSize=20)
 #list of servers
#[array]$source = (get-adcomputer -filter {operatingsystem -like "Windows server*" -and ((name -like "server1") -or (name -like "server2*") -or  (name -like "server3*"))})|select -expandproperty dnshostname
[array]$source = "localhost"
 #scriptblock
$blok = {
$mycol = @()
$AVSignatureVersion = Get-ItemProperty -ea silentlycontinue -ErrorVariable err 'hklm:\SOFTWARE\Microsoft\Microsoft Antimalware\Signature Updates\' |select -Expandproperty AvSignatureVersion
foreach ($errorRecord in $err)
{
    if ($errorRecord.Exception -is [System.Management.Automation.ItemNotFoundException])
    {
       $ErrorHandling = "Cant find registry key '$($errorRecord.TargetObject)'."
    }
    else
    {
        $ErrorHandling = Write-Error -ErrorRecord $errorRecord
    }
}
$ProductName = Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |?{$_.displayname -like "*Microsoft Forefront Endpoint*" -and ($_.installLocation)} |select -ExpandProperty Displayname
$MyObject = New-Object PSObject -Property @{
  AVSignatureVersion = $AVSignatureVersion
  ProductName = $ProductName
  ErrorHandling = $errorhandling
    }
$mycol += $MyObject
$mycol
}
# JOBs scriptblock
$elapsedTime = [system.diagnostics.stopwatch]::StartNew()
$result = @()
$itemCount = 0

## checking running jobs 
if (get-job|? {$_.name -like "Script*"}){
    write-host "ERROR: There are pending background jobs in this session:" -back red -fore white
    get-job |? {$_.name -like "Script*"} | out-host
    write-host "REQUIRED ACTION: Remove the jobs and restart this script" -back black -fore yellow
    $yn = read-host "Automatically remove jobs now?"
    if ($yn -eq "y"){
        get-job|? {$_.name -like "Script*"}|% {remove-job $_}
        write-host "jobs have been removed; please restart the script" -back black -fore green
        }
    exit
    }
$i = 0

$itemCount = $source.count
Write-Host "Script will run against $itemcount servers!"

## Script start time mark
write-host "Script started at $(get-date -uFormat "%Y/%m/%d %H:%M:%S")".padright(60)             -back darkgreen -fore white
write-host "                    (contains $itemCount unique entries)" -back black -fore green
$activeJobCount = 0
$totalJobCount = 0
write-host "Submitting background jobs..." -back black -fore yellow



for ($i=0; $i -lt $itemCount;$i += $batchSize){
    $activeJobCount += 1; $totalJobCount += 1; $HostList = @()
    $HostList += $source |select -skip $i -first $batchsize
    #$j = invoke-command -computername $Hostlist -scriptblock $blok -asjob
    try { 
    $j = invoke-command -computername $Hostlist -scriptblock $blok -asjob -ErrorAction Stop
    } 
    catch 
    { 
    New-Object PSObject -Property @{ 
    AVSignatureVersion = $null 
    ProductName = $Null 
    ErrorHandling = $Error[0].Exception.TransportMessage 
    }
    }
    
    
    $j.name = "Script`:$totalJobCount`:$($i+1)`:$($getHostList.count)"
    write-host "+" -back black -fore cyan -nonewline
  }

write-host "`n$totaljobCount jobs submitted, checking for completed jobs..." -back black -fore yellow
while (get-job |? {$_.name -like "Script*"}){
    foreach ($j in get-job | ? {$_.name -like "Script*"}){
        $temp = @()
        if ($j.state -eq "completed"){ 
            $temp = @()
            $temp += receive-job $j
            $result += $temp
            remove-job $j
            $ActiveJobCount -= 1
            write-host "-" -back black -fore cyan -nonewline
            }
           elseif ($j.state -eq "failed"){
            $temp = $j.name.split(":")
            if ($temp[1] -eq "R"){
                $temp = @()
                $temp += receive-job $j
                $result += $temp
                remove-job $j
                $ActiveJobCount -= 1
                write-host "-" -back black -fore cyan -nonewline
                }
            else{
                write-host "`nFailure detected in job: $($j.name)" -back black -fore red
                $temp = @()
                $temp += receive-job $j
                $result += $temp
                remove-job $j
                $ActiveJobCount -= 1
                }
            }
        }

 if ($result.count -lt $itemCount){
        sleep 3
        }
  }

write-host " "
write-host "Script finished at $(get-date -uFormat "%Y/%m/%d %H:%M:%S")".padright(60)             -back darkgreen -fore white
write-host ("   Elapsed Time : {0}" -f $($ElapsedTime.Elapsed.ToString())) -back black -fore green
$result |select PsComputerName,ProductName,AvSignatureVersion,ErrorHandling |sort ProductName,AVsignatureVersion

write-host  " Script completed all requested operations at $(get-date -uFormat "%Y/%m/%d %H:%M:%S")".padright(60) -back darkgreen -fore white
write-host ("   Elapsed Time : {0}" -f $($ElapsedTime.Elapsed.ToString())) -back black -fore green
 

Script started at 2014/06/13 20:15:38                       
                    (contains 1 unique entries)
Submitting background jobs...
+
1 jobs submitted, checking for completed jobs...

Failure detected in job: Script:1:1:0
[localhost] Connecting to remote server localhost failed with the following error message : The client cannot connect to the destination specified in the request. Verify that the service on
the destination is running and is accepting requests. Consult the logs and documentation for the WS-Management service running on the destination, most commonly IIS or WinRM. If the destinat
ion is the WinRM service, run the following command on the destination to analyze and configure the WinRM service: "winrm quickconfig". For more information, see the about_Remote_Troubleshoo
ting Help topic.
    + CategoryInfo          : OpenError: (localhost:String) [], PSRemotingTransportException
    + FullyQualifiedErrorId : CannotConnect,PSSessionStateBroken

Script finished at 2014/06/13 20:15:44                      
   Elapsed Time : 00:00:06.0390985
 Script completed all requested operations at 2014/06/13 20:15:44
   Elapsed Time : 00:00:06.0406878

I havent got required output :(

June 13th, 2014 3:24pm

Mjolinor,

have u been tested your code? If the hostlist contains 2 or more hostnames?

just example:

[array]$source = "validserver.domain.com","fakeone"
$blok = {
 $mycol = @()
 $wmiobjects = gwmi win32_bios |select __server,serialnumber
 $MyObject = New-Object PSObject -Property @{
            Computername = $wmiobjects.__Server
            SerialNumber = $wmiobjects.SerialNumber
            errorhandling = ""
            }
  $mycol += $MyObject
  $mycol
  }         

$j = invoke-command -ComputerName $source -ScriptBlock $blok -AsJob
using

Get-Job |receive-job -Keep

I get this

SerialNumber   : GB890BB02     
errorhandling  :
Computername   : validserver
PSComputerName : validserver.domain.com
RunspaceId     : 0e714f4c-cb08-4b7f-9fb8-cbc7333fe4db

[fakeone] Connecting to remote server fakeone failed with the following error message : WinRM cannot process the request. The following error occurred while using Kerberos authentication
: Cannot find the computer fakeone. Verify that the computer exists on the network and that the name provided is spelled correctly. For more information, see the about_Remote_Troubleshoo
ting Help topic.
    + CategoryInfo          : OpenError: (fakeone:String) [], PSRemotingTransportException
    + FullyQualifiedErrorId : NetworkPathNotFound,PSSessionStateBroken

Is there a way to get rid off (or save it to errorhandling property) the fakeone server, which fails in the same job as the good ones?

I still cant manage to try/catch it

Free Windows Admin Tool Kit Click here and download it now
July 16th, 2014 6:54am

No, I didn't test it.  But then this is a "General discussion" thread.  The suggestion was simply to output the same kind of object from the parent script that you'll when you do a receive-job from the background jobs if your Invoke-Command throws errors.

You may need to get that information from $Errors in the parent script.  


July 16th, 2014 7:38am

So this I have so far.

Is there any way to get computername from failed job into $pscomputername variable?

Param ([int]$BatchSize=2)
 #list of servers
[array]$source = get-adcomputer -filter * |select -expandproperty dnshostname
 #scriptblock
$blok = {
$mycol = @()
 ## Services Checking
 $CCMService = get-service  ccmexec -ea SilentlyContinue -ErrorVariable err
 $AVSignatureVersion = Get-ItemProperty -ea silentlycontinue -ErrorVariable err 'hklm:\SOFTWARE\Microsoft\Microsoft Antimalware\Signature Updates\' |select -Expandproperty AvSignatureVersion
 $ProductName = Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |?{$_.displayname -like "*Microsoft Forefront Endpoint*" -and ($_.installLocation)} |select -ExpandProperty Displayname

 ## Error handling
 foreach ($errorRecord in $err)
{
   write-host $($errorRecord.Exception) 
   if ($errorRecord.Exception -is [Microsoft.PowerShell.Commands.ServiceCommandException])
    {
       $ErrorHandling = "Cannot find service: '$($errorRecord.TargetObject)'."
    }
   if ($errorRecord.Exception -is [System.Management.Automation.ItemNotFoundException])
    {
       $ErrorHandling = "Cant find registry key '$($errorRecord.TargetObject)'."
    }
   else
    {
        $ErrorHandling = $errorRecord
    }
}
  ## Creating custom table
 $MyObject = New-Object PSObject -Property @{
 CCMService = $CCMService.status
 AVSignatureVersion = $AVSignatureVersion
 ProductName = $ProductName
 ErrorStatus = $ErrorHandling
       }
     $mycol += $MyObject
     $mycol
}# end of scriptblock

$elapsedTime = [system.diagnostics.stopwatch]::StartNew()
$result = @()
$itemCount = 0

## checking running jobs 
if (get-job|? {$_.name -like "Script*"}){
    write-host "ERROR: There are pending background jobs in this session:" -back red -fore white
    get-job |? {$_.name -like "Script*"} | out-host
    write-host "REQUIRED ACTION: Remove the jobs and restart this script" -back black -fore yellow
    $yn = read-host "Automatically remove jobs now?"
    if ($yn -eq "y"){
        get-job|? {$_.name -like "Script*"}|% {remove-job $_}
        write-host "jobs have been removed; please restart the script" -back black -fore green
        }
    exit
    }
$i = 0


$itemCount = $source.count
Write-Host "Script will run against $itemcount servers!"

## Script start time mark
write-host "Script started at $(get-date -uFormat "%Y/%m/%d %H:%M:%S")".padright(60)             -back darkgreen -fore white
write-host "                    (contains $itemCount unique entries)" -back black -fore green
$activeJobCount = 0
$totalJobCount = 0
write-host "Submitting background jobs..." -back black -fore yellow



for ($i=0; $i -lt $itemCount;$i += $batchSize){
    $activeJobCount += 1; $totalJobCount += 1; $HostList = @()
    $HostList += $source |select -skip $i -first $batchsize
    $j = invoke-command -computername $Hostlist -scriptblock $blok -asjob
    $j.name = "Script`:$totalJobCount`:$($i+1)`:$($getHostList.count)"
    write-host "+" -back black -fore cyan -nonewline
  }

write-host "`n$totaljobCount jobs submitted, checking for completed jobs..." -back black -fore yellow
while (get-job |? {$_.name -like "Script*"}){
    foreach ($j in get-job | ? {$_.name -like "Script*"}){
        $temp = @()
        if ($j.state -eq "completed"){ 
            $temp = @()
            $temp += receive-job $j
            $result += $temp
            remove-job $j
            $ActiveJobCount -= 1
            write-host "-" -back black -fore cyan -nonewline
            }
           elseif ($j.state -eq "failed"){
            $temp = $j.name.split(":")
            if ($temp[1] -eq "R"){
                $temp = @()
                $temp += receive-job $j
                $result += $temp
                remove-job $j
                $ActiveJobCount -= 1
                write-host "-" -back black -fore cyan -nonewline
                }
            else{
                write-host "`nFailure detected in job: $($j.name)" -back black -fore red
                $temp = @() ## NEED HELP WITH THIS
                $MyObject = New-Object PSObject -Property @{
                pscomputername = "FailedComputerName" # Can i get the computername from the failed job there?
                CCMService = $CCMService.status
                AVSignatureVersion = $AVSignatureVersion
                ProductName = $ProductName
                ErrorStatus = "Something happened here"
       }
                $temp += $MyObject
                $temp += receive-job $j
                $result += $temp
                remove-job $j
                $ActiveJobCount -= 1
                }
            }
        }

 if ($result.count -lt $itemCount){
        sleep 3
        }
  }

write-host " "
write-host "Script finished at $(get-date -uFormat "%Y/%m/%d %H:%M:%S")".padright(60)             -back darkgreen -fore white
write-host ("   Elapsed Time : {0}" -f $($ElapsedTime.Elapsed.ToString())) -back black -fore green
$result |select pscomputername,ccmservice,productname,avsignatureversion,errorstatus |ft -AutoSize

write-host  " Script completed all requested operations at $(get-date -uFormat "%Y/%m/%d %H:%M:%S")".padright(60) -back darkgreen -fore white
write-host ("   Elapsed Time : {0}" -f $($ElapsedTime.Elapsed.ToString())) -back black -fore green

Free Windows Admin Tool Kit Click here and download it now
November 3rd, 2014 4:55am

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics