#powershell
#powershell
Вопрос:
Есть ли способ очистить возвращаемые значения внутри функции, чтобы я мог гарантировать, что возвращаемое значение соответствует моим намерениям? Или, может быть, отключить это поведение для функции?
В этом примере я ожидаю, что возвращаемым значением будет ArrayList, содержащий («Hello», «World»)
function GetArray()
{
# $AutoOutputCapture = "Off" ?
$myArray = New-Object System.Collections.ArrayList
$myArray.Add("Hello")
$myArray.Add("World")
# Clear return value before returning exactly what I want?
return $myArray
}
$x = GetArray
$x
Однако выходные данные содержат захваченное значение из операций добавления.
0
1
Hello
World
Я нахожу эту «особенность» Powershell очень раздражающей, потому что она позволяет действительно легко отключить вашу функцию, просто вызвав другую функцию, которая, как вы не знали, вернула значение.
Обновить
Я понимаю, что есть способы предотвратить захват выходных данных (как описано в одном из ответов ниже), но для этого требуется, чтобы вы знали, что функция фактически возвращает значение. Если вы вызываете другую функцию Powershell, возможно, в будущем кто-то изменит эту функцию, чтобы вернуть значение, которое затем нарушит работу вашего кода.
Комментарии:
1. Как вы в конечном итоге справились с этой проблемой. Это очень раздражающая функция powershell, не позволяющая управлять возвращаемым значением.
2. В итоге я просто везде использовал [void]. Я также решил, что проще делать сложные вещи на C #, а затем использовать powershell для склеивания их вместе.
Ответ №1:
Я столкнулся с той же проблемой. В PS функция будет возвращать всю информацию выходного канала. С | Out-Null
остальным кодом в функции становится сложнее. Я обошел это, передав возвращаемую переменную в качестве ссылочного параметра [ref]
. Это работает последовательно. Проверьте приведенный ниже пример кода. Примечание: во избежание ошибок важен некоторый синтаксис. например, параметр должен передаваться в квадратных скобках ([ref]$result)
function DoSomethingWithFile( [ref]$result, [string]$file )
{
# Other code writing to output
# ....
# Initialize result
if (Test-Path $file){
$result.value = $true
} else {
$result.value = $false
}
}
$result = $null
DoSomethingWithFile ([ref]$result) "C:test.txt"
Комментарии:
1. Я думаю, что это решение наиболее понятно для любого, кто читает код. Это также позволяет избежать загромождения вашего кода перенаправлениями (например
| Out-Null
)2. Хотелось бы, чтобы был способ получше… но это больше всего похоже на «программирование». К сожалению, мне приходится использовать Write-Output для отображения журналов…
Ответ №2:
Перевод выходных данных в Out-Null
, перенаправление выходных данных на $null
или префикс вызова функции с [void]
:
$myArray.Add("Hello") | Out-Null
или
$myArray.Add("Hello") >$null
или
[void]$myArray.Add("Hello")
Комментарии:
1. Да, я знаю это, но это означает, что я должен передавать выходные данные каждого вызова функции в null, чтобы гарантировать, что мои выходные данные не повреждены, что является огромной проблемой. И если я забуду это сделать, и код сработает, может случиться так, что в будущем кто-то другой изменит функцию Powershell и сломает другую функцию.
2. Кажется, ответ заключается в том, что нет решения этой проблемы, кроме аннулирования каждого вызова функции, что очень раздражает.
3. К сожалению, это работает для вывода на запись, за исключением того, что вывод не выводится. Runbooks не будет записывать журналы портала ни во что, кроме записи-вывода, поэтому я сбит с толку.
Ответ №3:
Используя информацию от пользователя 1654962, вот способ, которым я работал над решением этой проблемы PowerShell. Поскольку, если есть выходная информация, PowerShell вернет ее в виде массива, я решил убедиться, что вывод функции всегда был массивом. Затем вызывающая строка может использовать [-1] для получения последнего элемента массива, и мы получим согласованное возвращаемое значение.
function DoSomething()
{
# Code that could create output
Write-Output "Random output that we don't need to return"
Write-Output "More random output"
# Create the return value. It can be a string, object, etc.
$MyReturnString = "ImportantValue"
# Other code
# Make sure the return value is an array by preceding it with a comma
return ,$MyReturnString
}
$CleanReturnValue = ( DoSomething() )[-1]
Ответ №4:
У меня тоже такое же разочарование! У меня была функция, в которой переменная должна была подсчитывать $ <variablename>
За исключением. Я забыл » » в конце на одной итерации. Из-за чего значение переменной отправлялось в выходной буфер. Это было очень сложно и отнимало много времени на поиск! MS должна была предоставить, как минимум, возможность очистки выходного буфера, прежде чем пользователь сможет присвоить желаемое возвращаемое значение. В любом случае… Я полагаю, что у меня есть обходной путь.
Поскольку я назначаю возвращаемое значение в конце функции, моим желаемым значением всегда будет последняя запись массива выходных буферов. Итак, я изменил способ вызова своих функций из:
If (FunctionName (parameters)) {}
Для:
If ((FunctionName (parameters))[-1]) {}
Мой конкретный сценарий укусил меня, когда я пытался зафиксировать возврат функции $False. из-за моей опечатки выше, мой оператор IF посчитал это как true из-за мусора в выходных данных, хотя моим последним выводом функции было «Return $ False». Последним результатом, присвоенным функцией, было значение $False из-за проблемы, возникшей в результате опечатки, вызвавшей неправильное вычисление.
Итак, изменение моей функции Возвращает оценку в:
If (!((FunctionName (parameters))[-1])) {#something went wrong!}
Сделал свое дело, позволив мне оценить только последний элемент выходного массива. Я надеюсь, что это поможет другим.
Комментарии:
1. Это хороший трюк, если вы ожидаете одно возвращаемое значение. Я буду иметь это в виду.
2. Обратите внимание, что это не работает, когда у вас есть единственное возвращаемое значение, которое является хэш-таблицей — вы бы попытались проиндексировать его. Решение: префикс вызова функции с
array
like[array](FunctionName(parameters))
, чтобы принудительно выдавать результат в виде массива возвращаемых значений. Тогда это содержало бы вашу хэш-таблицу с ожидаемым индексом.
Ответ №5:
Это то, что вызвало у меня некоторые проблемы с гораздо более крупными функциями.
Можно немного продвинуть первый ответ «Вывод канала в Out-Null». Мы берем код из нашей функции и внедряем его в блок сценария, который затем преобразуем в Out-Null.
Теперь нам не нужно просматривать весь код в функции…вот так:
function GetArray()
{
.{
# $AutoOutputCapture = "Off" ?
$myArray = New-Object System.Collections.ArrayList
$myArray.Add("Hello")
$myArray.Add("World")
} | Out-Null
# Clear return value before returning exactly what I want?
return $myArray
}
$x = GetArray
$x
Комментарии:
1. Никогда раньше не видел фигурную скобку. Что это делает?
Ответ №6:
Просто хотел опубликовать это на случай, если это поможет. У меня было несколько функций, которые я вызывал. Каждая функция возвращала 0 или 1. Я использовал это, чтобы посмотреть, все ли работает.
Итак, в принципе…
function Funct1
{
# Do some things
return 1
}
$myResult = Funct1
$myResult = Funct2
$myResult = Funct3
if ($myResult -eq 3) { "All is good" }
Все шло нормально, пока я не добавил функцию, в которой был некоторый элемент копирования и подобные команды.
Короче говоря, и через час или два я никогда не вернусь, я обнаружил ту же проблему с этим чертовым конвейером. В любом случае, с помощью сайтов, подобных этому, я нашел самый чистый способ гарантировать вам получение вашего «Возврата» и ничего больше.
$myResult = Funct1 -split " " | Select-Object -Last 1
$myResult = Funct2 -split " " | Select-Object -Last 1
$myResult = Funct3 -split " " | Select-Object -Last 1
Ответ №7:
Почему бы не использовать Array
объект Powershell вместо .Чистый список массивов?
Вы могли бы сделать что-то вроде :
function GetArray() {
# set $myArray as a powershell array
$myArray = @()
$myArray ="Hello"
$myArray ="World"
# $myArray=@("Hello", "World") would work as well
return $myArray
}
Это вернет «чистый» массив, как и ожидалось.
Если вам действительно нужно получить System.collections.ArrayList, вы могли бы сделать это в 2 шага :
- создайте массив powershell, как описано выше
-
Преобразуйте массив powershell в .Чистый список массивов таким образом :
# Get the powershellArray $x = getArray # Create a .Net ArrayList $myArrayList = New-Object System.Collections.ArrayList # Fill your arraylist with the powershell array $myArrayList.AddRange($x)
Надеюсь, это немного поможет.
Комментарии:
1. Код в вопросе был всего лишь примером нежелательного поведения. Я спрашиваю, в общем, как справиться с этой ситуацией.
Ответ №8:
Установите для переменной scope значение script или global.
function Get-Greeting {
'Hello Everyone'
$greeting = 'Hello World'
'Ladies and Gentlemen'
$script:greeting = $greeting
}
Get-Greeting
$greeting <== 'Hello World'