PowerShell. Работа с файлами, импорт и экспорт объектов в текстовые файлы. Вывод в файл powershell
Вывод данных в PowerShell
Обычно в процессе работы PowerShell генерируются некоторые выходные данные. Для вывода этих данных существуют специальные Out-командлеты (командлеты, название которых начинается с Out-). Когда выполняемая команда PowerShell возвращает данные, они передаются по конвейеру на вход Out-командлета, который обрабатывает их и отправляет в устройство вывода (на экран, в файл, на принтер и т.п.).
Для просмотра этих командлетов выполним команду:
Get-Command -Verb Out
Out-Host
Командлет Out-Host служит для вывода данных на экран. Например:
Get-Process powershell | Out-Host
Впрочем, добавлять Out-Host в конец команды совсем необязательно. В конце конвейера по умолчанию находится командлет Out-Default, который и перенаправляет все в Out-Host. Т.е. предыдущая команда эквивалентна команде:
Get-Process powershell | Out-Default
которая в свою очередь эквивалентна команде:
Get-Process powershell
На самом деле механизм вывода еще запутаннее. Как вы помните, результатом работы PowerShell являются объекты. Out-командлеты не умеют работать с любыми объектами, а только со специальным типом объектов форматирования, поэтому при получении объекта вызывают один из командлетов форматирования (Format-*). Format-командлет предоставляет Out-командлету объекты форматирования, описывающие порядок построения выходных данных, а Out-командлет отправляет их в нужное устройство. Т.е. при выполнении команды:
Get-Process powershell
в действительности отрабатывает команда:
Get-Process powershell | Format-Table | Out-Host
Хотя добавлять Out-Host в конец команды необязательно, но в некоторых случаях удобно. К примеру он имеет ключ Paging, с помощью которого можно организовать постраничный вывод:
Get-Process | Out-Host -Paging
Out-File
Командлет Out-File перенаправляет выходные данные в указанный файл, например:
Get-Process powershell | Out-File proc.txt
По умолчанию данные в файле перезаписываются. Запретить перезапись существующего файла можно, указав ключ NoClobber, а если необходимо дописывать данные в существующий файл, то можно использовать ключ Append, который добавляет данные в конец файла:
Get-Process powershell | Out-File proc.txt -Append
Для вывода в файл можно использовать сокращенный синтаксис. Например для записи:
Get-Process powershell >proc.txt
или для добавления в конец файла:
Get-Process powershell >>proc.txt
Out-GridView
Командлет Out-GridView выводит данные в виде графической таблицы, в которой их можно отфильтровать и отсортировать по нужному признаку. Для наглядности можно указать ключ Title, который будет отображаться в заголовке:
Get-Process | Out-GridView -Title processes
Начиная стретьей версии PowerShell Out-GridView поддерживает ключ PassThru, позволяющий передать полученные данные дальше по конвейеру. Например, можно вывести список процессов, в графической оснастке отобрать нужные и передать их командлету Stop-Process, который остановит выбранные процессы:
Get-Process | Out-GridView -PassThru | Stop-Process
Out-Null
Командлет Out-Null используется в том случае, если выходные данные отображать не нужно. Он отправляет полученные данные в устройство NULL, т.е. удаляет их. Для примера возьмем такую команду:
$process = Get-WmiObject win32_process -Filter ″Name = ′Notepad.exe′″$process.Terminate()
Помимо основного действия (остановка процесса) она выводит много лишней информации. Чтобы избавится от нее, отправим вывод в Out-Null, например так:
$process.Terminate() | Out-Null
или так:
$process.Terminate() >$null
Out-String
Командлет Out-String преобразует входные данные в массив строк. По сути Out-String преобразует объекты PowerShell в строки, с которыми дальше можно работать как с обычным текстом (форматировать, производить поиск и т.п.).
Для примера выведем процесс, сохраним его в переменную $a и посмотрим тип данных:
$a = Get-Process powershell $a.GetType()
$b = $a | Out-String $b.Get-Type()
Как видно из примера, на входе Out-String тип данных Process, а на выходе String.
Out-String принципиально отличается от остальных out-командлетов. Поскольку обычные out-командлеты работают с конечным результатом предыдущих команд, то сами они не производят никаких выходных данных. Именно поэтому out-командлет обычно ставится последним в командной строке, ведь после него в конвейере не остается ничего, с чем могут работать другие командлеты.
В отличие от них Out-String принимает объекты, преобразует их в массив строк и передает дальше по конвейеру. По умолчанию данные накапливаются и возвращаются одной строкой, но с помощью ключа Stream можно указать вывод по отдельной строке для каждого объекта.
Для примера выведем список системных служб со всеми свойствами и отформатируем его в виде таблицы:
Get-Service | Format-Table -Property * -AutoSize
Поскольку ширина консоли граничена 80 символами, то большинство данных будет обрезано, что не очень здорово.
Чтобы не обрезать вывод, направим его в Out-String и увеличим ширину:
Get-Service | Format-Table -Property * -AutoSize | Out-String -Width 1024
Теперь все данные попали на экран, но все равно выглядит не очень.
Исправим положение, передав вывод Out-String командлету Out-File:
Get-Service | Format-Table -Property * -AutoSize | Out-String -Width 1024 | Out-File service.txt
На выходе получаем файл с таблицей нужной ширины, а для просмотра есть полоса прокрутки. Таким образом можно создавать и просматривать таблицы практически любой ширины.
Out-Printer
Командлет Out-Printer перенаправляет вывод на принтер. Например:
Get-Service | Format-Table -Property * -AutoSize | Out-File service.txt -Width 1024Get-Content service.txt | Out-Printer
Вывод отправляется на принтер, заданный в системе по умолчанию. Для указания альтернативного принтера можно использовать ключ Name.
windowsnotes.ru
PowerShell. Работа с файлами, импорт и экспорт объектов в текстовые файлы. — Клёвый код
В данной статье описано, как записать и получить данные из файла при работе с PowerShell.
В этой статье описаны следующие темы:Операторы перенаправленияКомандлеты Set-Content, Add-ContentКомандлет Out-FileКомандлет Tee-ObjectКомандлет Get-ContentКомандлет Export-CSVКомандлет Import-CsvКомандлет Import-ClixmlКомандлет Export-Clixml
Операторы перенаправления.
В powershell, как и в командной строке есть способ перенаправить поток вывода и ошибок в файл. Как и в командной строке в PowerShell существуют операторы перенаправления.
Для того, что бы перенаправить поток консольного вывода в файл, необходимо после команды написать знак «>» ,если нужно затереть данные в файле, или «>>» , если данные надо дописать в конец файла, а потом полный путь к файлу.
Пример:
PS C:\temp> Get-ChildItem Каталог: C:\temp Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 29.07.2015 13:27 4472 1.csv -a--- 30.07.2015 13:02 0 1.txt PS C:\temp> Get-ChildItem > 1.txt PS C:\temp> PS C:\temp> Get-Content 1.txt Каталог: C:\temp Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 29.07.2015 13:27 4472 1.csv -a--- 30.07.2015 13:15 788 1.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
PS C:\temp> Get-ChildItem
Каталог: C:\temp
Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 29.07.2015 13:27 4472 1.csv -a--- 30.07.2015 13:02 0 1.txt
PS C:\temp> Get-ChildItem > 1.txt PS C:\temp> PS C:\temp> Get-Content 1.txt
Каталог: C:\temp
Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 29.07.2015 13:27 4472 1.csv -a--- 30.07.2015 13:15 788 1.txt |
Первая команда «Get-ChildItem» выводит свой результат работы в консоль,
Вторая «Get-ChildItem > 1.txt» записывает результат работы в файл «1.txt» текущей директории.
Рассмотрим ещё один пример:
PS C:\temp> Get-ChildItem skdjfsdlj Get-ChildItem : Не удается найти путь "C:\temp\skdjfsdlj", так как он не существует. строка:1 знак:4 + dir <<<< skdjfsdlj + CategoryInfo : ObjectNotFound: (C:\temp\skdjfsdlj:String) [Get-ChildItem], ItemNotFoundException + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand PS C:\temp> Get-ChildItem skdjfsdlj > 1.txt Get-ChildItem : Не удается найти путь "C:\temp\skdjfsdlj", так как он не существует. строка:1 знак:4 + dir <<<< skdjfsdlj > 1.txt + CategoryInfo : ObjectNotFound: (C:\temp\skdjfsdlj:String) [Get-ChildItem], ItemNotFoundException + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand PS C:\temp>
PS C:\temp> Get-ChildItem skdjfsdlj Get-ChildItem : Не удается найти путь "C:\temp\skdjfsdlj", так как он не существует. строка:1 знак:4 + dir <<<< skdjfsdlj + CategoryInfo : ObjectNotFound: (C:\temp\skdjfsdlj:String) [Get-ChildItem], ItemNotFoundException + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
PS C:\temp> Get-ChildItem skdjfsdlj > 1.txt Get-ChildItem : Не удается найти путь "C:\temp\skdjfsdlj", так как он не существует. строка:1 знак:4 + dir <<<< skdjfsdlj > 1.txt + CategoryInfo : ObjectNotFound: (C:\temp\skdjfsdlj:String) [Get-ChildItem], ItemNotFoundException + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
PS C:\temp> |
После выполнения команд файл 1.txt останется пустым. А ошибка отобразилась в консоли. Если поток ошибок надо так же перенаправить в файл, то в конце команды надо дописать 2>&1.
Пример:
Get-ChildItem lkdjflds >1.txt 2>&1
Get-ChildItem lkdjflds >1.txt 2>&1 |
После выполнения команды в файле будет записан как и результат выполнения команды, так и ошибки:
PS C:\temp> Get-ChildItem asdfsadf > 1.txt 2>&1 PS C:\temp> PS C:\temp> Get-content 1.txt Get-ChildItem : Не удается найти путь "C:\temp\asdfsadf", так как он не существует. строка:1 знак:14 + Get-ChildItem <<<< asdfsadf > 1.txt 2>&1 + CategoryInfo : ObjectNotFound: (C:\temp\asdfsadf:String) [Get-ChildItem], ItemNotFoundException + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand PS C:\temp>
PS C:\temp> Get-ChildItem asdfsadf > 1.txt 2>&1 PS C:\temp> PS C:\temp> Get-content 1.txt Get-ChildItem : Не удается найти путь "C:\temp\asdfsadf", так как он не существует. строка:1 знак:14 + Get-ChildItem <<<< asdfsadf > 1.txt 2>&1 + CategoryInfo : ObjectNotFound: (C:\temp\asdfsadf:String) [Get-ChildItem], ItemNotFoundException + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
PS C:\temp> |
В этом примере мы перенаправили второй поток вывода в первый, а первый поток записали в файл.
В PowerShell существуют следующие потоки:
0 | Поток ввода | |
1 | >filename|>>filename | Поток информационных сообщений |
2 | 2>filename|2>>filename|2>&1 | Поток сообщений с ошибоками |
В PowerShell 3.0 появилось ещё несколько потоков: | ||
3 | 3>filename|3>>filename|3>&1 | Поток предупреждений. |
4 | 4>filename|4>>filename|4>&1 | Поток подробного вывода. |
5 | 5>filename|5>>filename|5>&1 | Поток диагностики. |
* | *>filename|*>>filename | Все потоки. |
Set-Content, Add-Content
Так же для записи в файл можно использовать командлеты Set-Content и Add-Content. Эти командлеты заменяет все данные в файле на указанные. Перед записью они преобразовывают объекты в строки и не всегда удобны. Зато они могут использоваться для массового изменения файлов. Простейшая их запись выглядит так:
Set-content 1.txt "Hello"
Set-content 1.txt "Hello" |
Add-content 1.txt "Hello"
Add-content 1.txt "Hello" |
Данная команда заменит все данные в файле 1.txt на Слово «Hello». Если файла на момент запуска нет, то он создастся.
При работе с файловой системой командлеты могут применять следующие параметры:
-Value «Объект для записи»
В этом параметре нужно указывать новое содержимое элементов.
Пример:
Set-content 1.txt -value "Hello"
Set-content 1.txt -value "Hello" |
Данная команда изменит содержимое файла «1.txt» на «Hello»
Ещё пример:
PS C:\Temp> Add-content -Path 1.txt -value "Hello1","Hello2" PS C:\Temp>
PS C:\Temp> Add-content -Path 1.txt -value "Hello1","Hello2" PS C:\Temp> |
Добавляет к файлу 1.txt, текущей дирректории, две строки «Hello1» и «Hello2»
Название параметра можно опустить, тогда предыдущие примеры будет выглядеть так:
Set-content 1.txt "Hello"
Set-content 1.txt "Hello" |
Add-content -Path 1.txt "Hello1","Hello2"
Add-content -Path 1.txt "Hello1","Hello2" |
Данный параметр, так же можно передавать по контейнеру.
Но в файл попадут не данные как на консоли, а преобразованные в текстовые строки объекты.
Пример:
PS C:\temp> Get-ChildItem Каталог: C:\temp Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 30.07.2015 16:34 4 1.csv -a--- 30.07.2015 16:45 83 1.txt -a--- 30.07.2015 15:04 8 1.xml -a--- 30.07.2015 16:34 4 2.csv -a--- 30.07.2015 16:34 4 2.txt -a--- 30.07.2015 15:04 8 2.xml -a--- 30.07.2015 16:34 4 212.txt -a--- 30.07.2015 16:34 4 22.txt -a--- 30.07.2015 16:34 4 3.txt -a--- 30.07.2015 15:04 8 3.xml -a--- 30.07.2015 16:34 4 temp.txt PS C:\temp> Get-ChildItem | Set-Content 1.txt PS C:\temp> Get-Content 1.txt 1.csv 1.txt 1.xml 2.csv 2.txt 2.xml 212.txt 22.txt 3.txt 3.xml temp.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
PS C:\temp> Get-ChildItem
Каталог: C:\temp
Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 30.07.2015 16:34 4 1.csv -a--- 30.07.2015 16:45 83 1.txt -a--- 30.07.2015 15:04 8 1.xml -a--- 30.07.2015 16:34 4 2.csv -a--- 30.07.2015 16:34 4 2.txt -a--- 30.07.2015 15:04 8 2.xml -a--- 30.07.2015 16:34 4 212.txt -a--- 30.07.2015 16:34 4 22.txt -a--- 30.07.2015 16:34 4 3.txt -a--- 30.07.2015 15:04 8 3.xml -a--- 30.07.2015 16:34 4 temp.txt
PS C:\temp> Get-ChildItem | Set-Content 1.txt PS C:\temp> Get-Content 1.txt 1.csv 1.txt 1.xml 2.csv 2.txt 2.xml 212.txt 22.txt 3.txt 3.xml temp.txt |
Тоже самое произойдёт, если в параметр -value передать переменную:
Path[0]: PS C:\temp> $a=Get-ChildItem PS C:\temp> Set-Content 1.txt -value $a PS C:\temp> Set-Content 2.txt -value $a PS C:\temp> Get-Content 2.txt 1.csv 1.txt 1.xml 2.csv 2.txt 2.xml 212.txt 22.txt 3.txt 3.xml temp.txt
Path[0]: PS C:\temp> $a=Get-ChildItem PS C:\temp> Set-Content 1.txt -value $a PS C:\temp> Set-Content 2.txt -value $a PS C:\temp> Get-Content 2.txt 1.csv 1.txt 1.xml 2.csv 2.txt 2.xml 212.txt 22.txt 3.txt 3.xml temp.txt |
-LiteralPath «путь до файла(ов)»
В этом параметре надо указывать точный путь до файла. Можно использовать перечисление файлов, через «,» (запятую).
PS C:\temp> Set-content -literalPath 1.txt , 2.txt "Hello"
PS C:\temp> Set-content -literalPath 1.txt , 2.txt "Hello" |
Данная команда изменит данные в файлах текущей директории «1.txt» и «2.txt» на «Hello»
или можно добавить данные:
Add-content -literalPath 1.txt , 2.txt "Hello"
Add-content -literalPath 1.txt , 2.txt "Hello" |
-Path «строка с шаблоном пути до файлов»
Данный параметр подставляется автоматически если его не указывать явно и в нём указываются шаблон для файлов, которые будут подвергаться изменению.
Например команда:
Set-content C:\temp\*.txt "Hello"
Set-content C:\temp\*.txt "Hello" |
Заменит содержимое всех файлов в дирректории «C:\temp\» с типом *.txt на «Hello».
Можно так же добавить строку «Hello» к файлам в дирректории «C:\temp\» и «C:\temp2\» одним командлетом:
Set-content C:\temp\*,C:\temp2\* "Hello"
Set-content C:\temp\*,C:\temp2\* "Hello" |
-Force
Параметр -Force позволяет проводить действия, даже с файлами у которых стоит атрибут «Только на чтение».
PS C:\temp> Set-content -Path "C:\temp\1.txt" -value "33" Set-Content : Отказано в доступе по пути "C:\temp\1.txt". строка:1 знак:12 + Set-content <<<< -Path "C:\temp\1.txt" -value "33" + CategoryInfo : NotSpecified: (:) [Set-Content], UnauthorizedAccessException + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.SetContentCommand PS C:\temp> Set-content -Path "C:\temp\1.txt" -value "33" -force PS C:\temp>
PS C:\temp> Set-content -Path "C:\temp\1.txt" -value "33" Set-Content : Отказано в доступе по пути "C:\temp\1.txt". строка:1 знак:12 + Set-content <<<< -Path "C:\temp\1.txt" -value "33" + CategoryInfo : NotSpecified: (:) [Set-Content], UnauthorizedAccessException + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.SetContentCommand
PS C:\temp> Set-content -Path "C:\temp\1.txt" -value "33" -force PS C:\temp> |
При выполнении команды «Set-content -Path «C:\temp\1.txt» -value «33»». Появилась ошибка, так как на файле стоит атрибут «только на чтение», вторая команда прошла успешно.
Тоже самое и для Add-Content:
PS C:\temp> Add-Content -Path "C:\temp\1.txt" -value "33" Add-Content : Отказано в доступе по пути "C:\temp\1.txt". строка:1 знак:12 + Add-Content <<<< -Path "C:\temp\1.txt" -value "33" + CategoryInfo : NotSpecified: (:) [Set-Content], UnauthorizedAccessException + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.SetContentCommand PS C:\temp> Add-Content -Path "C:\temp\1.txt" -value "33" -force PS C:\temp>
PS C:\temp> Add-Content -Path "C:\temp\1.txt" -value "33" Add-Content : Отказано в доступе по пути "C:\temp\1.txt". строка:1 знак:12 + Add-Content <<<< -Path "C:\temp\1.txt" -value "33" + CategoryInfo : NotSpecified: (:) [Set-Content], UnauthorizedAccessException + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.SetContentCommand
PS C:\temp> Add-Content -Path "C:\temp\1.txt" -value "33" -force PS C:\temp> |
-Filter «шаблон имени»
В этом параметре можно указать шаблон имени файла.
Пример:
PS C:\temp> Set-content -Path "C:\temp\*" , "C:\temp2\*" -Filter "*.txt" -value "Hello2"
PS C:\temp> Set-content -Path "C:\temp\*" , "C:\temp2\*" -Filter "*.txt" -value "Hello2" |
Данная команда заменит значение всех файлов с типом «*.txt» в дирректриях «C:\temp» и «C:\temp2»
-Include «шаблоны имён»
В отличии от параметра «-Filter» в -Include можно указывать несколько шаблонов одновременно.
Пример:
PS C:\temp> Set-content -Path "C:\temp\*" , "C:\temp2\*" -Include "*.doc","*.txt" -value "33" -Exclude "1.txt"
PS C:\temp> Set-content -Path "C:\temp\*" , "C:\temp2\*" -Include "*.doc","*.txt" -value "33" -Exclude "1.txt" |
В этой команде заменится содержимое всех файлов с типом «*.txt» и «.doc» в директориях «C:\temp» и «C:\temp2»
или добавить содержимое:
PS C:\temp> Add-Content -Path "C:\temp\*" , "C:\temp2\*" -Include "*.doc","*.txt" -value "33" -Exclude "1.txt"
PS C:\temp> Add-Content -Path "C:\temp\*" , "C:\temp2\*" -Include "*.doc","*.txt" -value "33" -Exclude "1.txt" |
-Exclude «Шаблон исключений пути файлов»
Данный параметр отбрасывает файлы удовлетворяющие «Шаблон исключений пути файлов», из списка найденных по шаблону в параметре «-Path». Но не влияет на файлы указанные в параметре -LiteralPath.
Пример:
PS C:\temp> Set-content -Path *.txt -Exclude ?.txt "22"
PS C:\temp> Set-content -Path *.txt -Exclude ?.txt "22" |
Данная команда установит содержимое всех файлов с типом «txt» на 22, кроме текстовых файлов у которых имя файла без типа, содержит один символ.
Так же и для Add-Content:
PS C:\temp> Add-Content -Path *.txt -Exclude ?.txt "22"
PS C:\temp> Add-Content -Path *.txt -Exclude ?.txt "22" |
-PassThru
Данный параметр позволяет передать объекты дальше по контейнеру, или вывести объекты на консоль, если данный командлет является последним.
Пример:
PS C:\temp> Get-ChildItem | Set-Content 1.txt -PassThru |gm TypeName: System.Object[] Name MemberType Definition ---- ---------- ---------- Count AliasProperty Count = Length Address Method System.Object&, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934... Clone Method System.Object Clone() CopyTo Method System.Void CopyTo(array array, int index), System.Void CopyTo(array array, long index) Equals Method bool Equals(System.Object obj) Get Method System.Object Get(int )
PS C:\temp> Get-ChildItem | Set-Content 1.txt -PassThru |gm
TypeName: System.Object[]
Name MemberType Definition ---- ---------- ---------- Count AliasProperty Count = Length Address Method System.Object&, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934... Clone Method System.Object Clone() CopyTo Method System.Void CopyTo(array array, int index), System.Void CopyTo(array array, long index) Equals Method bool Equals(System.Object obj) Get Method System.Object Get(int ) |
-Confirm
Данный параметр указывает, что перед выполнение командлета, необходимо запросить у пользователя подтверждение на выполнения команды.
Пример:
PS C:\temp> Set-Content 1.txt "Hello" -Confirm Подтверждение Вы действительно хотите выполнить это действие? Выполнение операции "Установка содержимого" над целевым объектом "Путь: C:\temp\1.txt". [Y] Да - Y [A] Да для всех - A [N] Нет - N [L] Нет для всех - L [S] Приостановить - S [?] Справка (значением по умолчанию является "Y"):N PS C:\temp>
PS C:\temp> Set-Content 1.txt "Hello" -Confirm
Подтверждение Вы действительно хотите выполнить это действие? Выполнение операции "Установка содержимого" над целевым объектом "Путь: C:\temp\1.txt". [Y] Да - Y [A] Да для всех - A [N] Нет - N [L] Нет для всех - L [S] Приостановить - S [?] Справка (значением по умолчанию является "Y"):N PS C:\temp> |
Данные командлеты позволяют писать в файл только строки, для записи в файл объектов используются следующие командлеты:
Out-File
В простейшем варианте этот командлет выглядит так:
get-childitem | Out-File 2.txt
get-childitem | Out-File 2.txt |
При выполнении данной команды, get-childitem передаст содержимое каталога на командлет Out-File, а он запишет его в файл «2.txt» в текущем каталоге. При этом если файл «2.txt» существует, то командлет его перезапишет.
Out-File может принимать следующие параметры:
-FilePath «Имя файла»
В этом параметре нужно указывать имя файла или полный путь до файла в который будет записаны данные.
Имя данного параметра можно опустить, как мы и сделали в предыдущем примере.
Полная запись будет выглядеть так:
get-childitem | Out-File -FilePath 2.txt
get-childitem | Out-File -FilePath 2.txt |
-Append
При указании данного параметра данные будут дописываться, а не затираться.
Тоесть если мы запустим команду:
get-childitem | Out-File -FilePath 2.txt -Append
get-childitem | Out-File -FilePath 2.txt -Append |
То данные будут дописываться в конец файла «2.txt».
-NoClobber
Данный параметр предотвращает перезапись существующих данных.
Если запусnить команду :
get-childitem | Out-File -FilePath 2.txt -NoClobber
get-childitem | Out-File -FilePath 2.txt -NoClobber |
При уже имеющемся файле 2.txt
То получится ошибка:
Out-File : Файл "C:\temp\2.txt" уже существует. строка:1 знак:25 + get-childitem | Out-File <<<< -FilePath 2.txt -NoClobber + CategoryInfo : ResourceExists: (C:\temp\2.txt:String) [Out-File], IOException + FullyQualifiedErrorId : NoClobber,Microsoft.PowerShell.Commands.OutFileCommand
Out-File : Файл "C:\temp\2.txt" уже существует. строка:1 знак:25 + get-childitem | Out-File <<<< -FilePath 2.txt -NoClobber + CategoryInfo : ResourceExists: (C:\temp\2.txt:String) [Out-File], IOException + FullyQualifiedErrorId : NoClobber,Microsoft.PowerShell.Commands.OutFileCommand |
Однако с параметром -Append
get-childitem | Out-File -FilePath 2.txt -NoClobber -Append
get-childitem | Out-File -FilePath 2.txt -NoClobber -Append |
Сохранности данных ничего не угрожает и данные благополучно допишутся в конец файла.
-Confirm
Параметр указывает, что перед выполнением команды у пользователя будет запрошено подтвержение.
При выполнении данной команды:
get-childitem | Out-File -FilePath 2.txt -Confirm
get-childitem | Out-File -FilePath 2.txt -Confirm |
Выведется следующее сообщение:
Подтверждение Вы действительно хотите выполнить это действие? Выполнение операции "Вывод в файл" над целевым объектом "2.txt". [Y] Да - Y [A] Да для всех - A [N] Нет - N [L] Нет для всех - L [S] Приостановить - S [?] Справка (значением по умолчанию является "Y"):
Подтверждение Вы действительно хотите выполнить это действие? Выполнение операции "Вывод в файл" над целевым объектом "2.txt". [Y] Да - Y [A] Да для всех - A [N] Нет - N [L] Нет для всех - L [S] Приостановить - S [?] Справка (значением по умолчанию является "Y"): |
-Force
Перезаписать файл с атрибутом «Только на чтение».
То есть команда:
get-childitem 234234f 2>&1 | Out-file 2.txt -force
get-childitem 234234f 2>&1 | Out-file 2.txt -force |
Позволяет переписать файл 2.txt даже если в Атррибуте будет стоят галочка «Только на чтение».
При этом после записи в этот файл, галка не уберётся.
-Encoding «Тип кодировки»
Задаёт метод кодировки в файле можно писать файл в следующих кодировках: «Unicode», «UTF7», «UTF8», «UTF32», «ASCII», «BigEndianUnicode» и «OEM». По умолчанию использует кодировку «Unicode».
Пример:
get-childitem 234234f 2>&1 | Out-file 2.txt -Encoding "ASCII"
get-childitem 234234f 2>&1 | Out-file 2.txt -Encoding "ASCII" |
-InputObject «Переменная»
Данный параметр позволяет сохранять в файл объект. При этом отображение этого объекта в консоли и сохраннёные данные в файл, могут визуально не совпадать
Например создадим вложенный массив :
$a1 = 1,2,3 $a2 = $a1,$a1,$a1
$a1 = 1,2,3
$a2 = $a1,$a1,$a1 |
Посмотрим на массив:
В данном примере и в файле и в консоле будет одно и тоже:
Запишем объект массива в файл, через параметр -InputObject:
Out-File -InputObject $a2 2.txt;$a2
Out-File -InputObject $a2 2.txt;$a2 |
Теперь в консоли будет выводиться :
А в файл :
Length : 3 LongLength : 3 Rank : 1 SyncRoot : {1, 2, 3} IsReadOnly : False IsFixedSize : True IsSynchronized : False Count : 3 Length : 3 LongLength : 3 Rank : 1 SyncRoot : {1, 2, 3} IsReadOnly : False IsFixedSize : True IsSynchronized : False Count : 3 Length : 3 LongLength : 3 Rank : 1 SyncRoot : {1, 2, 3} IsReadOnly : False IsFixedSize : True IsSynchronized : False Count : 3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
Length : 3 LongLength : 3 Rank : 1 SyncRoot : {1, 2, 3} IsReadOnly : False IsFixedSize : True IsSynchronized : False Count : 3
Length : 3 LongLength : 3 Rank : 1 SyncRoot : {1, 2, 3} IsReadOnly : False IsFixedSize : True IsSynchronized : False Count : 3
Length : 3 LongLength : 3 Rank : 1 SyncRoot : {1, 2, 3} IsReadOnly : False IsFixedSize : True IsSynchronized : False Count : 3 |
-Width «Ширина в символах»
Указывает максимальное кол-во символов в строке, при превышении данного значения, строка обрезается.
Пример:
Get-ChildItem |Out-File .\2.txt -Width 40
Get-ChildItem |Out-File .\2.txt -Width 40 |
Получился вот такой файл:
Каталог: C:\temp ПРЕДУПРЕЖДЕНИЕ: столбец Name не поместил ся на экране и был удален. Mode LastWriteTime Length ---- ------------- ------ -a--- 21.07.2015 12:39 117 -a--- 21.07.2015 17:33 458 -a--- 21.07.2015 16:43 1709
Каталог: C:\temp
ПРЕДУПРЕЖДЕНИЕ: столбец Name не поместил ся на экране и был удален.
Mode LastWriteTime Length ---- ------------- ------ -a--- 21.07.2015 12:39 117 -a--- 21.07.2015 17:33 458 -a--- 21.07.2015 16:43 1709 |
Данный инструмент намного функциональней, чем просто перенаправление в файл, но он как и перенаправление имеет один не достаток, эти способы могут быть только в конце контейнера. И после данных выводов в файл объекты дальше не передаются. Это позволяет избежать следующий командлет:
Tee-Object
Этот командлет сохраняет отображаемые объекты и передаёт их дальше по контейнеру.
Пример:
Get-ChildItem *.txt|Tee-Object 3.txt |Get-Content
Get-ChildItem *.txt|Tee-Object 3.txt |Get-Content |
coolcode.ru
Powershell — логирование в файл / Хабр
Доброго времени суток, $username!Хочу поделиться с вами функцией, которую я использую вместо обычного вывода информации на экран или только записи в файл.
Функция была написана для того, чтобы информация выводилась и на экран и в лог (текстовый), предназначается для замены стандартного write-host.
Из вкусностей:
- Точная дата и время события
- Тип события
- Подсчет ошибок и предупреждений
- Вывод информации цветом (в зависимости от типа события)
- Формат лога совместим с CSV ([TAB] separated)
Функция объявлена глобально, это значит что в пределах одной сессии достаточно один раз ее проиницилизировать — читай запустить файл с ней.
Варианты использования:write-log "Hello Хабр!" 14.07.2011 00:22:15 info Hello Хабр! write-log -message "Hello Хабр!" -type warning
write-log -message "Hello Хабр!" -type error -silent
Правда, путь должен существовать: write-log -message "Hello Хабр!" -type CustomType logfile c:\enter\your\path\here.log
Количество ошибок и предупреждений (за всю сессию или до ручного обнуления переменных) хранятся в $errorcount и $warningcount.
Лично у меня эта функция храниться в файле set-functions.ps1, и в скриптах я ее вызываю так:
Cамое начало любого (там где это необходимо) моего скрипта:
$ver="0.1" $ProgrammName="SomeScriptName" try { # Функция вывода информации на экран и записи в лог ./Set-Functions.ps1 #Инициализация функций $global:logfilename = "log`\"+ $ProgrammName +".log" write-log "$ProgrammName (ver $ver) started." } catch { return "Error loading functions Set-Functions.ps1" }Тело функции write-log:
$ver = "0.4" $dt=Get-Date -Format "dd-MM-yyyy" New-Item -ItemType directory log -Force | out-null #Создаю директорию для логов $global:logfilename="log\"+$dt+"_LOG.log" [int]$global:errorcount=0 #Ведем подсчет ошибок [int]$global:warningcount=0 #Ведем подсчет предупреждений function global:Write-log # Функция пишет сообщения в лог-файл и выводит на экран. {param($message,[string]$type="info",[string]$logfile=$global:logfilename,[switch]$silent) $dt=Get-Date -Format "dd.MM.yyyy HH:mm:ss" $msg=$dt + "`t" + $type + "`t" + $message #формат: 01.01.2001 01:01:01 [tab] error [tab] Сообщение Out-File -FilePath $logfile -InputObject $msg -Append -encoding unicode if (-not $silent.IsPresent) { switch ( $type.toLower() ) { "error" { $global:errorcount++ write-host $msg -ForegroundColor red } "warning" { $global:warningcount++ write-host $msg -ForegroundColor yellow } "completed" { write-host $msg -ForegroundColor green } "info" { write-host $msg } default { write-host $msg } } } }У этого примера есть только один недостаток — она «синхронная», то есть не обрабатывает проблемы одновременной записи в лог-файл. Кто знает как это изменить, прошу в комменты.
habr.com
Записочка по PowerShell | ITNote
Не так часто использую PowerShell. По этому решил записать некоторые особенности в одной записи что бы освежать память. А вообще Python приятней 🙂
Перед выполнение скриптового файла
set-executionpolicy remotesignedПолучить помощь
# помощь по команде Get-Process get-help Get-Process # пример использования команды Get-Process get-help Get-Process -examples # Получить методы возвращаемого объекта Get-Process Get-Process| Get-Member # Узнать тип объекта. В данном случае переменной с каталогом пользователя $home.GetType()Операции сравнения
Операция | без учета регистра | с учетом регистра | C# | равно(equal) | -eq | -ceq | == | не равно (not equal) | -ne | -cne | != | больше чем (greater then) | -gt | -cgt | > | меньше чем (less than) | -lt | -clt | < | больше равно (greater or equal) | -ge | -cge | >= | меньше равно (less than or equal) | -le | -cle | <= |
Операции со строкамиПолная аналогия с C#.Разбить строку по пробелам
$string = "Test string" $string.split(" ")Ищем в $string первый пробел
$string.IndexOf(" ")Предопределенные переменнеы$home — каталог пользователя$NULL — пусто$true — истина$false — лож$DebugPreference — «Continue» выводить отладку, «SilentlyContinue» не выводить отладочную информацию. См. команду Write-Debug
Работа с файламиДописать $string новой строкой в файл $file
$string | Out-File $file -AppendПолучить в $string содержимое файла $file
$string = get-content -Path $fileПроверить существование файла:
Test-Path "C:test.txt"Найти все файлы с определенным расширением расширением в каталоге и подкаталогах.Затем скопировать эти файлы в другой каталог.
$flist = get-childitem e:doc* -include *.pdf -recurse $flist | ForEach-Object{$_.CopyTo("e:docall_pdf" + $_.PSChildName)}Текущий каталог
$local = Get-Location $local.Path # Рабочий каталог $local.Drive.Root # Корень $local.Drive.Name # Буква диска $local.Drive.Used # Использовано диска $local.Drive.Free # Свободно на дискеВывод текста на экран
# текст на который надо обратить внимание. Выделяется желтым. Write-Warning("Текст требующий внимания") # Просто выводит текст Write-Host("Просто текст") #включили вывод отладочной информации $DebugPreference = "Continue" # вывели отладочную информацию Write-Debug "Cannot open file." # отключили отладочную вывод отладочной информации $DebugPreference = "SilentlyContinue"Сделать паузу на несколько секунд
Start-Sleep -s 15 # Пауза на 15 секундПауза в консоли, до нажатия Enter
Read-Host "Нажмите Enter"Работа с процессамиЗадача: убить все процессы с именем Notepad
# Способ №1 get-process Notepad | Stop-Process # Способ №2 (Работает только с одним процессом) $plist = get-process Notepad $plist.Kill() # Способ №3 (то же что и 2, но все процессы) $plist = get-process Notepad $plist | ForEach-Object {$_.Kill()}Получить процессы и даты их запуска
Get-Process| Format-Table Name,StartTime -AutoSizeitnote.ru
[stdout] Как перенаправить вывод PowerShell в файл во время его выполнения [scripting]
Возможно, Start-Transcript будет работать для вас. Сначала остановите его, если он уже запущен, затем запустите его и остановите, когда закончите.
$ErrorActionPreference="SilentlyContinue" Stop-Transcript | out-null $ErrorActionPreference = "Continue" Start-Transcript -path C:\output.txt -append # do some stuff Stop-TranscriptВы также можете запустить этот процесс во время работы над файлами и сохранить его для сеансов командной строки для последующего использования.
EDIT : если вы хотите полностью подавить ошибку при попытке остановить транскрипцию, которая не расшифровывается, вы можете сделать это:
$ErrorActionPreference="SilentlyContinue" Stop-Transcript | out-null $ErrorActionPreference = "Continue" # or "Stop"Напишите «Stuff to write» | Out-File Outputfile.txt -Append
Возможно, вы захотите взглянуть на Tee-Object cmdlet. Вы можете вывести вывод на Tee, и он будет записываться в конвейер, а также в файл
powershell ".\MyScript.ps1" > test.logЕсли вы хотите прямое перенаправление всего вывода в файл, попробуйте использовать *>> :
# You'll receive standard output for the first command, and an error from the second command. mkdir c:\temp -force *>> c:\my.log ; mkdir c:\temp *>> c:\my.log ;Так как это прямой перенаправление на файл, он не будет выводиться на консоль (часто полезно). Если вы хотите вывести консоль, объедините все выходные данные с помощью *&>1 , а затем подключите с помощью Tee-Object :
mkdir c:\temp -force *>&1 | Tee-Object -Append -FilePath c:\my.log ; mkdir c:\temp *>&1 | Tee-Object -Append -FilePath c:\my.log ; # shorter aliased version mkdir c:\temp *>&1 | tee -Append c:\my.log ;Я считаю, что эти методы поддерживаются Powershell 3.0+, я тестирую Powershell 5.0.
code-examples.net
Как рекурсивно получить размер всех файлов и папок в PowerShell, настраиваемый вывод
Я хочу получить размер каждого файла/папки по определенному пути и вывести его в файл.
Я играл с PowerShell, насколько мог, с моим очень ограниченным знанием PowerShell и просмотром многих сообщений, но я не могу найти способ его вывода, поскольку мне это нужно.
В настоящее время у меня есть сценарий ниже, благодаря этому post.
$folderToBeListed = "PATH"; $folder = (Get-ChildItem $folderToBeListed -recurse | Where-Object {$_.PSIsContainer -eq $False} | Sort-Object) foreach ($i in $folder) { $i.DirectoryName $subFolderItems = (Get-ChildItem $i.FullName | Measure-Object -property Length -sum | Select-Object Sum) $i.Name + " -- " + "{0:N2}" -f ($subFolderItems.sum /1MB) + " MB" } <# $date = "$(Get-Date -f [email protected])h$(Get-Date -f mm)m$(Get-Date -f ss)s" Out-File PATH\filesSizes_$date.txt #>Это выводит ниже формат:
DirectoryName -- size MB FileName -- size MB DirectoryName FileName -- size MBЯ хотел бы выход быть похожим на это:
DirectoryName -- size MB FileName1 -- size MB FileName2 -- size MB Folder1 -- size MB FileName3 -- size MB FileName4 -- size MB Folder2 -- size MB FileName5 -- size MB DirectoryName2 -- size MB ...Есть ли способ, чтобы пройти через все файлы и папки рекурсивно форматировать их таким образом или мне нужно форматировать вывод с DirectoryName по файлу, а затем фильтровать их по имени каталога?
Тогда я хотел бы выводить результат в файле (комментируемая часть является моей отправной точкой пока я не знаю, что кормить Out-File.
Update
Отступа не является обязательным. Я положил его, чтобы он показывает более наглядно, что я намерен получить в качестве продукции, но на самом деле, ниже выход будет в порядке.
DirectoryName -- size MB FileName1 -- size MB FileName2 -- size MB Folder1 -- size MB FileName3 -- size MB FileName4 -- size MB Folder2 -- size MB FileName5 -- size MB DirectoryName2 -- size MB ...Update 2
Это обновление того, что у меня есть. У него все еще есть недостатки, и он еще не прав. Я опишу проблемы с этим ниже кода.
$folderToBeListed = "PATH"; $elements = Get-ChildItem $folderToBeListed -recurse $originSize = getSizeFolder -path $folderToBeListed "Listed folder : " + $folderToBeListed + " -- Size : " + $originSize + " MB"| Out-String foreach ($i in $elements) { if($i.PSIsContainer -eq $True) { try { $folderSize = getSizeFolder -path $i.FullName "`n`nFolder -- " + $i.Name + " -- Size : " + $folderSize + " MB" | Out-String foreach ($it in (Get-ChildItem $i.FullName -recurse)) { $fileSize = getSizeFile -path $it.FullName $it.Name + " -- " + $fileSize + " KB" } } catch { "NOOO (It's a catch, line ~28)" | Out-String } } else { $i.Name + " -- " + $fileSize + " KB" } } function getSizeFolder($path) { $sizeFolder = (Get-Item $path).GetFiles() | Measure-Object -Sum Length return $sizeFolder.Sum/1000000 <#Supposed MB#> } function getSizeFile($path) { $sizeFile = (Get-Item $path).Length return $sizeFile/1000 <#Supposed KB#> }Хорошо так ситуации, у меня встреча еще являются следующим:
1- Если есть папка, содержащая другую папку, он делает список все папки и файлы внутри только.
Folder -- DirectoryName -- Size XX MB Folder1 -- Size XX KB Folder2 -- Size XX KB FileInFolder1 -- Size XX KB ...2 Если есть только папки, содержащие файлы, это показывает, что это нормально.
Folder -- DirectoryName -- Size XX MB File1 -- Size XX KB File2 -- Size XX KB Folder2 -- DirectoryName -- Size XX MB File3 -- Size XX KB File4 -- Size XX KB ...Это, как говорится, у меня еще есть все файлы, перечисленные в конце концов, из-за статьи еще ...
Update 3
Взял немного другого подхода. Это список всех папок и файлов в выбранной папке, но я еще не реализовал «рекурсивность». Все еще пытаясь выяснить алгоритм, который я буду использовать для его работы. Я еще не начал операцию записи в txt-файле. Вся помощь приветствуется!
function getFoldersInFolder($path) { [array]$elements = Get-ChildItem $path | Where-Object {$_.PSIsContainer} return $elements } function getFilesInFolder($path) { [array]$elements = Get-ChildItem $path | Where-Object {!$_.PSIsContainer} return $elements } function getSizeFolder($path) { $sizeFolder = (Get-Item $path).GetFiles() | Measure-Object -Sum Length if($sizeFolder.Sum -lt 1000)<#Octets#> { if($sizeFolder.Sum -eq $Null)<#The folder contains only folders#> { return "`n`nThe size is null (th efolder only contains folders.)`nThe sizes of each folder will be displayed below." } else { return "{0:N2}" -f $sizeFolder.Sum + " octets" } } elseif($sizeFolder.Sum -gt 1000 -and $sizeFolder.Sum -lt 999999)<#Ko#> { return "{0:N2}" -f ($sizeFolder.Sum/1000) + " Ko" } elseif($sizeFolder.Sum -gt 1000000 -and $sizeFolder.Sum -lt 999999999)<#Mo#> { return "{0:N2}" -f ($sizeFolder.Sum/1000000) + " Mo" } elseif($sizeFolder.Sum -gt 1000000000 -and $sizeFolder.Sum -lt 999999999999)<#Go#> { return "{0:N2}" -f ($sizeFolder.Sum/1000000000) + " Go" } } function getSizeFile($path) { $sizeFile = (Get-Item $path).Length if($sizeFile -lt 1000)<#Octets#> { return "{0:N2}" -f $sizeFile + " octets" } elseif($sizeFile -gt 1000 -and $sizeFile -lt 999999)<#Ko#> { return "{0:N2}" -f ($sizeFile/1000) + " Ko" } elseif($sizeFile -gt 1000000 -and $sizeFile -lt 999999999)<#Mo#> { return "{0:N2}" -f ($sizeFile/1000000) + " Mo" } elseif($sizeFile -gt 1000000000 -and $sizeFile -lt 999999999999)<#Go#> { return "{0:N2}" -f ($sizeFile/1000000000) + " Go" } } function main() { $folder = "{INPUT PATH HERE}" $originFolderSize = getSizeFolder -path $folder Write-Host "`nBelow are the files/folders from : $folder => Size : $originFolderSize `n" <#List all folders#> [array]$foldersInFolder = getFoldersInFolder -path $folder for($i = 0; $i -lt $foldersInFolder.Count; $i++) { ##$foldersInFolder[$i] | Out-String $tempPath = $folder + "\" + $foldersInFolder[$i] $tempFolderSize = getSizeFolder -path $tempPath Write-Host FOLDER => $foldersInFolder[$i] => Size : $tempFolderSize`n } <#List all files#> [array]$filesInFolder = getFilesInFolder -path $folder for($i = 0; $i -lt $filesInFolder.Count; $i++) { ##$filesInFolder[$i] | Out-String $tempPath = $folder + "\" + $filesInFolder[$i] $tempFileSize = getSizeFile -path $tempPath Write-Host FILE => $filesInFolder[$i] => Size : $tempFileSize`n } } mainЭто делает выходы, как это:
Below are the files/folders from : PATH => Size : XX,XX Mo FOLDER1 => Folder1Name => Size : XX,XX Mo FOLDER2 => Folder2Name => Size : XX,XX Ko FILE1 => File1Name => Size : XX,XX Mo FILE2 => File2Name => Size : XX,XX Go FILE3 => File3Name => Size : XX,XX Kostackoverrun.com
Добавить вывод Powershell в файл Excel MS Excel онлайн
Хорошо, CSV в порядке, но при представлении данных или совместном использовании с другими это просто не очень, поэтому я полностью хочу сбросить данные в Excel. Чтобы добавить данные в лист Excel, я настоятельно рекомендую запустить массив объектов, а затем использовать командлет ConvertTo-CSV , Clip и вставить в Excel.
Вы действительно не указываете, что хотите вставить в Excel, но я собираюсь предположить HostName, Serial # и пользователей. Поскольку список пользователей представляет собой массив, я присоединяюсь к нему в строку, чтобы Excel не волновался об этом и вставлял тонну пустых строк.
Итак, давайте сделаем эту информацию в объект. Есть несколько способов сделать это, но тот, который я предпочитаю (должен работать на PS v3 и выше), должен отличать его как таковой:
$Record = [PSCustomObject]@{ 'Hostname' = $Hostname 'Serial Number' = $Serialnumber 'Users' = $(If($XPUsers){$XPUsers}Else{$Win7Users}) -join ', ' }Теперь, если мы ConvertTo-Csv это к ConvertTo-Csv и сделаем его вкладкой с помощью -NoTypeInformation он выйдет примерно так:
PS C:\Temp> $Record|ConvertTo-Csv -del "`t" -notype "Hostname" "Serial Number" "Users" "Computer001" "42K6NNZ" "TMTech, Andrew"Теперь, если вы не хотите, чтобы строка заголовка вставлялась в ваш файл Excel каждый раз, когда мы Select -Skip 1 в Select -Skip 1 и это решает. Но сейчас мы включим его. Вот код, который я бы использовал, чтобы получить эту информацию в Excel.
#Launch Excel $XL = New-Object -ComObject Excel.Application #Open the workbook $WB = $XL.Workbooks.Open("C:\HDDInfo.xlsx") #Activate Sheet1, pipe to Out-Null to avoid 'True' output to screen $WB.Sheets.Item("Sheet1").Activate() | Out-Null #Find first blank row #, and activate the first cell in that row $FirstBlankRow = $($xl.ActiveSheet.UsedRange.Rows)[-1].Row + 1 $XL.ActiveSheet.Range("A$FirstBlankRow").Activate() #Create PSObject with the properties that we want, convert it to a tab delimited CSV, and copy it to the clipboard $Record = [PSCustomObject]@{ 'Hostname' = $Hostname 'Serial Number' = $Serialnumber 'Users' = $(If($XPUsers){$XPUsers}Else{$Win7Users}) -join ', ' } $Record | ConvertTo-Csv -Delimiter "`t" -NoTypeInformation | Clip #Paste at the currently active cell $XL.ActiveSheet.Paste() | Out-Null # Save and close $WB.Save() | Out-Null $WB.Close() | Out-Null $XL.Quit() | Out-Null #Release ComObject [System.Runtime.Interopservices.Marshal]::ReleaseComObject($XL)Теперь вам может потребоваться изменить пользовательский объект, но он должен делать то, что вы хотите. Если ваш скрипт обрабатывает более одного элемента за раз, вы можете создать массив объектов и вставить их все в Excel сразу таким образом.
Изменить: Хорошо, где пропустить заголовок и вставить имена в свои ячейки …
Как я уже сказал, вы будете трубить:
`$Record|ConvertTo-Csv -del "`t" -notype`в |Select -Skip 1 . Это может сбить с толку, я думаю, потому что тогда я вложил его в | Clip | Clip , но если вы рассмотрите, как работает конвейер, и как каждый канал принимает вывод из предыдущего сегмента, то вы ConvertTo-CSV в Select -Skip 1 чтобы он пропускал первую строку (где находятся заголовки), а затем подключить к Clip чтобы скопировать результат в буфер обмена … Это имеет смысл, когда вы его сломаете. Команда будет выглядеть так:
$Record | ConvertTo-Csv -del "`t" -notype | Select -Skip 1 | ClipТеперь для вставки каждого пользователя в свою ячейку вам нужно быть более конкретным. Вы хотите охватить ячейки по горизонтали или по вертикали? Если вы хотите по горизонтали, тогда все становится сложнее. В основном, что мы будем делать, это создать объект, а затем использовать Add-Member для добавления свойств к объекту, по одному для каждого пользователя.
#Create PSObject with the properties that we want, convert it to a tab delimited CSV, and copy it to the clipboard $Record = [PSCustomObject]@{ 'Hostname' = $Hostname 'Serial Number' = $Serialnumber } #Compile users, and add a member to the object for each user [Array]$Users = If($WinXPUsers){$WinXPUsers}Else{$Win7Users} For($i = 0; $i -lt $Users.Count; $i++){ $Record | Add-Member "User$i" $Users[$i] } $Record | ConvertTo-Csv -Delimiter "`t" -NoTypeInformation | Select -Skip 1 | ClipЭто создало бы запись вроде этого (заголовки, оставшиеся для ссылки, они не появлялись в Excel):
Hostname Serial Number User0 User1 -------- ------------- ----- ----- Computer001 42K6NNZ TMTech AndrewЕсли вы хотите перечислить каждого пользователя по вертикали, вы можете сделать что-то вроде создания объекта для каждого пользователя, но только с Host и S / N на первом.
[Array]$Users = If($WinXPUsers){$WinXPUsers}Else{$Win7Users} [Array]$Record = [PSCustomObject]@{ 'Hostname' = $Hostname 'Serial Number' = $Serialnumber 'Users' = $Users[0] } $Record += $Users | Select -Skip 1 | ForEach{[PSCustomObject]@{ 'Hostname' = '' 'Serial Number' = '' 'Users' = $_ }}Это выводит что-то вроде этого (заголовки слева для ссылки, они не появятся в Excel):
Hostname Serial Number Users -------- ------------- ----- Computer001 42K6NNZ TMTech Andrewexcel.bilee.com