none
Return PSCustomObject Problem RRS feed

  • Frage

  • Hallo,

    wenn ich folgenden Code ausführe bekomme ich den String "test123" ausgegeben.

    function test1 { $test = New-Object PSObject $test | Add-Member -MemberType NoteProperty -Name "a" -Value "test123" $test | Add-Member -MemberType NoteProperty -Name "b" -Value "test456" return $test } $var1 = test1 $var1.a

    Dieses Prinzip habe ich auf etwas komplexeres angewandt und bekomme nun nichts mehr zurückgegeben.

    function test2
    {
        [IO.FileInfo]$FilePath = "PFAD ZU EINER BELIEBIGEN MSI DATEI"
        $PropertyList = @("ProductCode","ProductVersion","ProductName")
        $ReturnObject = New-Object PSObject
    
        Try
        {
            $WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer
            $MSIDatabase = $WindowsInstaller.GetType().InvokeMember("OpenDatabase","InvokeMethod",$Null,$WindowsInstaller,@($FilePath.FullName,0))
    
            Foreach ($Property in $PropertyList)
            {
                $Query = "SELECT Value FROM Property WHERE Property = '$Property'"
                $View = $MSIDatabase.GetType().InvokeMember("OpenView","InvokeMethod",$null,$MSIDatabase,($Query))
                $View.GetType().InvokeMember("Execute", "InvokeMethod", $null, $View, $null)
                $Record = $View.GetType().InvokeMember("Fetch","InvokeMethod",$null,$View,$null)
                $Value = $Record.GetType().InvokeMember("StringData","GetProperty",$null,$Record,1)
                $ReturnObject | Add-Member -MemberType NoteProperty -Name "$Property" -Value $Value
            } 
        }
        
        Catch
        {
            Write-Output $_.Exception.Message
        }
              
        return $ReturnObject
    
    }
    
    $var2 = test2
    $var2.ProductCode


    In der Variable

    $var2

    steht bei mir folgender Inhalt

    PS C:\Windows\system32> $var2 | get-member
    
    
       TypeName: System.Management.Automation.PSCustomObject
    
    Name           MemberType   Definition                                                          
    ----           ----------   ----------                                                          
    Equals         Method       bool Equals(System.Object obj)                                      
    GetHashCode    Method       int GetHashCode()                                                   
    GetType        Method       type GetType()                                                      
    ToString       Method       string ToString()                                                   
    ProductCode    NoteProperty System.String ProductCode={C43920E3-2939-455A-B1E2-8A0673A5FFCA}    
    ProductName    NoteProperty System.String ProductName=Cisco AnyConnect Start Before Login Module
    ProductVersion NoteProperty System.String ProductVersion=4.2.04018 

    trotzdem bekomme ich bei

    $var2.ProductCode

    keine Ausgabe.

    PowerShell Version:

    Name                           Value                                                                                                                                                         
    ----                           -----                                                                                                                                                         
    CLRVersion                     2.0.50727.5485                                                                                                                                                
    BuildVersion                   6.1.7601.17514                                                                                                                                                
    PSVersion                      2.0                                                                                                                                                           
    WSManStackVersion              2.0                                                                                                                                                           
    PSCompatibleVersions           {1.0, 2.0}                                                                                                                                                    
    SerializationVersion           1.1.0.1                                                                                                                                                       
    PSRemotingProtocolVersion      2.1                         
    Kann mir hier irgendwer Helfen oder einen Tipp geben?

    Donnerstag, 28. Juli 2016 09:36

Antworten

  • Funtioniert das hier?

    function test2
    {
        [IO.FileInfo]$FilePath = "PFAD ZU EINER BELIEBIGEN MSI DATEI"
        $PropertyList = @("ProductCode","ProductVersion","ProductName")
        $ReturnObject = New-Object PSObject
    
        Try
        {
            $WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer
            $MSIDatabase = $WindowsInstaller.GetType().InvokeMember("OpenDatabase","InvokeMethod",$Null,$WindowsInstaller,@($FilePath.FullName,0))
    
            Foreach ($Property in $PropertyList)
            {
                $Query = "SELECT Value FROM Property WHERE Property = '$Property'"
                $View = $MSIDatabase.GetType().InvokeMember("OpenView","InvokeMethod",$null,$MSIDatabase,($Query))
                $View.GetType().InvokeMember("Execute", "InvokeMethod", $null, $View, $null) > $null
                $Record = $View.GetType().InvokeMember("Fetch","InvokeMethod",$null,$View,$null)
                $Value = $Record.GetType().InvokeMember("StringData","GetProperty",$null,$Record,1)
                $ReturnObject | Add-Member -MemberType NoteProperty -Name "$Property" -Value $Value
            } 
        }
        
        Catch
        {
            Write-Host $_.Exception.Message
        }
              
        return $ReturnObject
    
    }
    
    $var2 = test2
    $var2.ProductCode

    Wie schon gesagt, es liegt am Output-Stream. Wenn du den Code nicht als Funktion ausführst, wird jeder Output an die Console übergeben. Wenn du es als Funktion ausführst wird es an die Rückgabe der Funktion übergeben. Als Beispiel versuch mal das hier:

    function test
    {
        "ABC"
        $a = 42
        Write-Host "Dies kommt direkt die Console"
        New-Item "C:\Temp\Test.txt" -ItemType File -Force
    
        return $a
    }
    
    $c = Test

    und das hier:

    function test
    {
        "ABC" > $null
        $a = 42
        Write-Host "Dies kommt direkt die Console"
        New-Item "C:\Temp\Test.txt" -ItemType File -Force > $null
    
        return $a
    }
    
    $c = Test

    Im ersten Fall hast du auch das "ABC" und das neu erstellte Datei-Objekt in der Rückgabe. In letzterem werden alle Ausgaben abgefangen, außer der, die wir wollen. Die return-Anweisung ist NICHT die ausschließliche Rückgabe bei einer PowerShell-Funktion!



    • Bearbeitet hpotsirhc Freitag, 29. Juli 2016 06:05
    • Als Antwort markiert 0x4d2 Freitag, 29. Juli 2016 06:27
    Freitag, 29. Juli 2016 06:04

Alle Antworten

  • Hallo,

    ich habe deinen Code für meinen Test etwas reduziert und einfach Zufallszahlen eintragen lassen. Dabei konnte ich keinen Fehler finden.

    Da Get-Member die Werte bei dir anzeigt, müssen sie auch vorhanden sein. Eigentlich muss es funktionieren.

    Du könntest höchstens nochmal $var2.GetType() versuchen.

    Viele Grüße

    Christoph


    • Bearbeitet hpotsirhc Donnerstag, 28. Juli 2016 09:52
    Donnerstag, 28. Juli 2016 09:52
  • Hey,

    __________________________________________________________________________________________________________________________________________________________________________________________
    PS C:\Windows\system32> $var1.GetType()
    
    IsPublic IsSerial Name                                     BaseType                                                                                                                          
    -------- -------- ----                                     --------                                                                                                                          
    True     False    PSCustomObject                           System.Object                                                                                                                     
    
    
    
    __________________________________________________________________________________________________________________________________________________________________________________________
    PS C:\Windows\system32> $var2.GetType()
    
    IsPublic IsSerial Name                                     BaseType                                                                                                                          
    -------- -------- ----                                     --------                                                                                                                          
    True     True     Object[]                                 System.Array                                                                                                                      
    
    
    
    __________________________________________________________________________________________________________________________________________________________________________________________
    

    danke für den Tipp mit .GetType()
    Ich glaube hier liegt der Fehler.
    Hast du auch eine Idee wie ich das am besten gefixt bekomme?

    Donnerstag, 28. Juli 2016 09:56
  • Moin,

    caste doch den Wert von $Value zu String, bevor Du ihn zuweist:

    $ReturnObject | Add-Member -MemberType NoteProperty -Name "$Property" -Value ([string]$Value)

    oder

    $ReturnObject | Add-Member -MemberType NoteProperty -Name "$Property" -Value ($Value.ToString())

    je nachdem, was davon funktioniert.


    Evgenij Smirnov

    msg services ag, Berlin -> http://www.msg-services.de
    my personal blog (mostly German) -> http://it-pro-berlin.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.

    Donnerstag, 28. Juli 2016 10:59
  • Hey,

    beides macht bei mir leider keinen Unterschied :(

    PS C:\Windows\system32> $var2.gettype()
    
    IsPublic IsSerial Name                                     BaseType                                                                                                       
    -------- -------- ----                                     --------                                                                                                       
    True     True     Object[]                                 System.Array                                                                                                   
    
    

    Donnerstag, 28. Juli 2016 11:21
  • Aha, es ist ein Array. 

    In PowerShell 4.0 (und wahrscheinlich auch 3.0) bekommst du beim Aufruf von $a.p die Werte der Eigenschaft p für alle Elemente des Arrays $a. 

    In PowerShell 2.0 geht das noch nicht. Wenn $a ein Einzelelement ist, wird dir mit $a.p der Wert der Eigenschaft p wiedergegeben. Ist es ein Array, kommt einfach nichts.

    Versuch mal $Var2[0].ProductCode.

    Übrigens: Get-Member hat die Werte angezeigt, weil es nicht das Objekt selbst untersucht, sondern im Falle eines Arrays die einzelnen Elemente.



    • Bearbeitet hpotsirhc Donnerstag, 28. Juli 2016 12:02
    Donnerstag, 28. Juli 2016 12:00
  • Ich sehe gerade, aber ich kann deinen Code leider nicht bei mir laufen lassen:

    Diese Zeile

     $View.GetType().InvokeMember("Execute", "InvokeMethod", $null, $View, $null)

    Ist eine Methode, deren Output in den Output-Stream geht. Wenn Sie einen Output hat. Versuch mal die Zeile mit

    > $null

    oder 

    | Out-Null

    abzuschließen. Funktionen sammeln die Rückgaben, die sonst in der Console angezeigt würden. Es wird nicht nur der mit return angegebene Rückgabewert übergeben, sondern der gesamte Output-Stream. Daher sollten in Funktionen oder aufgerufenen Skripten alle Methodenaufrufe immer ein "=" enthalten oder in die $null-Variable (ins Schwarze Loch) verbannt werden.

    Donnerstag, 28. Juli 2016 12:09
  • $Var2[0].ProductCode


    Funtktioniert leider nicht.
    Aber ich möchte die Rückgabe eigentlich auch als

    System.Object

    Wie bei $var1 in meinem Beispiel.
    Das muss doch irgendwie funktionieren..

    Hast du zum testen ein MSI File angegeben?

    Donnerstag, 28. Juli 2016 12:53
  • Dann schau nochmal auf meinen letzten Beitrag, das müsste es eigentlich sein.

    Ansonsten versuch mal andere Indices als 0, vielleicht -1. Aber du hast natürlich Recht, das Array muss weg.

    Donnerstag, 28. Juli 2016 12:58
  • -1 Funktioniert.

    Ich vermute das es an der Funktion liegt und weniger an dem Code, weil wenn ich folgenden Code ausführe

    [IO.FileInfo]$FilePath = "F:\Dev\psbase\anyconnect-gina-win-4.2.04018-pre-deploy-k9.msi"
    $PropertyList = @("ProductCode","ProductVersion","ProductName")
    $ReturnObject = New-Object PSObject
    $WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer
    $MSIDatabase = $WindowsInstaller.GetType().InvokeMember("OpenDatabase","InvokeMethod",$Null,$WindowsInstaller,@($FilePath.FullName,0))
    Foreach ($Property in $PropertyList)
            {
                $Query = "SELECT Value FROM Property WHERE Property = '$Property'"
                $View = $MSIDatabase.GetType().InvokeMember("OpenView","InvokeMethod",$null,$MSIDatabase,($Query))
                $View.GetType().InvokeMember("Execute", "InvokeMethod", $null, $View, $null)
                $Record = $View.GetType().InvokeMember("Fetch","InvokeMethod",$null,$View,$null)
                $Value = $Record.GetType().InvokeMember("StringData","GetProperty",$null,$Record,1)
                $ReturnObject | Add-Member -MemberType NoteProperty -Name "$Property" -Value $Value
            }

    st alles Super...

    PS C:\Users> $ReturnObject.GetType()
    
    IsPublic IsSerial Name                                     BaseType                                                                                    
    -------- -------- ----                                     --------                                                                                    
    True     False    PSCustomObject                           System.Object                                                                               
    
    
    
    PS C:\Users> $ReturnObject
    
    ProductCode                            ProductVersion ProductName                               
    -----------                            -------------- -----------                               
    {C43920E3-2939-455A-B1E2-8A0673A5FFCA} 4.2.04018      Cisco AnyConnect Start Before Login Module


    Wenn ich das Ganze in eine Funktion packe mit einem

    return $ReturnObject

    und das Ergebis in eine Variable schreibe dann kommt das dabei raus..

    PS C:\Users> $blub.GetType()
    
    IsPublic IsSerial Name                                     BaseType                                                                                    
    -------- -------- ----                                     --------                                                                                    
    True     True     Object[]                                 System.Array     

    Donnerstag, 28. Juli 2016 13:22
  • Funtioniert das hier?

    function test2
    {
        [IO.FileInfo]$FilePath = "PFAD ZU EINER BELIEBIGEN MSI DATEI"
        $PropertyList = @("ProductCode","ProductVersion","ProductName")
        $ReturnObject = New-Object PSObject
    
        Try
        {
            $WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer
            $MSIDatabase = $WindowsInstaller.GetType().InvokeMember("OpenDatabase","InvokeMethod",$Null,$WindowsInstaller,@($FilePath.FullName,0))
    
            Foreach ($Property in $PropertyList)
            {
                $Query = "SELECT Value FROM Property WHERE Property = '$Property'"
                $View = $MSIDatabase.GetType().InvokeMember("OpenView","InvokeMethod",$null,$MSIDatabase,($Query))
                $View.GetType().InvokeMember("Execute", "InvokeMethod", $null, $View, $null) > $null
                $Record = $View.GetType().InvokeMember("Fetch","InvokeMethod",$null,$View,$null)
                $Value = $Record.GetType().InvokeMember("StringData","GetProperty",$null,$Record,1)
                $ReturnObject | Add-Member -MemberType NoteProperty -Name "$Property" -Value $Value
            } 
        }
        
        Catch
        {
            Write-Host $_.Exception.Message
        }
              
        return $ReturnObject
    
    }
    
    $var2 = test2
    $var2.ProductCode

    Wie schon gesagt, es liegt am Output-Stream. Wenn du den Code nicht als Funktion ausführst, wird jeder Output an die Console übergeben. Wenn du es als Funktion ausführst wird es an die Rückgabe der Funktion übergeben. Als Beispiel versuch mal das hier:

    function test
    {
        "ABC"
        $a = 42
        Write-Host "Dies kommt direkt die Console"
        New-Item "C:\Temp\Test.txt" -ItemType File -Force
    
        return $a
    }
    
    $c = Test

    und das hier:

    function test
    {
        "ABC" > $null
        $a = 42
        Write-Host "Dies kommt direkt die Console"
        New-Item "C:\Temp\Test.txt" -ItemType File -Force > $null
    
        return $a
    }
    
    $c = Test

    Im ersten Fall hast du auch das "ABC" und das neu erstellte Datei-Objekt in der Rückgabe. In letzterem werden alle Ausgaben abgefangen, außer der, die wir wollen. Die return-Anweisung ist NICHT die ausschließliche Rückgabe bei einer PowerShell-Funktion!



    • Bearbeitet hpotsirhc Freitag, 29. Juli 2016 06:05
    • Als Antwort markiert 0x4d2 Freitag, 29. Juli 2016 06:27
    Freitag, 29. Juli 2016 06:04
  • @hpotsirhc
    Danke für deine Hilfe und die super Erklärung!
    Jetzt habe ich es auch verstanden..

    > $null

    War die die Lösung.

    Freitag, 29. Juli 2016 06:27