- Remove From My Forums
-
Question
-
Hello
Infos from me:
Working on a win 7 64x VM
scripting with Power Gui Editor
WPS v2 installed.
————————————
My problem:
I’be got an excel file where weve got date and some VmWare Datastore infos.
So everytime, whe the script is runnig it Schould insert on top of the allready existing excel data 8 new rows. where i can fill in the new Datastore informations.
but how can i insert new rows with powershell?
What i found was this thread. but because the script isnt commented at all i didnt understand it.
http://social.technet.microsoft.com/forums/en-us/ITCG/thread/18BEC31A-A020-4BD3-BADD-B524C9C4830B
[ Im swiss. I’m sorry for my bad english writing ]
-
Edited by
Friday, December 16, 2011 10:16 AM
-
Edited by
Answers
-
This is the basic code for inserting a row at the top of a worksheet:
$xlShiftDown = -4121 $strPath="c:ScriptsBook2.xlsx" $objExcel=New-Object -ComObject Excel.Application $objExcel.Visible=$true $WorkBook=$objExcel.Workbooks.Open($strPath) $worksheet = $workbook.sheets.item("Sheet1") $eRow = $worksheet.cells.item(1,1).entireRow $active = $eRow.activate() $active = $eRow.insert($xlShiftDown)
([string](0..9|%{[char][int](32+(«39826578846355658268″).substring(($_*2),2))})).replace(‘ ‘,»)
-
Marked as answer by
HH.Scripting
Friday, December 16, 2011 11:50 AM
-
Marked as answer by
I have a small Excel template, the first row consists of cells with formulas like
=SUBTOTAL(9,C3:C15000)
and such. The second row is headers.
I have a PowerShell process gathering data to fill the Excel daily using Import-Excel
, but when I merge the two files (importing the template Excel into a variable and adding rows to it), those top cells with the formulas lose their underlying formula values and get read as 0 (since there is no data in the template).
Is there a way to preserve those formula cells so that when the file is exported, they will contain dynamic values? I am using the Import-Excel
module now but I’m not opposed to doing it a different way, including other programs. Thank you!
$report = $report | Sort thing_1, thing_2 | Select $reportcolumns
$template = Import-Excel -Path C:TempTemplate.xlsx -NoHeader
foreach ($row in $report) {
$template += $row
}
$template | Export-Excel -Path C:TempFilled_Template.xlsx
$Report is a collection of customPS objects with the same columns as the template.
Some stuff happens before this but it’s specific, and not really important to this part of the script anyway.
I’m guessing that you want all of your user objects inserted, and are assuming that you can only do a row at a time since that would be better than a cell at a time. Let’s just do the whole array at once instead, what do you say? You don’t give us some of the information that would be needed, so I’ll make up what I don’t have already. Obviously you want to use the worksheet represented by $SPREADSHEET_WORKSHEET_2
, which is fine we can work with that. Since you posted code that supposedly enters the names of the properties as a header row I assume that you do in fact want a header row, which is good because we are going to paste one in by default (skipping that gets a little more complicated, but I digress). I am going to use $arrUsers
as your array variable name since you did not specify one (I am assuming that $obj
is one object from the array). So, let’s do this…
We will be pasting the array of objects with a header row at cell A1. When pasting to Excel you want things to be tab delimited, which we can do easily enough with ConvertTo-CSV -delimeter "
t»and we will also use the
-NoTypeInformation` switch for that same cmdlet so that it doesn’t insert the object type info as the first row and just gives us the header and records. We will pipe to Clip (if your PowerShell doesn’t like to pipe to Clip you can pipe to c:windowssystem32clip.exe instead which basically inserts things into your clipboard, which is awesome for this purpose).
#Convert array of object to a CSV that is tab delimited and without object type information, and copy it to the clipboard
$arrUsers | ConvertTo-CSV -Delimeter "`t" -NoType | Clip
#Select the first cell of the desired sheet and activate it's PasteSpecial method with no arguments (typing it as `[void]` so we don't get "True" spam because it was successful)
[void]$SPREADSHEET_WORKSHEET_2.cells.Item(1).PasteSpecial()
Done. No, really, that’s it. That will paste the entire array with headers to the desired sheet of your workbook at cell A1.
Ok, so that didn’t actually directly answer your question, but I think it’s what you wanted. To directly answer your question I will tell you how to fill an entire row’s worth of values at once. Basically it is the same thing, but we only select one object from the array, and also add |select -skip 1
right before we pipe to clip so that it skips the header row.
$arrUsers[20] | ConvertTo-CSV -NoType -Del "`t" | Select -Skip 1 | Clip
[void]$SPREADSHEET_WORKSHEET_2.cells.Item(1).PasteSpecial()
That pastes the 21st user’s record into A1. You don’t want A1? Well, that’s manageable, let’s say you want A22 (21st user, plus header row, it makes sense in my head). We can do:
[void]$SPREADSHEET_WORKSHEET_2.columns.Item(1).cells.item(22).PasteSpecial()
That’s the first row, and the 22nd cell in that row. Or you can use the Range method like you did before:
[void]$SPREADSHEET_WORKSHEET_2.Range("A22").cells.Item(1).PasteSpecial()
Same thing. Just a last comment here before I go…
We use .cells.item(1)
so often because the Cell object is what has the PasteSpecial method that we want to use. With no arguments it works just like a generic paste. The WorkSheet object does have a Paste method, but that goes off the currently selected cell, and from the way you were talking it sounds like you really don’t want to do that. This lets you specify a cell and paste directly to it.
В это статье мы покажем, как получить доступ к данным в файлах Excel напрямую из PowerShell. Возможности прямого обращения к данным Excel из PowerShell открывает широкие возможности по инвентаризации и построению различных отчетов по компьютерам, серверам, инфраструктуре, Active Directory и т.д.
Содержание:
- Доступ к данным в Excel из консоли PowerShell
- Как получить данные из Active Directory и сохранить их в книге Excel?
Обращение к Excel из PowerShell выполняется через отдельный Component Object Model (COM) объект. Это требует наличие установленного Excel на компьютере.
Прежде, чем показать, как обратиться к данным в ячейке файла Excel, необходимо рассмотреть архитектуру уровней представления в документе Excel. На следующем рисунке показаны 4 вложенных уровня в объектной модели Excel:
- Уровень приложения (Application Layer) – запущенное приложение Excel;
- Уровень книги (WorkBook Layer) – одновременно могут быть открыты несколько книг (документов Excel);
- Уровень листа (WorkSheet Layer) – в каждом xlsx файле может быть несколько листов;
- Ячейки (Range Layer) – здесь можно получить доступ к данным в конкретной ячейке или диапазонe ячеек.
Доступ к данным в Excel из консоли PowerShell
Рассмотрим на простом примере как получить доступ из PowerShell к данным в Excel файле со списком сотрудников.
Сначала нужно запустить на компьютере приложение Excel (application layer) через COM объект:
$ExcelObj = New-Object -comobject Excel.Application
После выполнения этой команды на компьютере запускается в фоновом режиме приложение Excel. Чтобы сделать окно Excel видимым, нужно изменить свойство Visible COM объекта:
$ExcelObj.visible=$true
Все свойства объекта Excel можно вывести так:
$ExcelObj| fl
Теперь можно открыть файл (книгу, workbook) Excel:
$ExcelWorkBook = $ExcelObj.Workbooks.Open("C:PSad_users.xlsx")
В каждом файле Excel может быть несколько листов (worksheets). Выведем список листов в текущей книге Excel:
$ExcelWorkBook.Sheets| fl Name, index
Теперь можно открыть конкретный лист (по имени или по индексу):
$ExcelWorkSheet = $ExcelWorkBook.Sheets.Item("AD_User_List")
Текущий (активный) лист Excel можно узнать командой:
$ExcelWorkBook.ActiveSheet | fl Name, Index
Теперь вы можете получить значения из ячеек документа Excel. Можно использовать различные способы адресации ячеек в книге Excel: через диапазон (Range), ячейку (Cell), столбец (Columns) или строку(Rows). Ниже я привел разные примеры получения данных из одной и той же ячейки:
$ExcelWorkSheet.Range("B2").Text
$ExcelWorkSheet.Range("B2:B2").Text
$ExcelWorkSheet.Range("B2","B2").Text
$ExcelWorkSheet.cells.Item(2, 2).text
$ExcelWorkSheet.cells.Item(2, 2).value2
$ExcelWorkSheet.Columns.Item(2).Rows.Item(2).Text
$ExcelWorkSheet.Rows.Item(2).Columns.Item(2).Text
Как получить данные из Active Directory и сохранить их в книге Excel?
Рассмотрим практический пример использования доступа к данным Excel из PowerShell. Например, нам нужно для каждого пользователя в Excel файле получить информацию из Active Directory. Например, его телефон (атрибут telephoneNumber), отдел (department) и email адрес (mail).
# Импорт модуля Active Directory в сессию PowerShell
import-module activedirectory
# Сначала откройте книгу Excel:
$ExcelObj = New-Object -comobject Excel.Application
$ExcelWorkBook = $ExcelObj.Workbooks.Open("C:PSad_users.xlsx")
$ExcelWorkSheet = $ExcelWorkBook.Sheets.Item("AD_User_List")
# Получаем количество заполненных строк в xlsx файле
$rowcount=$ExcelWorkSheet.UsedRange.Rows.Count
# Перебираем все строки в столбце 1, начиная со второй строки (в этих ячейках указано доменное имя пользователя)
for($i=2;$i -le $rowcount;$i++){
$ADusername=$ExcelWorkSheet.Columns.Item(1).Rows.Item($i).Text
# Получаем значение атрибутов пользователя в AD
$ADuserProp = Get-ADUser $ADusername -properties telephoneNumber,department,mail|select-object name,telephoneNumber,department,mail
#Заполняем ячейки данными из AD
$ExcelWorkSheet.Columns.Item(4).Rows.Item($i) = $ADuserProp.telephoneNumber
$ExcelWorkSheet.Columns.Item(5).Rows.Item($i) = $ADuserProp.department
$ExcelWorkSheet.Columns.Item(6).Rows.Item($i) = $ADuserProp.mail
}
#Сохраните xls файл и закройте Excel
$ExcelWorkBook.Save()
$ExcelWorkBook.close($true)
В результате в Excel файле для каждого пользователя были добавлены столбцы с информацией из AD.
Рассмотрим еще один пример построения отчета с помощью PowerShell и Excel. Допустим, вам нужно построить Excel отчет о состоянии службы Print Spooler на всех серверах домена.
# Создать объект Excel
$ExcelObj = New-Object -comobject Excel.Application
$ExcelObj.Visible = $true
# Добавить рабочую книгу
$ExcelWorkBook = $ExcelObj.Workbooks.Add()
$ExcelWorkSheet = $ExcelWorkBook.Worksheets.Item(1)
# Переименовывать лист
$ExcelWorkSheet.Name = 'Статус сервиса spooler'
# Заполняем шапку таблицы
$ExcelWorkSheet.Cells.Item(1,1) = 'Имя сервера'
$ExcelWorkSheet.Cells.Item(1,2) = 'Имя службы'
$ExcelWorkSheet.Cells.Item(1,3) = 'Статус службы'
# Выделить шапку таблицы жирным. задать размер шрифта и ширину столбцов
$ExcelWorkSheet.Rows.Item(1).Font.Bold = $true
$ExcelWorkSheet.Rows.Item(1).Font.size=14
$ExcelWorkSheet.Columns.Item(1).ColumnWidth=25
$ExcelWorkSheet.Columns.Item(2).ColumnWidth=25
$ExcelWorkSheet.Columns.Item(3).ColumnWidth=25
# получим список всех Windows Server в домене
$computers = (Get-ADComputer -Filter 'operatingsystem -like "*Windows server*" -and enabled -eq "true"').Name
$counter=2
# подключается к каждому компьютеру и получаем статус службы
foreach ($computer in $computers) {
$result = Invoke-Command -Computername $computer –ScriptBlock { Get-Service spooler | select Name, status }
#Заполняем ячейки Excel данными с сервера
$ExcelWorkSheet.Columns.Item(1).Rows.Item($counter) = $result.PSComputerName
$ExcelWorkSheet.Columns.Item(2).Rows.Item($counter) = $result.Name
$ExcelWorkSheet.Columns.Item(3).Rows.Item($counter) = $result.Status
$counter++
}
# сохраните полученный отчет и закройте Excel:
$ExcelWorkBook.SaveAs('C:psservice-report.xlsx')
$ExcelWorkBook.close($true)
Область применения возможностей доступа из PowerShell в Excel очень широка. Начиная от простого построения отчетов, например, из Active Directory, и заканчивая возможностью создания PowerShell скриптов для актуализации данных в AD из Excel.
Например, вы можете поручить сотруднику отдела кадров вести реестр пользователей в Excel. Затем с помощью PowerShell скрипта через Set-ADUser сотрудник может автоматически обновлять данные пользователей в AD (достаточно делегировать пользователю права на изменение этих атрибутов пользователей AD и показать как запускать PS скрипт). Таким образом можно вести актуальную адресную книгу с актуальными номерами телефонами и должностями.
Об инвентаризации не писал, наверное, только ленивый. Вот и я, чтобы не казаться ленивым, тоже решил взяться за это дело. Поводом для написания стало появление нескольких статей на эту тему. Меня даже заинтересовала не сама инвентаризация (что там инвентаризировать – дёргай нужные объекты, смотри их свойства), а работа с Excel’ем, так как всё руки не доходили попробовать. С Word’ом сталкиваться уже приходилось, а вот с Excel’ем ещё нет. Можно, конечно, не заморачиваться, и вывести всё в CSV-файл, но повторюсь – меня интересовала именно работа с Excel: заполнение и форматирование ячеек, раскраска, диаграммы и т.д. Но обо всём по порядку 🙂
Итак, прежде всего нужно создать объект Excel и сделать его видимым, чтоб видеть всю дальнейшую магию 🙂
# Созадём объект Excel $Excel = New-Object -ComObject Excel.Application # Делаем его видимым $Excel.Visible = $true
Это равносильно запуску Excel. Далее необходимо создать файл (в терминологии Excel рабочую книгу):
# Добавляем рабочую книгу $WorkBook = $Excel.Workbooks.Add()
В оригинале статьи автор говорит, что этой операцией добавляется три листа, и если остальные не нужны их можно/нужно удалить, и показывает как это сделать. Но у меня добавляется только один лист, не знаю с чем это связано, возможно в разных версиях офиса по разному, поэтому я на этом останавливаться не буду.
Начинаем работать с первым листом. Для простоты обращения к нему создаём соответствующую переменную:
$LogiclDisk = $WorkBook.Worksheets.Item(1)
Далее переименовываем лист (чтобы было не Лист1, Лист2 и т.д., а “человеческие” названия) и заполняем шапку таблицы:
# Переименовываем лист $LogiclDisk.Name = 'Логические диски' # Заполняем ячейки - шапку таблицы $LogiclDisk.Cells.Item(1,1) = 'Буква диска' $LogiclDisk.Cells.Item(1,2) = 'Метка' $LogiclDisk.Cells.Item(1,3) = 'Размер (ГБ)' $LogiclDisk.Cells.Item(1,4) = 'Свободно (ГБ)'
Как (наверное) понятно здесь мы пишем в каждую ячейку по очереди, первая цифра в скобках – номер строки, вторая – номер столбца.
Уже можно наслаждаться первыми результатами работы 🙂
Главное окно Excel
Пока смотрится криво из-за того, что надписи не влазят в ячейки, и хочется растянуть ячейки, но ничего страшного, мы это потом поправим.
Переходим на следующую строку, возвращаемся в первый столбец и в цикле заполняем таблицу данными по логическим дискам, после каждого диска переводим курсор (или как правильно назвать текущую ячейку?) на следующую строку и возвращаемся в первый столбец:
# Переходим на следующую строку... $Row = 2 $Column = 1 # ... и заполняем данными в цикле по логическим разделам Get-WmiObject Win32_LogicalDisk | ForEach-Object ` { # DeviceID $LogiclDisk.Cells.Item($Row, $Column) = $_.DeviceID $Column++ # VolumeName $LogiclDisk.Cells.Item($Row, $Column) = $_.VolumeName $Column++ # Size $LogiclDisk.Cells.Item($Row, $Column) = ([Math]::Round($_.Size/1GB, 2)) $Column++ # Free Space $LogiclDisk.Cells.Item($Row, $Column) = ([Math]::Round($_.FreeSpace/1GB, 2)) # Переходим на следующую строку и возвращаемся в первую колонку $Row++ $Column = 1 }
Размеры дисков переводятся в гигабайты, и чтобы много цифр не сбивали с толку, округляются до двух знаков после запятой.
Смотрим результат:
Логические диски в Excel
мдя… многовато дисков, надо-бы их немножко пообъединять, создавались когда-то временно для тестовых целей, но как известно нет ничего более постоянного чем временное 🙂
Диски с нулевыми размерами это два DVD-привода и один виртуальный.
Осталось немного приукрасить внешний вид – выделим шапку таблицы (первая строка) жирным, и отрегулируем ширину ячеек по ширине текста (до этого момента я даже не подозревал, что Excel такое умеет:)):
# Выделяем жирным шапку таблицы $LogiclDisk.Rows.Item(1).Font.Bold = $true # Выравниваем для того, чтобы их содержимое корректно отображалось в ячейке $UsedRange = $LogiclDisk.UsedRange $UsedRange.EntireColumn.AutoFit() | Out-Null
Переменная $UsedRange содержит все занятые ячейки (эквивалентно однократному нажатию Ctrl+A)
Смотрим, что получилось:
Готовая таблица
Красота да и только 🙂
С логическими дисками разобрались, переходим к физическим.
Создадим для них отдельный лист:
# Добавляем лист $WorkBook.Worksheets.Add()
Тут есть один нюанс, заключающийся в том, что листы добавляются в обратном порядке, т.е. только что добавленный лист будет иметь номер 1, а предыдущий станет номером 2. Поэтому выделяем только что созданный лист, и делаем всё то же самое, только с физическими дисками:
$PhysicalDrive = $WorkBook.Worksheets.Item(1) # Переименовываем лист $PhysicalDrive.Name = 'Физические диски' # Заполняем ячейки - шапку таблицы $PhysicalDrive.Cells.Item(1,1) = 'Модель' $PhysicalDrive.Cells.Item(1,2) = 'Размер (ГБ)' $PhysicalDrive.Cells.Item(1,3) = 'Кол-во разделов' $PhysicalDrive.Cells.Item(1,4) = 'Тип' # Переходим на следующую строку... $Row = 2 $Column = 1 # ... и заполняем данными в цикле по физическим дискам Get-WmiObject Win32_DiskDrive | ForEach-Object ` { # Model $PhysicalDrive.Cells.Item($Row, $Column) = $_.Model $Column++ # Size $PhysicalDrive.Cells.Item($Row, $Column) = ([Math]::Round($_.Size /1GB, 1)) $Column++ # Partitions $PhysicalDrive.Cells.Item($Row, $Column) = $_.Partitions $Column++ # InterfaceType $PhysicalDrive.Cells.Item($Row, $Column) = $_.InterfaceType # Переходим на следующую строку и возвращаемся в первую колонку $Row++ $Column = 1 } # Выделяем жирным шапку $PhysicalDrive.Rows.Item(1).Font.Bold = $true # Выравниваем для того, чтобы их содержимое корректно отображалось в ячейке $UsedRange = $PhysicalDrive.UsedRange $UsedRange.EntireColumn.AutoFit() | Out-Null
Смотрим, что получилось:
Логические диски
Осталось сохранить полученный отчёт и выйти из Excel:
$WorkBook.SaveAs('C:tempReport.xlsx') $Excel.Quit()
На сегодня всё :). В следующих частях мы научимся объединять и раскрашивать ячейки, а также строить диаграммы.