Возвращаемое значение функции в PowerShell
Я разработал функцию PowerShell, которая выполняет ряд действий, связанных с обеспечением SharePoint сайтов команды. В конечном счете, я хочу, чтобы функция возвращала URL-адрес подготовленного сайта как String, поэтому в конце моей функции у меня есть следующий код:
$rs = $url.ToString();
return $rs;
Код, вызывающий эту функцию, выглядит так:
$returnURL = MyFunction -param 1 ...
Итак, я ожидаю String, но это не так. Вместо этого это объект типа System.Management.Automation.PSMethod. Почему он возвращает этот тип вместо типа String?
Ответы
Ответ 1
PowerShell имеет действительно дурацкую семантику возврата - по крайней мере, если смотреть с более традиционной перспективы программирования. Есть две основные идеи, которые можно обернуть вокруг:
- Весь вывод захватывается и возвращается
- Ключевое слово return на самом деле просто указывает логическую точку выхода
Таким образом, следующие два блока script будут эффективно выполнять то же самое:
$a = "Hello, World"
return $a
$a = "Hello, World"
$a
return
Переменная $a во втором примере оставлена как вывод на конвейере, и, как уже упоминалось, возвращается весь вывод. Фактически, во втором примере вы можете полностью опустить возврат, и вы получите такое же поведение (возврат будет подразумеваться по мере того, как функция будет естественным образом завершена и завершена).
Без вашего определения функции я не могу сказать, почему вы получаете объект PSMethod. Я предполагаю, что у вас, вероятно, есть несколько строк, которые не фиксируются и помещаются в выходной конвейер.
Также стоит отметить, что вам, вероятно, не нужны эти точки с запятой, если вы не вставляете несколько выражений в одну строку.
Вы можете больше узнать о семантике возврата на странице about_Return на TechNet или вызвать команду help return
из самой PowerShell.
Ответ 2
Эта часть PowerShell, вероятно, самый глупый аспект. Любые посторонние результаты, генерируемые во время функции, будут загрязнять результат. Иногда нет выходных данных, а затем в некоторых условиях есть и другие незапланированные выходные данные, помимо запланированного возвращаемого значения.
Итак, я удаляю назначение из исходного вызова функции, чтобы вывод выводился на экран, а затем пошагово, пока что-то, что я не планировал, не появилось в окне отладчика (с помощью PowerShell ISE).
Даже такие вещи, как резервирование переменных во внешних областях, вызывают вывод, например [boolean]$isEnabled
, который досадно выплевывает False, если вы не сделаете это [boolean]$isEnabled = $false
.
Другим хорошим примером является $someCollection.Add("thing")
, который выплевывает счет новой коллекции.
Ответ 3
С PowerShell 5 теперь у нас есть возможность создавать классы. Измените вашу функцию на класс, и return вернет только объект, непосредственно предшествующий ему. Вот очень простой пример.
class test_class {
[int]return_what() {
Write-Output "Hello, World!"
return 808979
}
}
$tc = New-Object -TypeName test_class
$tc.return_what()
Если бы это была функция, ожидаемый результат был бы
Hello World
808979
но в качестве класса единственное возвращаемое значение - это целое число 808979. Класс является своего рода гарантией того, что он будет возвращать только объявленный или недействительный тип.
Ответ 4
В качестве обходного пути я возвращал последний объект в массиве, который вы получили из функции... Это не отличное решение, но лучше, чем ничего:
someFunction {
$a = "hello"
"Function is running"
return $a
}
$b = someFunction
$b = $b[($b.count - 1)] # Or
$b = $b[-1] # Simpler
Ответ 5
Я передаю простой объект Hashtable с единственным членом результата, чтобы избежать сумасшествия возврата, поскольку я также хочу выводить на консоль. Это действует через проход по ссылке.
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
Вы можете увидеть реальный пример использования в моем проекте GitHub unpackTunes.
Ответ 6
Трудно сказать, не глядя на код. Убедитесь, что ваша функция не возвращает более одного объекта и что вы фиксируете результаты других вызовов. Что вы получаете за:
@($returnURL).count
В любом случае, два предложения:
Передача объекта в строку:
...
return [string]$rs
Или просто заключите его в двойные кавычки, такие же, как указано выше, но короче, чтобы напечатать:
...
return "$rs"
Ответ 7
Люк, описывающий результаты работы функции в этих сценариях, кажется правильным. Я только хочу понять основную причину, и команда разработчиков PowerShell сделает что-то с этим поведением. Это кажется довольно распространенным явлением и стоило мне слишком много времени на отладку.
Чтобы обойти эту проблему, я использовал глобальные переменные, а не возвращал и использовал значение из вызова функции.
Вот еще один вопрос об использовании глобальных переменных:
Установка глобальной переменной PowerShell из функции, где имя глобальной переменной является переменной, переданной функции
Ответ 8
Следующий просто возвращает 4 в качестве ответа. При замене выражений добавления для строк возвращается первая строка.
Function StartingMain {
$a = 1 + 3
$b = 2 + 5
$c = 3 + 7
Return $a
}
Function StartingEnd($b) {
Write-Host $b
}
StartingEnd(StartingMain)
Это также можно сделать для массива. В приведенном ниже примере будет возвращено "Текст 2"
Function StartingMain {
$a = ,@("Text 1","Text 2","Text 3")
Return $a
}
Function StartingEnd($b) {
Write-Host $b[1]
}
StartingEnd(StartingMain)
Обратите внимание, что вы должны вызывать функцию под самой функцией. В противном случае при первом запуске он выдаст ошибку, что он не знает, что такое "StartingMain".
Ответ 9
В качестве альтернативы return
я бы предложил Write-Output
.
Write-Output
может принимать входные данные из конвейера и пересылать их либо по конвейеру, либо выводить их на консоль, если это последняя команда.
Однако Write-Output
не завершает сценарий, как это сделал бы return
, что может быть преимуществом, если вывод следует использовать, пересылать и т.д. В цикле.