Как AdminOfThings правильно указывает:
Хотя $y = @()
назначает пустой массив для $y
, он не ограничение типа этой переменной, поэтому ваше следующее присвоение - $y = "Create Users process ..."
- изменяет тип переменной на строку .
- Простое использование
+=
вместо =
в этом последующем присваивании предотвратило бы проблему: $y += "Create Users process ..."
. - В качестве альтернативы ограничение типа переменнаясоздание -
[array] $y = @()
- то есть размещение литерала типа слева от присваиваемой переменной (сродни приведению) - также предотвратило бы проблему.
Последующее использование +=
, следовательно, выполняет простую конкатенацию строк вместо желаемого постепенного построения массива без добавления разделителей между «строками». [1]
- В отличие от , если бы вы использовали массив , как предполагалось, как
Out-File
, так и Set-Content
будет автоматически вставлять соответствующие элементы платформы [2] между элементами, плюс один в конце, при сохранении (в PSv5 + вы можете использовать переключатель -NoNewline
отказаться).
Тем не менее, использование +=
для "расширения" массива неэффективно, потому что PowerShell должен сделать за сценой создание новый массив , содержащий старые элементы плюс новые элементы, учитывая, что массивы имеют структуру фиксированного размера .
В то время как снижение производительности при использовании +=
для«Расширение» массивов в цикле действительно имеет значение только при большом количестве итераций, это более кратко, удобно и эффективно, чтобы позволял PowerShell создавать массивы для вас неявно , используя ваш foreach
цикл в качестве выражение :
# Initialize the array and assign the first element.
# Due to the type constraint ([array]), the RHS string implicitly becomes
# the array's 1st element.
[array] $y = "Create Users process. Run started at $('[{0:MM/dd/yyyy} {0:HH:mm:ss}]' -f (Get-Date))"
# Add the strings output by the foreach loop to the array.
# PowerShell implicitly collects foreach output in an array when
# you use it in as an expression.
$y += foreach ($x in $users)
{
"User $($x.displayname) with NNN of $($x.ID)"
}
# Add the final string to the array.
$y += "Completed at $('[{0:MM/dd/yyyy} {0:HH:mm:ss}]' -f (Get-Date))"
# Send the array to a file with Out-File, which separates
# the elements with newlines and adds a trailing one.
# Windows PowerShell:
# Out-File creates UTF-16LE-encoded files.
# Set-Content, which can alternatively be used, creates "ANSI"-encoded files.
# PowerShell Core:
# Both cmdlets create UTF-8-encoded files without BOM.
$y | Out-File "Log.txt"
Обратите внимание, что вы можете аналогичным образом использовать операторы for
, if
, do
/ while
/ switch
каквыражения .
Во всех случаях, однако, на PowerShell 6.2.0, тэти выражения могут служить только выражениями сами по себе ;к сожалению, встраивание их в большие выражения не работает - см. этот выпуск GitHub .
[1] Простая демонстрацияВаша проблема:
# The initialization of $y as @() is overridden by $y = 'first'.
PS> $y = @(); $y = 'first'; $y += 'second'; $y
firstsecond # !! $y contains a single string built with string concatenation
Поэтому описание ваших симптомов не соответствует вашему коду, поскольку вы должны были видеть однострочную строку вывода во всех сценариях (печать прямо на экран / через Format-Table
, отправка в файл и type
-ing, что из cmd.exe
).
[2] Соответствующий платформе символ новой строки отражается в [Environment]::NewLine
, и это "`r`n"
(CRLF) в Windowsи просто "`n"
(LF) на Unix-подобных платформах (в PowerShell Core ).