functionsrückgabewert in PowerShell

Ich habe eine PowerShell-function entwickelt, die eine Reihe von Aktionen zur Bereitstellung von SharePoint- Teamwebsites ausführt. Letztendlich möchte ich, dass die function die URL der bereitgestellten Site als String zurückgibt. Am Ende meiner function habe ich den folgenden Code:

$rs = $url.ToString(); return $rs; 

Der Code, der diese function aufruft, sieht folgendermaßen aus:

 $returnURL = MyFunction -param 1 ... 

Ich erwarte also einen String, ist es aber nicht. Stattdessen ist es ein Objekt vom Typ System.Management.Automation.PSMethod. Warum gibt es diesen Typ anstelle eines String-Typs zurück?

   

PowerShell hat wirklich eine komische Rückkehrsemantik – zumindest wenn man es aus einer eher traditionellen Programmierperspektive betrachtet. Es gibt zwei Hauptideen, mit denen Sie sich beschäftigen können:

  • Alle Ausgaben werden erfasst und zurückgegeben
  • Das Schlüsselwort return gibt nur einen logischen Ausgangspunkt an

Daher werden die folgenden zwei Skriptblöcke genau dasselbe bewirken:

 $a = "Hello, World" return $a 

 $a = "Hello, World" $a return 

Die $ a-Variable im zweiten Beispiel wird als Ausgabe in der Pipeline belassen und, wie erwähnt, wird die gesamte Ausgabe zurückgegeben. Im zweiten Beispiel könnten Sie die Rückgabe ganz weglassen und Sie würden das gleiche Verhalten erhalten (die Rückgabe wäre implizit, da die function natürlich abgeschlossen und beendet wird).

Ohne weitere Definition Ihrer function kann ich nicht sagen, warum Sie ein PSMethod-Objekt erhalten. Meine Vermutung ist, dass Sie wahrscheinlich ein paar Zeilen haben, die nicht erfasst werden und in der Ausgabepipeline platziert werden.

Es ist auch erwähnenswert, dass Sie diese Semikolons wahrscheinlich nicht benötigen – es sei denn, Sie verschachteln mehrere Ausdrücke in einer einzelnen Zeile.

Sie können mehr über die Rückkehrsemantik auf der Seite about_Return auf TechNet lesen oder indem Sie den Befehl help return von PowerShell selbst aufrufen.

Dieser Teil von PowerShell ist wahrscheinlich der dümmste Aspekt. Jede externe Ausgabe, die während einer function erzeugt wird, verschmutzt das Ergebnis, manchmal gibt es keine Ausgabe und dann gibt es unter anderen Bedingungen zusätzlich zu Ihrem geplanten Rückgabewert eine andere ungeplante Ausgabe.

Also, was ich mache, ist die Zuweisung aus dem ursprünglichen functionsaufruf zu entfernen, so dass die Ausgabe auf dem Bildschirm endet, und dann durchgehen, bis etwas, das ich nicht plante, im Debugger-Fenster (mit dem PS ISE) herausspringt.

Selbst Dinge wie das Reservieren von Variablen in äußeren Bereichen verursachen eine Ausgabe, wie [boolean]$isEnabled die einen False ausspuckt, es sei denn, man macht es [boolean]$isEnabled = $false .

Ein weiterer guter $someCollection.Add("thing") ist $someCollection.Add("thing") der die Anzahl der neuen Sammlungen ausspuckt.

Als Workaround habe ich das letzte Objekt in dem Array zurückgegeben, das Sie von der function erhalten haben … keine gute Lösung, aber es ist besser als nichts:

 someFunction { $a = "hello" "Function is running" return $a } $b = someFunction $b = $b[($b.count - 1)] # or $b = $b[-1] # simpler 

Mit PowerShell 5 haben wir jetzt die Möglichkeit, classn zu erstellen. Wenn du deine function in eine class änderst, kannst du sie nicht nur eingeben und zurückgeben, sondern NUR das unmittelbar davor liegende Objekt zurückgeben. Hier ist ein wirklich einfaches Beispiel.

 class test_class{ [int]return_what() { $a = "Hello World" return 808979 } } $tc = New-Object -TypeName test_class $tc.return_what() 

Wenn dies eine function wäre, wäre die erwartete Ausgabe

 Hello World 808979 

aber als class ist das Einzige, was zurückgegeben wird, ein INT 808979. Eine class ist wie eine Garantie, dass sie nur den deklarierten oder ungültigen Typ zurückgibt.

Es ist schwer zu sagen, ohne Code anzusehen. Stellen Sie sicher, dass Ihre function nicht mehr als ein Objekt zurückgibt und dass Sie Ergebnisse aus anderen Aufrufen erfassen. Wofür bekommst du:

 @($returnURL).count 

Wie auch immer, zwei Vorschläge:

Wirf das Objekt in einen String:

 ... return [string]$rs 

Oder schließen Sie es einfach in doppelte Anführungszeichen ein, wie oben, aber kürzer, um Folgendes einzugeben:

 ... return "$rs" 

Lukes Beschreibung der functionsergebnisse in diesen Szenarien scheint richtig zu sein. Ich möchte nur die Ursache verstehen und das PowerShell-Produktteam würde etwas gegen das Verhalten unternehmen, scheint ziemlich verbreitet zu sein und kostet zu viel Debugging-Zeit.

Um dieses Problem zu umgehen, habe ich globale Variablen verwendet und nicht den Wert aus dem functionsaufruf zurückgegeben.

Hier ist ein weiterer Thread zur Verwendung von globalen Variablen: Festlegen einer globalen PowerShell-Variablen aus einer function, wobei der Name der globalen Variablen eine Variable ist, die an die function übergeben wird

Ich übergebe ein einfaches Hashtable-Objekt mit einem einzigen Ergebnis-Member, um die Rückkehr-Verrücktheit zu vermeiden, da ich auch auf der Konsole ausgeben möchte. Es handelt sich um Durchgang durch Referenz.

 function sample-loop($returnObj) { for($i = 0; $i -lt 10; $i++) { write-host "loop counter: $i" $returnObj.result++ } } function main-sample() { $countObj = @{ result = 0 } sample-loop -returnObj $countObj write-host "_____________" write-host "Total = " ($countObj.result) } main-sample 

Sie können eine reale Beispielverwendung in meinem GitHub-Projekt unpackTunes sehen

Das Folgende gibt einfach 4 als Antwort zurück. Wenn Sie die Add-Ausdrücke für Strings ersetzen, wird die erste Zeichenfolge zurückgegeben.

 Function StartingMain { $a = 1 + 3 $b = 2 + 5 $c = 3 + 7 Return $a } Function StartingEnd($b) { Write-Host $b } StartingEnd(StartingMain) 

Dies kann auch für ein Array erfolgen. Das folgende Beispiel gibt “Text 2” zurück

 Function StartingMain { $a = ,@("Text 1","Text 2","Text 3") Return $a } Function StartingEnd($b) { Write-Host $b[1] } StartingEnd(StartingMain) 

Beachten Sie, dass Sie die function unterhalb der function selbst aufrufen müssen, sonst wird beim ersten Start ein Fehler zurückgegeben, der nicht weiß, was “StartingMain” ist.

Ich hoffe, es hilft.