Выходные данные области выполнения Powershell ведут себя по-разному в зависимости от того, как определен возвращаемый настраиваемый объект

Я экспериментирую с пространствами выполнения Powershell и заметил разницу в том, как вывод выводится на консоль в зависимости от того, где я создаю свой настраиваемый объект. Если я создаю настраиваемый объект непосредственно в блоке сценария, вывод записывается в консоль в виде таблицы. Однако таблица кажется открытой, пока в пуле пространства выполнения все еще есть открытые потоки, то есть создается таблица, но я могу видеть результаты завершенных заданий, динамически добавляемых к таблице. Это желаемое поведение. Я буду называть это поведением 1.

Несоответствие возникает, когда я добавляю настраиваемый модуль в пул пространств выполнения, а затем вызываю функцию, содержащуюся в этом модуле, которая затем создает настраиваемый объект. Этот объект выводится на экран в виде списка для каждого возвращенного объекта. Это нежелательное поведение. Я назову это поведение 2

Я попытался передать вывод из поведения 2 в формат Format-Table, но это просто создает новую таблицу для каждого возвращаемого объекта. Я могу добиться желаемого эффекта, используя Write-Host для печати строки значений объекта, но я не думаю, что это уместно, учитывая, что, похоже, есть встроенное поведение, которое может достичь желаемого результата, если я его понимаю.

Я думаю по этому поводу, что это как-то связано с асинхронным поведением пространства выполнения. Я новичок в PowerShell, но, возможно, когда пользовательский объект поступает непосредственно из блока сценария, существует скрытый метод или объявление типа, сообщающее PowerShell, чтобы держать таблицу открытой и ждать результата? Это будет отменено при использовании второго метода, потому что он исходит из моей пользовательской функции?

Я хотел бы понять, почему это происходит и как я могу добиться поведения 1, имея возможность использовать настраиваемый модуль, который в конечном итоге будет очень большим. Я открыт и для другой методики, если только можно увидеть, как таблица результатов растет по мере завершения работы. Используемый код приведен ниже.

$ISS = [InitialSessionState]::CreateDefault()
[void]$ISS.ImportPSModule(".\Modules\Test-Item.psm1")
$Pool = [RunspaceFactory]::CreateRunspacePool(1, 5, $ISS, $Host)
$Pool.Open()
$Runspaces = @()

# Script block to run code in
$ScriptBlock = {
    Param ( [string]$Server, [int]$Count )
    Test-Server -Server $Server -Count $Count

    # Uncomment the three lines below and comment out the two
    # lines above to test behavior 1.
    #[int] $SleepTime = Get-Random -Maximum 4 -Minimum 1
    #Start-Sleep -Seconds $SleepTime
    #[pscustomobject]@{Server=$Server; Count=$Count;}
}


# Create runspaces and assign to runspace pool
1..10 | ForEach-Object {
    $ParamList = @{ Server = "Server A" Count = $_ }
    $Runspace = [PowerShell]::Create()
    [void]$Runspace.AddScript($ScriptBlock)
    [void]$Runspace.AddParameters($ParamList)
    $Runspace.RunspacePool = $Pool
    $Runspaces += [PSCustomObject]@{
        Id = $_
        Pipe = $Runspace
        Handle = $Runspace.BeginInvoke()
        Object = $Object
    }
}

# Check for things to be finished
while ($Runspaces.Handle -ne $null)
{
    $Completed = $Runspaces | Where-Object { $_.Handle.IsCompleted -eq $true }

    foreach ($Runspace in $Completed)
    {
        $Runspace.Pipe.EndInvoke($Runspace.Handle)
        $Runspace.Handle = $null
    }

    Start-Sleep -Milliseconds 100
}

$Pool.Close()
$Pool.Dispose()

Пользовательский модуль, который я использую, выглядит следующим образом.

function Test-Server {
    Param ([string]$Server, [int]$Count )
    [int] $SleepTime = Get-Random -Maximum 4 -Minimum 1
    Start-Sleep -Seconds $SleepTime

    [pscustomobject]@{Server = $Server;Item = $Count}
}

person Collin Craige    schedule 28.07.2018    source источник
comment
Можете ли вы воспроизвести проблему с рассматриваемым кодом? Учитывая ошибки в вашем коде, я полагаю, вы не тестируете его самостоятельно.   -  person user4003407    schedule 28.07.2018
comment
Ошибка связана с тем, что я просто изменил код для SO. Я оставил там дополнительный параметр. Отредактирую пост. Я могу воспроизвести оба поведения на своей машине.   -  person Collin Craige    schedule 28.07.2018
comment
Но если вы действительно убедитесь, что ваш упрощенный код позволяет воспроизвести проблему, почему бы просто не скопировать и вставить рабочий упрощенный код под вопрос?   -  person user4003407    schedule 28.07.2018
comment
Я неправильно понял ваш первоначальный комментарий. Я не проверял, что публикуется, просто проверял, и все работает как надо. Я не проверял это, потому что все, что я изменил, это удаление лишних значений в настраиваемом объекте модуля. Я добавил к этому объекту переменную $ SleepTime и настраиваемое сообщение (я здесь). Однако я ошибся в написании $ SleepTime и был слишком отвлечен резким изменением вывода, чтобы заметить. Но почему выход меняют? Почему не ошибка или таблица с пустым значением для $ SleepTime как формат списка? Вы можете объяснить в качестве ответа?   -  person Collin Craige    schedule 28.07.2018
comment
Немного странности. Если я добавлю более 4 переменных, результат снова станет списком. Кроме того, изменение вывода больше похоже на то, что я не спасаюсь, когда вношу изменения. Однако я до сих пор не понимаю, почему не возникает ошибка. Выдается ли ошибка, но она просто не возвращается к моей основной мощности?   -  person Collin Craige    schedule 28.07.2018
comment
Если вы не предоставите код, который позволяет воспроизвести описанное поведение, я не вижу, чем я могу вам помочь. И, кстати, (Begin/End)Invoke не возвращает ничего, кроме успешного вывода. Если вам нужно что-то еще, например ошибки, предупреждения и т. Д., Вам необходимо проверить _ 2_.   -  person user4003407    schedule 28.07.2018


Ответы (2)


То, что вы упомянули, мне кажется совершенно нормальным. Так разработан PowerShell, потому что он разделяет бремя отображения. Если пользователь не указал, как отображать, PowerShell решает, как это сделать.

Мне не удалось воспроизвести вашу проблему с помощью предоставленного кода, но я думаю, что это решит вашу проблему.

$FinalTable = foreach ($Runspace in $Completed)
{
    $Runspace.Pipe.EndInvoke($Runspace.Handle)
    $Runspace.Handle = $null
}

$FinalResult теперь будет иметь ожидаемый формат таблицы.

person Sid    schedule 28.07.2018

Похоже, что моей основной проблемой, помимо ошибок в моем коде, было непонимание, связанное с обработкой объектов по умолчанию в PowerShell. Powershell отображает выходные данные объектов в виде таблицы, если имеется менее четырех пар ключ-значение, и в виде списка, если их больше.

Пользовательский объект, возвращенный в моем тестовом модуле, имел больше, чем пары ключ-значение, в то время как пользовательский объект, который я вернул напрямую, имел только два. Это привело к тому, что я считал странным. Я усугубил проблему, удалив несколько пар ключ-значение в опубликованном коде, чтобы сократить его, а затем не тестировал (извините).

В этом сообщении stackoverflow есть длинный ответ, объясняющий поведение и приводящие примеры изменения вывода по умолчанию.

person Collin Craige    schedule 05.08.2018