Invoke-Command connection errors

This topic contains 5 replies, has 3 voices, and was last updated by Profile photo of Darwin Reiswig Darwin Reiswig 1 year, 3 months ago.

  • Author
    Posts
  • #31274
    Profile photo of Darwin Reiswig
    Darwin Reiswig
    Participant

    I'm feeding an Invoke-Command a list of servers to run a script and return results. Everything works as I want, except for servers that it cannot connect to (obviously).

    What I would like is to have the script also output a list of the computers that were unable to successfully connect with the Invoke-Command, so I know which ones were offline and not part of the results (instead of just seeing the default error messages).

    The important part of the code currently looks something like this:

    $Results = @()
    $Results = invoke-command -computername 'PC1','PC2','OfflinePC','PC3','PC4'
    {get-service}
    write-output $Results

  • #31277
    Profile photo of Don Jones
    Don Jones
    Keymaster

    You probably need to do one computer at a time, so that when one fails, you know which one it was.

    $computers = @('PC1','PC2','OfflinePC','PC3','PC4')
    foreach ($computer in $computers) {
      Try {
        Invoke-Command -Script { get-service } -Computer $computer -ErrorAction Stop
      } catch {
        Write-Warning "$computer failed"
      }
    }
    

    You don't get parallelization that way, though. A different approach would be to use jobs.

    invoke-command -computername 'PC1','PC2','OfflinePC','PC3','PC4' -AsJob
    

    You'll get a master job for the entire command, with sub-jobs that track each machine. You'll be able to run Receive-Job to get the results, and easily see which ones failed.

  • #31296
    Profile photo of Mike Eyler
    Mike Eyler
    Participant

    IMHO, there's no need to do an invoke command when using get-service.

    try this, It will list the failed computer name in the error message.

    $Servers = ('localhost','Server1','Computer2')

    foreach($Server in $Servers){
    $Output = Get-Service -ComputerName $Server | select machinename,status,name,displayname
    $Output
    }

  • #31299
    Profile photo of Darwin Reiswig
    Darwin Reiswig
    Participant

    The get-service command was just an example. I'm actually doing something more complicated in the invoke-command, but I didn't want to confuse the question with that information.

    I will try the AsJob code and see how that goes.

    Thanks!

  • #31301
    Profile photo of Mike Eyler
    Mike Eyler
    Participant

    "The get-service command was just an example. I'm actually doing something more complicated in the invoke-command"

    Please post, I'm interested in learning more about using the invoke-command.

  • #31312
    Profile photo of Darwin Reiswig
    Darwin Reiswig
    Participant

    Here's the full script. I stole the heart of it from another script that did much more than I needed it to do. The thing I needed was just to see which computers were offline and which still had uninstalled updates, so I could tell that my scheduled install of server updates actually got them all installed and that nobody was still rebooting. I coded the ability to get the update data as the only output, but for my usual purposes it just displays that and then a list of offline computers and a list of computers needing updates.

    Function Get-PendingWindowsUpdates
    {

    [CmdletBinding()]
    Param(
    [Parameter(Mandatory=$True,Position=1,ParameterSetName='List')]
    [string[]]$ComputerName='localhost',
    [Parameter(Mandatory=$False)]
    [switch]$RawOutput
    )

    Begin {

    Remove-Job 'MSPatch' -ErrorAction SilentlyContinue

    Invoke-Command -ComputerName $ComputerName -AsJob -JobName MSPatch -ScriptBlock {

    Write-Verbose "Start of script on $Computer"
    #$VerbosePreference=$Using:VerbosePreference
    $Computer = $env:COMPUTERNAME

    $UpdateCollection = @()
    Write-Verbose "Create Microsoft.Update.Session object for $Computer"
    $objSession = [activator]::CreateInstance([type]::GetTypeFromProgID("Microsoft.Update.Session",$Computer))

    Write-Verbose "Create Microsoft.Update.Session.Searcher object for $Computer"
    $objSearcher = $objSession.CreateUpdateSearcher()

    $objResults = $objSearcher.Search("IsInstalled = 0")
    $PreFoundUpdatesToDownload = $objResults.Updates.count
    Write-Verbose "Found [$PreFoundUpdatesToDownload] Updates in pre search criteria"

    Foreach($Update in $objResults.Updates)
    {

    $Status = ""
    If($Update.IsDownloaded) {$Status += "D"} else {$status += "-"}
    If($Update.IsInstalled) {$Status += "I"} else {$status += "-"}
    If($Update.IsMandatory) {$Status += "M"} else {$status += "-"}
    If($Update.IsHidden) {$Status += "H"} else {$status += "-"}
    If($Update.IsUninstallable) {$Status += "U"} else {$status += "-"}
    If($Update.IsBeta) {$Status += "B"} else {$status += "-"}

    Add-Member -InputObject $Update -MemberType NoteProperty -Name ComputerName -Value $Computer
    Add-Member -InputObject $Update -MemberType NoteProperty -Name KB -Value $Update.KBArticleIDs
    Add-Member -InputObject $Update -MemberType NoteProperty -Name Size -Value $Update.MaxDownloadSize
    Add-Member -InputObject $Update -MemberType NoteProperty -Name Status -Value $Status

    $Update.PSTypeNames.Clear()
    $Update.PSTypeNames.Add('PSWindowsUpdate.WUList')

    If ($Update.IsDownloaded) {$UpdateCollection += $Update}
    } #End Foreach $Update in $objResults.Updates

    $FoundUpdatesToDownload = $UpdateCollection.count
    Write-Verbose "Found [$FoundUpdatesToDownload] Updates in post search criteria"
    Return $UpdateCollection
    } #End Invoke

    Get-Job 'MSPatch' | Wait-Job

    $JobList = Get-Job 'MSPatch' -IncludeChildJob
    $ComputerFailed = @()
    $ComputerHasPatch = @()
    $UpdateAllList = @()

    ForEach ($Job in $Joblist) {
    If ($Job.name -like 'Job*') {
    Write-Verbose $Job.Location
    If ($Job.state -like "Failed") {
    Write-Verbose "Computer is offline"
    $ComputerFailed += $Job.Location
    }
    If ($Job.HasMoreData -eq $True) {
    Write-Verbose "Computer has patches"
    $ComputerHasPatch += $Job.Location
    $UpdateAllList += Receive-Job $Job.Id
    }
    }
    }
    Remove-Job 'MSPatch' -ErrorAction SilentlyContinue

    If ($RawOutput) {
    Write-Output $UpdateAllList
    } else {
    $UpdateAllList | Sort-Object -Property Computername,KB | Format-Table -Property ComputerName,KB,Size,Status,Title -AutoSize
    Write-Output "Computers with updates"
    $ComputerHasPatch
    Write-Output ""
    Write-Output "Offline Computers"
    $ComputerFailed
    }
    }
    } #End Function Get-PendingWindowsUpdates

You must be logged in to reply to this topic.