Pull to refresh

Comments 19

Прикольная такая лень, мне нравится. Из предложений: проверять доступность компьютера не по расположению его в соответствующем ou, а по последнему общению с ним (у QAD такая штука есть, гуглится по obsolete computer account) — так несколько надежнее, ибо перемещение — ручная операция :)
А по выводу — интересно все это выгружать сразу в csv, например, для дальнейшего анализа в виде таблицы.
Еще, кстати, можно развернуть powershell на всех машинах групповой политикой и крутить скриптами локально, выкладывая результаты на сетевой диск — тогда точно всем достанется :) единственная проблема — с линухами не катит никак, как, впрочем, и оригинальный скрипт…
Локально то возможно, но с подписыванием скриптов у меня пока дела обстоят худо. Да и парк наших машин оставляет желать лучшего :)
З.Ы. В csv можно все собрать, но понимаешь, либо весь вывод отправлять разом, ибо в export-csv нет волшебной команды -append. Хотя возможно я чего то не знаю :)
Подписывание скриптов лечится политикой.
System center денег стоит. MAPT бесплатен. Про prtg не слыхал. Но вообще такого софта вагон.
ocs inventory, бесплатно, быстро, наглядно.
вот PRTG классная вещь.
Только я сначала прочитал заголовок как «Инвентаризация компьютеров в доме»?
Читаю хабр и понимаю, что у Кэпа был бы тут самый большой рейтинг.
Хоть приложение и старенькое — юзал на предыдущей работе CheckCFG — легко интегрируется в логон скрипты и умеет делать очень много полезных штук. Есть вроде даже скрипты для Линукса…
>>Здесь надо пояснить, что у меня в домене есть папка Disable, где располагаются учетные записи всех отключенных компьютеров. Если они отключены, то какой смысл к ним стучаться. По этому эту папку мы исключаем из поиска.

Тю, есть решение гораздо проще (хоть и строчек кода больше):

=Cut=
function Get-ADComputers ()
{
# $strFilter = "(objectCategory=Computer)"
#get AD computers without disabled accounts
$strFilter = "(&(objectCategory=computer)(!userAccountControl:1.2.840.113556.1.4.803:=2))"

$objDomain = New-Object System.DirectoryServices.DirectoryEntry

$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter

$colProplist = «name»

foreach ($i in $colPropList)
{
$null = $objSearcher.PropertiesToLoad.Add($i)
}

$colResults = $objSearcher.FindAll()
foreach ($objResult in $colResults)
{
$objItem = $objResult.Properties;
[string]$str = $objItem.name
$str
}
}
=ENDCut=

Не требует модуля ActiveDirectory, кстати, а значит и работает в PSv1 (для меня это было критично одно время)

>>Get-WmiObject -computername $a Win32_Processor
Если процессоров больше одного, информация будет дублироваться, для записи в текстовый файл — не критично, при запихивании результатов в таблицу — будут проблемы.
То же относится к памяти, дискам, томам и сетевым картам.

>>Get-WmiObject -computername $a Win32_Physicalmemory
Пропущен параметр MemoryType, для преобразования в читаемый вариант можно прогнать через тупой свитч:
switch( $wmiW32PM[0].MemoryType )
{
0 {$strRAMType = «Unknown»}
1 {$strRAMType = «Other»}
2 {$strRAMType = «DRAM»}
9 {$strRAMType = «RAM»}
17 {$strRAMType = «SDRAM»}
19 {$strRAMType = «RDRAM»}
20 {$strRAMType = «DDR»}
21 {$strRAMType = «DDR-2»}
default {$strRAMType = $_}
} #end switch
(для DDR-3 встречалось как 22 так и 23, адаптировать по месту, некоторые маловерятные я выкинул)

Так же не наблюдаю инвентаризации ОС, через класс Win32_OperatingSystem, в котором есть следующие полезные свойства:
Caption, Version, Description, InstallDate, lastbootuptime, SerialNumber, CSDVersion

Это может выглядеть вот так:
=CUT=

Get-WmiObject Win32_OperatingSystem -computername $a | `
Select-Object Caption, Version, Description, InstallDate, lastbootuptime, SerialNumber, CSDVersion | `
ft @{Label=«Наименование»; Expression={$_.Caption}}, `
@{Label=«Версия ОС»; Expression={$_.Version}}, `
@{Label=«Описание ПК»; Expression={$_.Description}}, `
@{Label=«Дата установки»; Expression={[System.Management.ManagementDateTimeconverter]::ToDateTime($_.InstallDate)}},
@{Label=«Время последнего запуска»; Expression={[System.Management.ManagementDateTimeconverter]::ToDateTime($_.lastbootuptime)}},
@{Label=«Серийный номер ОС»; Expression={($_.SerialNumber)}},
@{Label=«Установленный пакет обновлений»; Expression={($_.CSDVersion)}}

=ENDCUT=

Говоря об инвентаризации ОС полезно воспользоваться следующей функцией и получить ключ продукта установленной ОС:

=CUT=

function Get-WindowsProductKey {
param ($strComputer)

$hklm = 2147483650
$key = «SOFTWARE\Microsoft\Windows NT\CurrentVersion\»
$value = «DigitalProductId»
$wmi2 = "\\"+$strComputer+"\root\default:stdRegProv"
$wmi = [wmiclass]$wmi2
$rpk = ($wmi.GetBinaryValue($hklm,$key,$value)).uValue
if ($rpk)#if rpk present — do math
{
# $rpk = (Get-ItemProperty «HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\» -Name DigitalProductId).DigitalProductId
$i = 28
$rpkOffset = 52
$PossibleChars = «BCDFGHJKMPQRTVWXY2346789»
do {
$Accumulator = 0
$j = 14
do {
$Accumulator = $Accumulator * 256
$Accumulator = $rpk[$j + $rpkOffset] + $Accumulator
$Accumulator / 24 -match "^\d*" | Out-Null
$rpk[$j + $rpkOffset] = $matches[0] -band 255
$Accumulator = $Accumulator % 24
$j--
} while ($j -ge 0)
$i--
$ProductKey = $PossibleChars.Substring($Accumulator, 1) + $ProductKey
if ((29 — $i) % 6 -eq 0 -and $i -ne -1) {
$i--
$ProductKey = "-" + $ProductKey
}
} while ($i -ge 0)
$ProductKey

} # end of if rpk
else
{break}
}

=ENDCut=
(да, код уродский, но лень приводить в порядок)

Таким же образом можно получить версию Internet Explorer установленного в системе:

=Cut=
function Get-InternetExplorerVersionWMI {
param ($strComputer)

$hklm = 2147483650
$key = «SOFTWARE\Microsoft\Internet Explorer\»
$value = «Version»
$wmi2 = "\\"+$strComputer+"\root\default:stdRegProv"
$wmi = [wmiclass]$wmi2
$rpk = ($wmi.GetStringValue($hklm,$key,$value)).sValue
$rpk
}

=ENDCut=

Так же непонятна конструкция
>> $OS=Get-WmiObject -computername $a Win32_OperatingSystem | foreach {$_.caption}

Вполне можно обойтись более элегантым (и чуть более быстрым)
$OS = (Get-WmiObject -computername $a Win32_OperatingSystem).caption

или совсем быстрым
$OS = (get-wmiobject -query «SELECT Caption FROM Win32_OperatingSystem» -computername $a).Caption

Плюс всё это хозяйство можно писать не в отдельные текстовые файлы, а вполне в табличку, которую потом через export-csv выгрузить.
А при желании — через System.Net.WebClient и выгрузить на FTP.
Объяснюсь про Disable. Домен достался мне по наследству, по этому когда я только начинал заниматься дизайном домена, эта папка появился по необходимости собирать там отключенные учетные записи компьютеров. Все таки удобнее держать их всех в одной куче, нежели разбросанными по домену. Да я согласен с Вашим предложением по отсеву отключенных учетных записей. Но, так как лично у меня они лежат все в 1 месте, мне легче было сделать таким образом :)

Что касается разных свойств, будь то процессор, память и тому подобное — я опять же с Вами согласен, но мне в моем задании этой информации было достаточно :)

На счет непонятной конструкции — пути PowerShella неисповедимы :)

Что касается csv файла, не скрою, что сначала хотел выгружать все туда. Но к сожалению до конца с этим не разобрался, и остановился на текстовых файлах. Буду развиваться дальше :)
>>Объяснюсь про Disable
Да не надо было, и так понятно. Тем более в моих подотчётных доменах тоже есть такой OU ;)

>>Что касается разных свойств
Ну я и уточнил, что текстовика этого достаточно.
По поводу выгрузки в табличку — есть тупой вариант чтобы не связываться с CSV:

==CUT==
$computers = «COMP1»,«SERVER2»,«NOTEBOOK3»
$table = @{}

$computers | % `
{
$cpu = «Intel Itanium » + (Get-Random 3000) + «Mhz»
$ram = [string](Get-Random 2048) + «MB RDRAM»
$table[$_] = @{«cpu»=$cpu;«ram»=$ram}
}

$random = Get-Random 2048
$builder = New-Object System.Text.StringBuilder
[void]$builder.AppendLine( «Name;RAM;CPU» )
$computers | % { [void]$builder.AppendLine( $_ + ";" + $table[$_].ram +";"+ $table[$_].cpu ) }

$builder.ToString()
==ENDCUT==

Надеюсь будет понятно куда что.

>>На счет непонятной конструкции — пути PowerShella неисповедимы :)
Просто в Поше много путей, не все они оптимальны ;)
В стародавние времена инвентаризацию деал с помощью Fpinger, у него есть какой-то модуль который достаточно запихать в логон скрипт или через psexec прогнать по всем машинам. На выходе получались такие красивые бумажки с табличками и непонятными буковками, которые так любит руководство.
Sign up to leave a comment.

Articles