PowerShell / PowerShell/PowerShell

Objects are unexpectedly accumulated when a CimCmdlet or CDXML-based command is in the middle of a pipeline

Offen
#25,241 1 Kommentar 2 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Needs-Triage WG-Cmdlets
Vorherrschende Sprache
C#
Sterne
55.5k
Forks
8.5k
Ø Merge
1 T. 2 Std.
Gemergte PRs (30 T.)
88

Beschreibung

Prerequisites
Summary

When a CimCmdlet cmdlet or CDXML function is in the middle of a pipeline (not first/last), the following appears to occur:

  • Objects processed by the CimCmdlet/CDXML command are unexpectedly accumulated in the middle of the pipeline.
  • Once all objects have been processed in the middle of the pipeline, EndProcessing is called on the CimCmdlet/CDXML command and any upstream commands.
  • Downstream commands finally start to receive input.

Related:

Steps to reproduce
$cn = [pscustomobject] @{ ClassName = 'Win32_ComputerSystem' }
$c = [Console]

1, 2, 3 |
    ForEach-Object -Begin { $c::WriteLine('B1') } -Process { $c::WriteLine('P1'); $cn } -End { $c::WriteLine('E1') } |
    Get-CimInstance |
    ForEach-Object -Begin { $c::WriteLine('B2') } -Process { $c::WriteLine('P2') } -End { $c::WriteLine('E2') }

# B1
# B2
# P1
# P1
# P1 <-- Objects accumulated instead of passing through
# E1 <-- EndProcessing prematurely called
# P2 <-- Finally, objects pass through to downstream commands
# P2
# P2
# E2
Trace-Command excerpt:
ParameterBinding Information: 0 : BIND arg [Win32_ComputerSystem] to param [ClassName] SUCCESSFUL
[...]
ParameterBinding Information: 0 : BIND arg [Win32_ComputerSystem] to param [ClassName] SUCCESSFUL
[...]
ParameterBinding Information: 0 : BIND arg [Win32_ComputerSystem] to param [ClassName] SUCCESSFUL
[...]
ParameterBinding Information: 0 : CALLING EndProcessing <--- Write-Output
ParameterBinding Information: 0 : CALLING EndProcessing <--- ForEach-Object (#1)
ParameterBinding Information: 0 : CALLING EndProcessing <--- Get-CimInstance
ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [ForEach-Object]
[...]
ParameterBinding Information: 0 : CALLING EndProcessing <--- ForEach-Object (#2)
Impact

This fundamentally breaks PowerShell's item-by-item processing when the middle of a pipeline involves a CimCmdlet/CDXML command. For example, short-circuiting with Select-Object -First cannot be performed. Notice how commands upstream from Get-Disk must process all objects before Select-Object can raise its stop processing exception.

Get-Partition | 
    ForEach-Object { [Console]::WriteLine('1'); $_ } | 
    Get-Disk | 
    ForEach-Object { [Console]::WriteLine('2'); $_ } | 
    Select-Object -First 1

# 1
# 1
# 1
# 1
# 1
# 1
# 2

-PipelineVariable is broken in the process. The exact behavior depends on the type and position of the CimCmdlet/CDXML command.

  • Downstream contains CimCmdlet/CDXML command:

    # Applicable when the first command is not a CDXML command. 
    # The first command *can* be a CimCmdlet command.
    Write-Output 1 2 3 -pv var |
        ForEach-Object { [Console]::WriteLine("1: $var"); [pscustomobject] @{ Number = 0 } } |
        Get-Disk |
        ForEach-Object { [Console]::WriteLine("2: $var") }
    
    # 1: 1
    # 1: 2
    # 1: 3
    # 2: 3 <-- PV remains as the last accumulated object
    # 2: 3
    # 2: 3
    
  • Downstream contains CimCmdlet/CDXML AND the first command is CDXML:

    Get-Partition -pv var |
        ForEach-Object { [Console]::WriteLine("1: $($var.PartitionNumber)"); $_ } |
        Get-Disk |
        ForEach-Object { [Console]::WriteLine("2: $($var.PartitionNumber)") }
    
    # 1: 1
    # 1: 2
    # 1: 3
    # 1: 4
    # 1: 5
    # 1: 6
    # 2:   <-- PV is reset to $null
    # 2:
    # 2:
    # 2:
    # 2:
    # 2:
    

    The above scenario is the subject of https://github.com/PowerShell/PowerShell/issues/20546.

Expected behavior
  • Objects flow through the pipeline one-by-one from start to end instead of being unexpectedly accumulated.
  • EndProcessing is not called prematurely on upstream commands in the middle of a pipeline.
B1
B2
P1
P2
P1
P2
P1
P2
E1
E2
Actual behavior
B1
B2
P1
P1
P1
E1
P2
P2
P2
E2
Environment data
Name                           Value
----                           -----
PSVersion                      7.6.0-preview.3
PSEdition                      Core
GitCommitId                    7.6.0-preview.3
OS                             Microsoft Windows 10.0.19045
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0, 5.0, 5.1…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne damit, den bereitgestellten CimCmdlet/CDXML-Pipeline-Reproduzierer auszuführen und seine Ausgabe mit der erwarteten Sequenz Element für Element zu vergleichen. Verwende den enthaltenen Trace-Command-Auszug, um EndProcessing und die Pipelinebindung nachzuverfolgen; die Aufgabe ist abgeschlossen, wenn Objekte nacheinander bei nachgelagerten Befehlen ankommen, ohne vorzeitiges EndProcessing des vorgelagerten Befehls.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
powershell
Bereich
cli
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.