Share via

Getting error information when running command on multiple computers at once

Darren Rose 496 Reputation points
2021-02-16T17:34:03.307+00:00

When using a Foreach loop to test remoting for example I can access the error information to record useful information in my results

e.g. stored in $remotenotworkingwithreason below

$computers = Get-Content C:\Tmp\PCA_TESTING_ONLY\temp\computerlist.txt

$remoteworking =@()
$remotenotworking = @()
$remotenotworkingwithreason = @()

 Foreach ($onlinecomputer in $computers) {

        Try {

            $result = Invoke-Command -ComputerName $onlinecomputer { 1 } -ErrorAction Stop

            If ($result -eq "1") { $remoteworking += $onlinecomputer }

        }
        Catch {

              If ($PSItem.Exception.Message.Contains("Access is denied")) { $remotenotworkingwithreason += $onlinecomputer + " (Remoting not enabled)" } Else { $remotenotworkingwithreason += $onlinecomputer + " (DNS)" }
              $remotenotworking += $onlinecomputer
        }

    }

How do I get the same information if I am not using Foreach but running command on multiple computers at once with below code?

$computers = Get-Content C:\Tmp\PCA_TESTING_ONLY\temp\computerlist.txt

$remoteworking =@()
$remotenotworking = @()
$remotenotworkingwithreason = @()

$remotecheck = Invoke-Command -ComputerName $computers { 1 } -ErrorAction SilentlyContinue

$remoteworking = $remotecheck | Select-Object -ExpandProperty PSComputerName 

$remotenotworking = $computers | Where-Object { $remoteworking -notcontains $_ }

Second example - similar issue

I use the below function to show a toast message on a list of computers

Function Show-Toast {

    param (
        [Parameter(Mandatory = $true)]
        [string]
        $Title,

        [Parameter(Mandatory = $true)]
        [string]
        $Body
    )

    # Load required namespaces - not really needed it seems
    $null = [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime]
    $null = [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime]

    # Set the AppID to use
    $AppID = '{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\WindowsPowerShell\v1.0\powershell.exe' # using PowerShell
    #$AppID = 'PC.Assist' # using a custom AppID entry

    # Configure the AppID in the registry for use with the Action Center, if required (so notification stays in notification center until dismissed)
    $RegPath = 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Notifications\Settings'
    If (!(Test-Path -Path "$RegPath\$AppId")) {
        $null = New-Item -Path "$RegPath\$AppId" -Force
        $null = New-ItemProperty -Path "$RegPath\$AppId" -Name 'ShowInActionCenter' -Value 1 -PropertyType 'DWORD'
    }
    Else {
        Set-ItemProperty "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Notifications\Settings\$AppID" -Name "ShowInActionCenter" -Type Dword -Value "1" -ErrorAction Ignore
    }

    # Define the toast notification in XML format
    [xml]$ToastTemplate = @"
<toast scenario="reminder">
    <visual>
    <binding template="ToastGeneric">
        <text>$Title</text>
 <text>$Body</text>
    </binding>
    </visual>
 <actions>
 <action activationType="system" arguments="dismiss" content=""/>
 </actions>
    <audio src="ms-winsoundevent:Notification.Reminder"/>
</toast>
"@

    # Load the notification into the required format
    $ToastXml = New-Object -TypeName Windows.Data.Xml.Dom.XmlDocument
    $ToastXml.LoadXml($ToastTemplate.OuterXml)

    # Display
    Try {
        $Notify = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($AppID).Show($ToastXml)

        Return "Success"

    }
    Catch {
        Return $PSItem.Exception.InnerException
    }

}

If I call it with a foreach then I can easily get result of which ones had success and which had and error and what it was e.g.

  $computers = @("PC-1", "PC-2", "PC-3", "PC-4","PC-5")

Foreach ($computertonotify in $computers) {

            Write-Progress -Activity "Sending toast notifcation" -Status $computertonotify -PercentComplete (($count / $computers.Count) * 100)

            $result = Invoke-Command -ComputerName $computertonotify -ScriptBlock ${function:Show-Toast}  -ArgumentList "IT Department", "IGNORE - TESTING ONLY"

            if ($result -eq "Success") {
                $toastsuccess += $computertonotify
            }
            else {
                $toastfailed += $computertonotify
                If ($result.Message.Contains("The notification platform is unavailable")) { $toastfailedwithreason += $computertonotify + " (Computer Logged Off)" } Else { $toastfailedwithreason += $computertonotify + " ($result)" }

            }

            $count += 1

        }

But if I call same function with all computers at once - how do I get "success" or the returned error information?

$computers = @("PC-1", "PC-2", "PC-3", "PC-4","PC-5")

$result = Invoke-Command -ComputerName $computers -ScriptBlock ${function:Show-Toast}  -ArgumentList "IT Department", "IGNORE - TESTING ONLY" 
Windows for business | Windows Server | User experience | PowerShell
0 comments No comments

Answer accepted by question author

Rich Matheisen 48,116 Reputation points
2021-02-16T20:05:05.66+00:00

Redirect stream #2 (the Error Stream) to stream #1 (the Success Stream):

$remotecheck = Invoke-Command -ComputerName $computers { 1 } 2>&1

To differentiate between the data you expect and an error you'll have to check the type:

if ($remotecheck[$i] -is [System.Management.Automation.ErrorRecord]){
    do something
}
else{
    do something else
}

Was this answer helpful?

2 people found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.