Возможна ли Инвентаризация ПО и выгрузка данных в Excel через PowerShell?

За ранее прошу простить, может за глупые вопросы и тупняки, я не волшебник я только учусь....

Смысл в чем, есть парк компов в корпоративном домене. необходимо сделать инвинтаризацию программ на компьтерах, ставить и тем более закупать софт нет возможности. Пришла мысль сделать скрипт на PowerShell который будет дергать информацию с реестра, и закидывать в таблицу. Скрипт раскидать по компам и закинуть результат в папку, после через Excel собрать в кучу. Но столкнулся с парой проблем, так как опыта в PowerShell мало.
1 ) как посмотреть имя компа знаю, но как сохранить файл с именем этого компа так и не разобрался....
2 ) есть 2 скрипта, 1й выводит инфу о ПО на ПК, он более чем устраивает, второй смотрит и записывает инфу о железе. НО вот заставить второй скрипт брать инфу с реестра и писать в файл у меня не вышло.

готовый код не прошу, хотя не отказываюсь, почитаю разберусь думаю =) кидаю оба скрипта в исходном виде, как нашел на форумах. тут скорее пару моментов, как выдернуть инфу с массива и заставить писать в столбец и как переменную писать в имя файла

пробовал писать в таблицу так

# DeviceID
$LogiclDisk.Cells.Item($Row, $Column) = $temp | Select-Object -Property DisplayName
$Column++

# DeviceID
$LogiclDisk.Cells.Item($Row, $Column) = -Massive ( $temp | Select-Object -Property DisplayName)
$Column++

но что то пошло нет так... просьба помидорков много не кидать а хотя бы направить где копать...
  • Вопрос задан
  • 598 просмотров
Пригласить эксперта
Ответы на вопрос 3
@AAT666
1. Таких скриптов полно в сети. Это уже банальная задача. Поиск выдает море информации. Вторым по запросу "Powershell инвентаризация программ" выдается хабровская статья столетней давности - Инвентаризация компьютеров в домене. Лень-двигател... ну и т.д и т.п.

2. Зачем бодаться с COM-объектами Excel ?? Не проще сохранять все в CSV файл и потом делать с ним что угодно ?

3. Зачем раскидывать скрипт по компьютерам, если можно забрать информацию удаленно ?
Ответ написан
@tartarelin
Ну знаете, если не разобраться, как сохранить файл с именем компьютера, то может стоит отказаться от написания своего собственного скрипта, а воспользоваться готовыми решениями?
Ответ написан
@Filkri Автор вопроса
вывод ПО


Write-Output ("`n`t`Приступаю к анализу системы...`n")
Write-Output ("`n`---------------------------------------------------------")

#Объявляем функцию содержащую способ вывода и сорт. по свойству DisplayName.
function Grid-Output

{
param (
<#
Объявляем, что наличие массива элементов указанного ниже для работы
данной функции явлется строго обязательным
#>
[Parameter (Mandatory = $true)]
[Array] $Massive
)

<#
Сортируем вывод по свойству DisplayName, далее указываем формат вывода
GridView
#>
$Massive |sort-object -property DisplayName | Out-GridView
}

<#
Получаем объекты из реестра.

На данном этапе из реестра мы получ. объекты типа:
System.MarshalByRefObject.RegistryKey (Microsoft.Win32.RegistryKey)
Отдельный объект для этих целей был создан потому что:

1.Возможно данный объект, в последующем, необходимо будет изменить.
Скорее всего даже на функцию анализирующую массивы
элементов описанных ниже, формируя единый массив:
1.1: $soft = Get-WmiObject -Class Win32_Product
1.2: $soft32 = gci "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
1.3: $soft64 = gci "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"

В связи с этим мы изолируем его для упрощения последующих модификаций.

2. Улучшает читабельность кода.
#>
[array]$RegUnistValues = Get-ChildItem HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall

<#
Генерируем объекты Automation.PSCustomObject для каждого свойства полученных ранее объектов Win32.RegistryKey
Более подр. информацию по Get-ItemProperty можно почитать тут:
https://technet.microsoft.com/ru-ru/library/hh8498...
#>
[String]$temp = 'Здесь будут временно содержаться значения'
[Array]$temp = $RegUnistValues | ForEach-object {(Get-ItemProperty Microsoft.PowerShell.Core\Registry::$_)}

<#
Создаём запрос на активацию фильтра.
Для этого мы генерируем popup запрос вывод которого записываем в объект $result.

object.Popup(strText,[nSecondsToWait],[strTitle],[nType]) в данном случае имеет следующие параметры:

strText = "Активировать фильтрацию столбцов?" / Текст запроса
nSecondsToWait = 10 / время ожидания ответа от пользователя
strTitle = "Question" / Не обязательное значение. Данная строка будет отображаться в сообщения.
nType = 4+32 / Типы кнопок во всплывающем сообщении. В данном случае :
4 = Сочетание кнопок "Да" и "Нет"
32 = Рисунок знака вопроса в сообщении

Более подробную информацию можно взять тут:
https://msdn.microsoft.com/en-us/library/x83z1d9f(...
#>
$shell = new-object -comobject "WScript.Shell"
$result = $shell.popup("Активировать фильтрацию столбцов?",10,"Question",4+32)

<#
Используем оператор Switch для анализа знчений объект $result
(ВНИМАНИЕ!! использование данного оператору в больших проектах с .Net объектами неприемлимо
и считается дурным тоном, так как сильно затрудняет читабильность кода. Аналогов в данном
случае я, к сожалению, не нашёл)
В данном случае объект $result у нас может иметь 3 варианта:

1. -1 : если в popup окне пользователь не нажал ни одну кнопку, и окно было закрыто по Тайм-Ауту.
2. 6 : если в popup окне пользователь нажал "Да"
3. 7 : если в popup окне пользователь нажал "Нет"

Соответственно, в зависимости от значения $result выполняется сценарий.
P.S.: значение -1 и все остальные возможные значения исключая 6 и 7 у меня перекрывает сценарий: Default.
Сделано на случай если $result вернёт вместо значения ошибку.
#>

Switch ($result) {

6 {
Write-Output ("`n`t`Фильтр активирован.`n")

<#
В данном конкретном случае меня интересовали свойста DisplayName, DIsplayVersion, PSChildName.
Однако никто не запрещает выбрать самостоятельно. Напоминаю, что все доступные свойтсва объекта
можно получить: $тут_будет_указан_объект_свойства_которого_хотим_посмотреть | Get-Member

В это конкретном случае $temp | Get-Member
Далее выбираем из свойств NoteProperty, указываем через запятую после Select-Object -Property.
Выбранные нами свойства будут являться заголовками столбцов при выводе.
#>
#вывод полученных данных с помощью ранее написанной функции Grid-Output
Grid-Output -Massive ($temp | Select-Object -Property DisplayName, DIsplayVersion, PSChildName)

}

7 {
Write-Output ("`n`t`Фильтр отключен.`n")
#вывод полученных данных с помощью ранее написанной функции Grid-Output#
Grid-Output -Massive $temp

}

Default {
Write-Output ("`n`t`Время на подтверждение активации фильтра истекло. Фильтр отключен.`n")
#вывод полученных данных с помощью ранее написанной функции Grid-Output
Grid-Output -Massive $temp

}

}

#Обнуляем значение, дабы не оставлять после себя артефактов со значениями реестра.
[String]$RegUnistValues = 'Здесь содержались значения реестра'
[String]$temp = 'Здесь временно содержались значения'

Write-Output ("`n`t`Запрос успешно обработан.`n")
Write-Output ("`n`---------------------------------------------------------")
Write-Output ("`n`t`Работа скрипта завершена.`n")

<#
Блокируем автоматическое закрытие окна PowerShell после выполнения скрипта. В данном конкретном случае,
мне необходимо было сделать именно таким образом, однако правильнее будет запустить скрипт с ключом:
powershell.exe -NoExit -command c:\myscript.ps1
Ибо вносить для этого отдельные изменения в сценарий не рекомендуется.
#>
$host.ui.RawUI.ReadKey(6)|out-null



запись в файл

# Созадём объект Excel
$Excel = New-Object -ComObject Excel.Application

# Делаем его видимым
$Excel.Visible = $true

# Добавляем рабочую книгу
$WorkBook = $Excel.Workbooks.Add()

$LogiclDisk = $WorkBook.Worksheets.Item(1)

# Переименовываем лист
$LogiclDisk.Name = 'Логические диски'

# Заполняем ячейки - шапку таблицы
$LogiclDisk.Cells.Item(1,1) = 'Буква диска'
$LogiclDisk.Cells.Item(1,2) = 'Метка'
$LogiclDisk.Cells.Item(1,3) = 'Размер (ГБ)'
$LogiclDisk.Cells.Item(1,4) = 'Свободно (ГБ)'

# Выделяем жирным шапку таблицы
$LogiclDisk.Rows.Item(1).Font.Bold = $true

# Выравниваем для того, чтобы их содержимое корректно отображалось в ячейке
$UsedRange = $LogiclDisk.UsedRange
$UsedRange.EntireColumn.AutoFit() | Out-Null

# Переходим на следующую строку...
$Row = 2
$Column = 1

# Добавляем лист
$WorkBook.Worksheets.Add()

# ... и заполняем данными в цикле по логическим разделам
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
}

$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) = 'Тип'

# Выделяем жирным шапку таблицы
$LogiclDisk.Rows.Item(1).Font.Bold = $true

# Выравниваем для того, чтобы их содержимое корректно отображалось в ячейке
$UsedRange = $LogiclDisk.UsedRange
$UsedRange.EntireColumn.AutoFit() | Out-Null

# Переходим на следующую строку...
$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
$WorkBook.SaveAs('C:\temp\Report')
$Excel.Quit()

$compname = (get-wmiobject -class win32_computersystem -namespace root/cimv2).Name
new-item -path . -name "$compname.xls" -type file
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы