Вы микшируете Add-Content
и Out-File
выходные данные, которые используют разные кодировки по умолчанию. Для командлетов *-Content
по умолчанию задано ASCII¹, а для командлета Out-File
по умолчанию задан Unicode (точнее, младший байтовый код UTF-16). Символы UTF-16 кодируются как 2 байта, тогда как символы ASCII кодируются как 1 байт. Отсюда необоснованный интервал в выводе, добавляемый Out-File
.
Из Out-File
документации :
-Encoding
Указывает тип кодировки символов, используемый в файле. Допустимые значения для этого параметра:
[...]
Юникод является значением по умолчанию.
Из Add-Content
документации :
-Encoding
Указывает кодировку файла. По умолчанию ASCII.
2 байта символов Unicode отображаются в виде 2 символов, поскольку файл изначально был создан с помощью Add-Content
(с использованием кодировки этого командлета по умолчанию). Если бы файл был изначально создан как файл Unicode, и вы впоследствии записали в него текст ASCII, то вы бы увидели, что называется "mojibake" (два символа ASCII отображаются как один символ Unicode). Это обычно не должно происходить при добавлении в файл Unicode с Add-Content
, потому что командлет учитывает BOM (Порядок порядка байтов), который указывает кодировку, используемую для файла.
Общая рекомендация - не смешивать *-Content
командлетов с Out-File
. Используйте один или другой, и придерживайтесь его. Если по какой-либо причине вы должны использовать Out-File
вместе с *-Content
, то командлеты обеспечивают требуемое кодирование с помощью параметра -Encoding
.
С учетом сказанного, если у вас уже есть функция ведения журнала: используйте ее для all ведения журнала. Не регистрируйте некоторые строки одним способом, а другие другим способом. Расширьте свою функцию регистрации, чтобы она принимала входные данные из конвейера:
function LogWrite {
[CmdletBinding()]
Param (
[Parameter(Position=0, Mandatory=$false, ValueFromPipeline=$true)]
[string]$logstring = ""
)
Process {
$logstring | Add-Content $Logfile
}
}
так что вы можете использовать его так:
LogWrite "something"
или как это:
Get-ChildItem | LogWrite
или как это:
Get-ChildItem | Out-String | LogWrite
в зависимости от вида вывода журнала, который вы хотите получить.
Я бы также порекомендовал добавить метку времени внутри функции регистрации, а не добавлять метки времени к отдельным строкам:
"$(Get-Timestamp) ${logstring}" | Add-Content $Logfile
¹ Да, я знаю, что технически кодирование является ANSI (или, скорее, одним из многих кодировок ANSI), и что фактическое кодирование ASCII использует 7 бит, а не 8 бит, как ANSI. Однако в контексте вопроса это различие без разницы, поскольку проблема заключается в том, что символы UTF-16 хранятся с использованием 2 байтов на символ, в то время как символы ASCII и ANSI хранятся с использованием только одного байта на характер.