среда, 5 марта 2014 г.

Get-Eventlog Get-LogonHistory.ps1 script

Качественно сделанная сложная задача приносит удовлетворение, вызывает чувство гордости. Это один из мощнейших мотиваторов. Если вы, конечно, внесли в нее значительный вклад.

Скрипт делает удаленную выборку событий журналов Eventlog security на предмет  последних интерактивных входов  пользователей в ОС Windows.
Скрипт решает несколько задач:
  • Автоматическое определение версии  и локализации ОС, Get-Wmi-Object  вследствие выполняются четыре различные функции
  • Ввод компьютеров с консоли пользователя либо опрос файла со списком компьютеров с которых нужно собрать информацию
  • Сбор информации из Eventlog Security за несколько последних дней. История входа пользователей.
  • Сбор данных о пользователях из Active Directory Get-Aduser mail, telephonenumber
  • Вывод требуемой информации в файл формата CSV  для последующей обработке в Excel со столбцами
Скачать мой скрипт можно отсюда:

Спасибо человеку с Github -  Craig Meinschein https://github.com/pfaffle за предоставленную наработку. Его скрипт был взят за основу и дописан мною под требования заказчика.

А задача была следующая:
Определение  для виртуальных Windows-машин неизвестного назначения 5-ти последних профилей пользователей AD, которые регистрировались  в операционной системе. Далее, опираясь на эту информацию, подготовить таблицу следующего содержания:

- Пользователь AD (по профилю);
- Список ОС виртуальных машин, на которых он регистрировался;
- Контакты пользователя из AD (email, телефон)
*** одна строка: 1 пользователь, 1 ВМ на которой он логинился, контакты пользователя в каждой строке. (для последующей сортировки в Excel)

Мне много пришлось потрудиться. Я потратил на скрипт неприличное количество часов и даже купил книжку по powershell. 

Мне очень понравилась задумка с функциями, которые предназначены для разных ОС учитывая разные номера EventID.  Функции выполняются на основе выбора оператором ветвления If() .. else if ().. и определению типа операционной системы Windows Server 2003 или Windows Server  2008.

Коды event ID с выходом Windows Server 2008 изменились. Коды событий взяты из замечательных справочников :

Давайте разберем понятия интерактивных входов в систему консоль entrytype=2 entrytype=10
Следует понимать, где следует собирать информацию о входах. Существует ошибочное мнение тех, кто готовился к экзаменам по сертификации МС, что информацию о входах пользователей надо искать на контроллерах домена. Но там будут только события сетевых входов entrytype=3. Это данные аутентификации пользователя в домене. 
Что мы понимаем под логином пользователя? сетевой вход, обращение к сетевой папке, вход компьютера, запрос билета керберос. Я провел тесты и обнаруживаю, что интересующие нас интерактивные входы контроллер не регистрирует. А значит их следует искать в локальных файлах журналов Eventlog Security куда непосредсвенно входил пользовтель по RDP  entrytype=10 и в консоль entrytype=2 (по нажатию ctrl + alt + delete).

Еntry type=2 — Interactive. Успешный вход пользователя на компьютер.
Entry type=10 — RemoteInteractive. Пользователь выполнил удаленный вход на этот компьютер, используя Terminal Services или Remote Desktop.

Информация по типам входа есть тут:

Более того, события в журнал пишутся на языке локализации ОС. Это значит, что будут разные записи в журнале смысл которых одинаков, а парсинг надо написать для каждого языка свой.
Пример:
"Entry type" = "Тип входа"
Для русской локазизации ОС пришлось написать еще две функции.


Что требовалось написать:

1. Основной запрос

$logons = Get-EventLog Security -AsBaseObject -InstanceId 4624,4647 |
              Where-Object { ($_.InstanceId -eq 4647) `
                        -or (($_.InstanceId -eq 4624) -and ($_.Message -match "Logon Type:\s+2")) `
                        -or (($_.InstanceId -eq 4624) -and ($_.Message -match "Logon Type:\s+10")) }

Переделан в более простой, дело в том что, опрос удаленных компьютеров происходил с подвисанием сессии. Упрощен на вариант:

Get-EventLog Security -computername $_ -AsBaseObject -InstanceId 4624 -after $date |
              Where-Object { ($_.Message -match "Logon Type:\s+2") `
                       -or  ($_.Message -match "Logon Type:\s+10") }

2. Поиск выражений в тексте

 # Determine user.
                if ($event.message -match "New Logon:\s*Security ID:\s*.*\s*Account Name:\s*(\w+)"

Имена без дефисов типа "mdanilov" доставались успешно, а ts-mdanilov читался как "ts-". Пришлось изменить фильтр по регулярным выражениям.

-match "New Logon:\s*Security ID:\s*.*\s*Account Name:\s*(\w+\S\w+\S\w+)" 

3. Добавлен новый фильтр по тексту для определения домена.

 # Determine Account Domain (Определение домена пользователя).
                if ($event.message -match "Account Domain:\s*(\w+\S\w+\S\w+)") {
                    $UserDomain = $matches[1]
                } else {
                    $index = $event.index
                    Write-Warning "Unable to parse Security log Event. Malformed entry? Index: $index"

   4. А это самая важная часть. В тело каждой функции содержит команедлеты для составления таблицы. Добавлен поиск пользователей в AD и вынимание атрибутов для коллекции $user

 # As long as we managed to parse the Event, print output (После разбора лога фомируем наконец вывод).
            if ($user) {
                $aduser = Get-ADuser $user -Properties name, samaccountname, mail,telephonenumber | Select-Object name, samaccountname, mail, telephonenumber
                $timeStamp = Get-Date $event.TimeGenerated
                $output = New-Object -Type PSCustomObject
                Add-Member -MemberType NoteProperty -Name 'TimeStamp' -Value $timeStamp -InputObject $output
                Add-Member -MemberType NoteProperty -Name 'UserName' -Value $user -InputObject $output
                Add-Member -MemberType NoteProperty -Name 'User Domain' -Value $UserDomain -InputObject $output
             Add-Member -MemberType NoteProperty -Name 'ComputerName' -Value $Event.MachineName -InputObject $output
                Add-Member -MemberType NoteProperty -Name 'Action' -Value $action -InputObject $output
                Add-Member -MemberType NoteProperty -Name 'LogonType' -Value $logonType -InputObject $output
                Add-Member -MemberType NoteProperty -Name 'Mail' -Value $aduser.Mail -InputObject $output
         Add-Member -MemberType NoteProperty -Name 'Telephonenumber' -Value $aduser.telephoneNumber -InputObject $output
                Write-Output $output | FT
                $output  | ConvertTo-Html | Add-Content  C:\script\UserProperties.html
             $output | Export-Csv -Append -Path C:\script\getuser.csv -Encoding 'UTF8' -force 
            }       
        }
    } else {
        Write-Host "No recent logon/logoff events ( Не обнаружено свежих записей о событиях входа в журнале )."
    }

5. Вывод информации в файл. Тут я ломал голову долго. Дело в том, что командлет Export-Csv в цикле обработки всегда перезаписывает конечный файл. Информация в нем будет только о последнем пользовтеле вынутом из коллекции $user

Export-Csv -Path C:\script\getuser.csv -Encoding 'UTF8' -force

Правильным решением стало добавить параметр -Append который доступен только в версии Powershell 3.0 Тем самым усложнив требования под среду выполнения. Но зато новые записи просто добавляется в файл, не перезаписывая его.

$output | Export-Csv -Append -Path C:\script\getuser.csv -Encoding 'UTF8' -force

6. Тело самой программы начинается с импорта модуля ActiveDirectory для работы с командлетами AD. Далее операторы ветвления для определения версии ОС и ее локализации. Дальше я работал над составлением четырех функций для требуемых ОС:

·         Windows Server 2003 RUS   Get-Win2003LogonHistory-rus
·         Windows Server 2003 EN     Get-Win2003LogonHistory-en
·         Windows Server 2008 RUS   Get-Win2008LogonHistory-rus
·         Windows Server 2008 EN     Get-Win2008LogonHistory-en

Import-Module ActiveDirectory
$Date = $null
$Day = $null
$Day = Read-Host "Enter count of several last days for parse log ( Введите количество дней за которые надо собрать информацию из лога )"
$Date = (Get-Date).AddDays(-$Day)
$ComputerName = $Null
$ComputerName = Read-Host "Enter computer name for analysis ( Введите имя компьютера для анализа )"
#$ComputerName = (Import-Csv -Path C:\script\computers.csv).name
 $ComputerName | ForEach-Object  {
$OSversion = (Get-WmiObject -computername $_ -Query 'SELECT version FROM Win32_OperatingSystem').version
$OSLanguage = (Get-WmiObject -computername $_ -Query 'SELECT oslanguage FROM Win32_OperatingSystem').oslanguage
if (($OSversion -ge 6) -and ($OSLanguage -eq 1049))
{ "Сбор событий журнала Security на компьютере $_ (Windows 2008 RU)"
    Get-Win2008LogonHistory-rus
} else {
if (($OSversion -ge 6) -and ($OSLanguage -eq 1033)) {
   "Сбор событий журнала Security на компьютере $_ (Windows 2008 EN)"
    Get-Win2008LogonHistory-en
}        elseif  ($OSLanguage -ge 1049) {
    "Сбор событий журнала Security на компьютере $_ (Windows 2003 RU)"
    Get-Win2003LogonHistory-rus
  }
  else {
    "Сбор событий журнала Security на компьютере $_ (Windows 2003 EN)"
    Get-Win2003LogonHistory-en
  }
 }
 }

Полную версию файла скрипта можно скачать тут 


Системные требования
  • Операционная система  – Windows Server 2008 R2
  • Платформа Dot net 4.5.1
  • Подключение к контроллеру домена Windows Server 2008 R2 или к Windows Server 2003 R2 установленной службой AD Gateway Service (AD Web Services)
  • PowerShell 3.0
  • Скрипт содержит Командлеты версии Powershell 3.0. По умолчанию в ОС Windows Server 2008 R2 содержится устаревший компонент Powershell 2.0 с которым данный скрипт будет работать неправильно.   
Подготовка ПО
На компьютере с windows Server 2008 R2 создаем папку C:\script помещаем в нее скрипт Get-logonhistory.ps1
Set-executionpolicy remotesigned



Для подключения к AD в среде контроллеров Windows Server 2003 необходимо поставить службу на сам контроллер домена

Установка ADWS:

Подготовка  к запуску скрипта
Создаем папку C:\script
Все файлы скрипта будут формироваться в этой папке.
! Важно при запуске скрипта от имени другого пользователя, важно указать его в разрешениях на папку C:\script
Открываем скрипт в  Powershell ISE  с правами чтения журналов на удаленных компьютерах в домене.



Вводим имя компьютера




Если нужно обработать список, то комментируем строку и снимаем знак комментария со строки



На вид:




Формирование списка компьютеров (произвольного)
Get-ADComputer -Filter * | select name | Export-Csv C:\script\computers.csv



v
Выполняем скрипт.
Время выполнения скрипта зависит от $day которые мы ввели. Примерно по 1-5 мин на один хост

Пример выполнения












В результате выполнения на выходе получаем два файла, для наглядности сделаны СSV и еще HTML






Задача решена! Вот такой красивый файл у нас получается.







Комментариев нет:

Отправить комментарий