Search code examples
powershellselect-object

Script has two variables when done, but when I pipe to SELECT-object only first one returns data to console


I am trying to query multiple servers with WMI, but I don't always have access to the servers.

The code is below. Alas, it returns "access is denied" to the console, but I can't seem to get rid of it. Oh well.

However, I am trapping the servers that I can't connect to, so that I can tell someone else to look at them, or request access.

But when I run the code, it only returns the first list of servers; even if $failed_servers has values, nothing is returned. If I tell both to pipe to ogv, then two windows pop up.

Why won't both "$variable|select" work? If I remove the select on $failed_servers, then it shows up, albeit just sitting immediately underneath the successful ones. Which is okay-but-not-great.

$list = ("servera","serverb","serverc")
$failed_servers = @()
$final = foreach ($server_instance in $list)
{
$errors=@()
gwmi -query "select * from win32_service where name like '%SQLSERVER%'" -cn $server_instance -ErrorVariable +errors -ErrorAction SilentlyContinue
if ($errors.Count -gt 0) {$failed_servers += $server_instance
}
}

$final|select pscomputername, name, startmode, state |where {$_.pscomputername -ne $null}

$failed_servers |select @{N='Failed Servers'; E={$_}}

Solution

  • What you're experiencing is merely a display problem:

    • Both your Select-Object calls produce output objects with 4 or fewer properties whose types do not have explicit formatting data associated with them (as reported by Get-FormatData).

    • This causes PowerShell's for-display output formatting system to implicitly render them via the Format-Table cmdlet.

    • The display columns that Format-Table uses are locked in based on the properties of the very first object that Format-Table receives.

    • Therefore, your second Select-Object call, whose output objects share no properties with the objects output by the first one, effectively produces no visible output - however, the objects are sent to the success output stream and are available for programmatic processing.

    A simple demonstration:

    & {
      # This locks in Month and Year as the display columns of the output table.
      Get-Date   | Select-Object Month, Year
      # This command's output will effectively be invisible,
      # because the property set Name, Attributes does not overlap with
      # Month, Year
      Get-Item \ | Select-Object Name, Attributes
    }
    

    The output will look something like this - note how the second statement's output is effectively invisible (save for an extra blank line at the end):

    
    Month Year
    ----- ----
        9 2021
    
    
    

    Note the problem can even affect a single statement that outputs objects of disparate types (whose types don't have associated formatting data); e.g.:
    (Get-Date | Select-Object Year), (Get-Item \ | Select-Object Name)


    Workarounds:

    • Applying | Format-List to the command above makes all objects visible, though that obviously changes the display format.

    • Intra-script you could pipe each Select-Object pipeline to Out-Host to force instant, pipeline-specific formatting, but - given that the results are sent directly to the host rather than to the success output stream - this technique precludes further programmatic processing.


    Potential future improvements:

    GitHub issue #7871 proposes at least issuing a warning if output objects effectively become invisible.