Очистить захваченный вывод / возвращаемое значение в функции Powershell

#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'