none
Value mit New-Item über eine Pipe einlesen

    Frage

  • Hallo zusammen.

    Ich stehe vor einem "Problem", dessen Ursache ich nicht verstehe.

    Ich möchte neue Dateien und Verzeichnisse erstellen und die dazu nötigen Daten aus einer Pipe verwenden. Laut Dokumentation unterstützen die Parameter Path, ItemType und Value Eingaben über eine Pipe als ByPropertyName, also über den Namen der Eigenschaft. Dies funktioniert hervorragend mit Path und ItemType, jedoch nicht mit Value. Das nachfolgende Beispiel zeigt dies.

    PS> $data = @" Path:ItemType:Value datei.txt:File:Hallo Welt verzeichnis:Directory: "@ PS> $data | ConvertFrom-Csv -Delimiter : | New-Item -Force

    PS> Get-Content .\datei.txt
    @{Path=datei.txt; ItemType=File; Value=Hallo Welt}

    Zur Lösung müsste ich das Kommando ausschreiben:

    $data | ConvertFrom-Csv -Delimiter : |% { New-Item -Path $_.Path -ItemType $_.ItemType -Value $_.Value -Force }
    

    Kann mir jemand erklären, wodurch sich die Probleme mit der Pipe im oberen Codeblock ergeben?

    Vielen Dank. cc

    Montag, 10. September 2018 12:29

Antworten

  • > (es wird ja auch hier ein String geliefert).

    Und auch der ist ein Objekt... Abgesehen davon hab ich grad auch nicht wirklich ne Ahnung, was da "under the hood" passiert.

    Naja, unter die Haube können wir ja einen vorsichtigen Blick riskieren:

    Trace-Command -Name ParameterBinding -Expression {$data | ConvertFrom-Csv -Delimiter : | New-Item -Force} -PSHost

    und sehen dann

    BIND PIPELINE object to parameters: [New-Item]
        PIPELINE object TYPE = [System.Management.Automation.PSCustomObject]
        RESTORING pipeline parameter's original values
        Parameter [Value] PIPELINE INPUT ValueFromPipeline NO COERCION
        BIND arg [@{Path=datei.txt; ItemType=File; Value=Hallo Welt}] to parameter [Value]
            BIND arg [@{Path=datei.txt; ItemType=File; Value=Hallo Welt}] to param [Value] SUCCESSFUL
        Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
        Parameter [ItemType] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
        BIND arg [File] to parameter [ItemType]
            BIND arg [File] to param [ItemType] SUCCESSFUL
        Parameter [Path] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
        BIND arg [datei.txt] to parameter [Path]
            Binding collection parameter Path: argument type [String], parameter type [System.String[]], collection type Array, element type [System.String], no coerceElementType
            Creating array with element type [System.String] and 1 elements
            Argument type String is not IList, treating this as scalar
            Adding scalar element of type String to array position 0
            BIND arg [System.String[]] to param [Path] SUCCESSFUL
        Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName WITH COERCION
        Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName WITH COERCION
    MANDATORY PARAMETER CHECK on cmdlet [New-Item]

    Das Blöde ist, wie ich vermute, dass man Value nicht nur nach Namen sondern auch nach Wert binden kann:

    Get-Help New-Item -Parameter Value
    
    -Value <Object>
        
        Erforderlich?                false
        Position?                    Benannt
        Pipelineeingaben akzeptieren?true (ByValue, ByPropertyName)
        Name des Parametersatzes           (Alle)
        Aliase                      Target
        Dynamisch?                     false
    Also bindet er da das gesamte übergebene PSCustomObject und ist zufrieden. Im zweiten Beispiel bindest Du explizit nach Namen, daher kommt auch das Gewünschte rein.


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    • Als Antwort markiert cgplc Montag, 10. September 2018 19:50
    Montag, 10. September 2018 14:58
  • > Ergebnis hier gebloggt <https://it-pro-berlin.de/2018/09/powershell-quirks-values-aus-der-pipeline-object-edition/>

    Da hast Du beide Params als [string] definiert. Was passiert denn, wenn einer davon [object] ist?

    Ich verrat's Dir gleich :-) Das ist das gleiche wie bei New-Item... Ein [object] krallt sich immer das ganze Objekt, wie es aussieht. Und zwar bevorzugt als ByType statt ByPropertyName

    MyOtherParm:
    MyOtherParmValue
    Type:string
    MyInput:
    
    MyInput      MyOtherParm      ForeignParm   
    -------      -----------      -----------   
    MyInputValue MyOtherParmValue ShouldNotSeeMe
    Type:System.Management.Automation.PSCustomObject


    Dienstag, 11. September 2018 15:56

Alle Antworten

  • Hallo,

    Mit:

    get-help new-item

    # Output

    SYNTAX
        New-Item [-Path] <string[]> [-ItemType <string>] [-Value <Object>] [-Force] [-Credential <pscredential>] [-WhatIf] [-Confirm] [-UseTransaction]
        [<CommonParameters>]

    siehst Du, dass Path und ItemTyp einen String verlangen, den Du ja auch lieferst, Value aber ein Objekt benötigt und daher der Direkt Aufruf in diesem Fall nicht funktioniert (es wird ja auch hier ein String geliefert).

    Montag, 10. September 2018 12:48
  • > (es wird ja auch hier ein String geliefert).

    Und auch der ist ein Objekt... Abgesehen davon hab ich grad auch nicht wirklich ne Ahnung, was da "under the hood" passiert.

    Montag, 10. September 2018 13:45
  • Hallo,

    Mit:

    get-help new-item

    # Output

    SYNTAX
        New-Item [-Path] <string[]> [-ItemType <string>] [-Value <Object>] [-Force] [-Credential <pscredential>] [-WhatIf] [-Confirm] [-UseTransaction]
        [<CommonParameters>]

    siehst Du, dass Path und ItemTyp einen String verlangen, den Du ja auch lieferst, Value aber ein Objekt benötigt und daher der Direkt Aufruf in diesem Fall nicht funktioniert (es wird ja auch hier ein String geliefert).

    Ein String ist ein Object, daher kann ich Deine Erklärung nicht nachvollziehen. Der Typ Object bedeutet lediglich, dass _jeder_ Typ übergeben werden kann, da _alle_ Datentypen von Object abgeleitet sind. Zudem dürfte nach Deiner Erklärung die ausführliche Variante nicht funktionieren, denn auch hier wird ein String übergeben. Die ausführliche Variante funktioniert aber hervorragend.

    cc

    Montag, 10. September 2018 14:24
  • > (es wird ja auch hier ein String geliefert).

    Und auch der ist ein Objekt... Abgesehen davon hab ich grad auch nicht wirklich ne Ahnung, was da "under the hood" passiert.

    Naja, unter die Haube können wir ja einen vorsichtigen Blick riskieren:

    Trace-Command -Name ParameterBinding -Expression {$data | ConvertFrom-Csv -Delimiter : | New-Item -Force} -PSHost

    und sehen dann

    BIND PIPELINE object to parameters: [New-Item]
        PIPELINE object TYPE = [System.Management.Automation.PSCustomObject]
        RESTORING pipeline parameter's original values
        Parameter [Value] PIPELINE INPUT ValueFromPipeline NO COERCION
        BIND arg [@{Path=datei.txt; ItemType=File; Value=Hallo Welt}] to parameter [Value]
            BIND arg [@{Path=datei.txt; ItemType=File; Value=Hallo Welt}] to param [Value] SUCCESSFUL
        Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
        Parameter [ItemType] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
        BIND arg [File] to parameter [ItemType]
            BIND arg [File] to param [ItemType] SUCCESSFUL
        Parameter [Path] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
        BIND arg [datei.txt] to parameter [Path]
            Binding collection parameter Path: argument type [String], parameter type [System.String[]], collection type Array, element type [System.String], no coerceElementType
            Creating array with element type [System.String] and 1 elements
            Argument type String is not IList, treating this as scalar
            Adding scalar element of type String to array position 0
            BIND arg [System.String[]] to param [Path] SUCCESSFUL
        Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName WITH COERCION
        Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName WITH COERCION
    MANDATORY PARAMETER CHECK on cmdlet [New-Item]

    Das Blöde ist, wie ich vermute, dass man Value nicht nur nach Namen sondern auch nach Wert binden kann:

    Get-Help New-Item -Parameter Value
    
    -Value <Object>
        
        Erforderlich?                false
        Position?                    Benannt
        Pipelineeingaben akzeptieren?true (ByValue, ByPropertyName)
        Name des Parametersatzes           (Alle)
        Aliase                      Target
        Dynamisch?                     false
    Also bindet er da das gesamte übergebene PSCustomObject und ist zufrieden. Im zweiten Beispiel bindest Du explizit nach Namen, daher kommt auch das Gewünschte rein.


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    • Als Antwort markiert cgplc Montag, 10. September 2018 19:50
    Montag, 10. September 2018 14:58
  • Parameter [Value] PIPELINE INPUT ValueFromPipeline NO COERCION

    Parameter [ItemType] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION

    Parameter [Path] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION

    Das Blöde ist, wie ich vermute, dass man Value nicht nur nach Namen sondern auch nach Wert binden kann:

    Ich vermute mal, Du vermutest recht ;) Ich musste aber auch zweimal hinschauen, bevor ich die relevante Information gesehen habe. Ich habe die Ausgabe von Trace-Command entsprechend gekürzt.

    Dieses Verhalten ist wirklich ärgerlich, denn es bedeutet, dass ganz allgemein die Kombination "ValueFromPipeline" und "ValueFromPipelineByPropertyName" in den Attributen der Parameter keine gute Idee ist, denn das "ValueFromPipelineByPropertyName" kann nur dann funktionieren, wenn diese Eigenschaft auch die einzige Eigenschaft ist.

    Vielen Dank, cc

    Montag, 10. September 2018 15:25
  • Dieses Verhalten ist wirklich ärgerlich, denn es bedeutet, dass ganz allgemein die Kombination "ValueFromPipeline" und "ValueFromPipelineByPropertyName" in den Attributen der Parameter keine gute Idee ist, denn das "ValueFromPipelineByPropertyName" kann nur dann funktionieren, wenn diese Eigenschaft auch die einzige Eigenschaft ist.

    Vielen Dank, cc

    Nee, verallgemeinern würde ich das nicht. Ich habe das zwischenzeitlich untersucht und das Ergebnis hier gebloggt. Ich werde mal schauen, ob wir jemanden anhauen können, der das vielleicht erklärt oder als Bug in New-Item bestätigt.

    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    Montag, 10. September 2018 15:54
  • > Ergebnis hier gebloggt <https://it-pro-berlin.de/2018/09/powershell-quirks-values-aus-der-pipeline-object-edition/>

    Da hast Du beide Params als [string] definiert. Was passiert denn, wenn einer davon [object] ist?

    Ich verrat's Dir gleich :-) Das ist das gleiche wie bei New-Item... Ein [object] krallt sich immer das ganze Objekt, wie es aussieht. Und zwar bevorzugt als ByType statt ByPropertyName

    MyOtherParm:
    MyOtherParmValue
    Type:string
    MyInput:
    
    MyInput      MyOtherParm      ForeignParm   
    -------      -----------      -----------   
    MyInputValue MyOtherParmValue ShouldNotSeeMe
    Type:System.Management.Automation.PSCustomObject


    Dienstag, 11. September 2018 15:56
  • Test: Ich antworte jetzt mal mit Quatsch und schau, ob Martins CloudBridge-Antwort gleich auftaucht...

    In der Tat... Das Web-Reply scheint im Hintergrund einen Sync anzustoßen, den Bridge-Replys nicht anstoßen... #grützebleibtgrütze :-))

    Greetings/Grüße, Martin - https://mvp.microsoft.com/en-us/PublicProfile/5000017 Mal ein gutes Buch über GPOs lesen? - http://www.amazon.de/Windows-Server-2012--8-Gruppenrichtlinien/dp/3866456956 Good or bad GPOs? My blog - http://evilgpo.blogspot.com And if IT bothers me? Coke bottle design refreshment - http://sdrv.ms/14t35cq

    Dienstag, 11. September 2018 16:08
  • > Ergebnis hier gebloggt <https://it-pro-berlin.de/2018/09/powershell-quirks-values-aus-der-pipeline-object-edition/>

    Da hast Du beide Params als [string] definiert. Was passiert denn, wenn einer davon [object] ist?

    Ja, richtig, das fehlte noch. Dann ist das Verhalten in etwa so wie bei New-Item. Trage ich gleich nach.

    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    Dienstag, 11. September 2018 16:11