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()

Затем скормим содержимое Out-String а вывод сохраним в переменную $b:

$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 -AutoSize

itnote.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 Ko

stackoverrun.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 Andrew

excel.bilee.com