В топике будет много кода, который, надеюсь, будет вам полезен.
Первым делом необходимо было определить список событий, которые необходимо было отслеживать. Чтобы уменьшить количество текста, я создала процедуру, которая по ID события выдает ее описание:
Function DefineReason ($Id){
switch ($Id){
4741{ Return "Создана учетна запись компьютера"}
4742{ Return "Изменена учетна запись компьютера" }
4743{ Return "Удалена учетная запись компьютера"}
4727{ Return "Создана глобальная группа с включенной безопасностью"}
4728{ Return "Добавлен пользователь к глобальной группе с включенной безопасностью"}
4729{ Return "Удален пользователь из глобальной группы с включенной безопасностью"}
4730{ Return "Удалена глобальная группа с включенной безопасностью"}
4731{ Return "Создана локальная группа с включенной безопасностью"}
4732{ Return "Добавлен пользователь в локальную группу с включенной безопасностью"}
4733{ Return "Удален пользователь из локальной группы с включенной безопасностью"}
4734{ Return "Удалена локальная группа с включенной безопасностью"}
4735{ Return "Изменена локальная группа с включенной безопасностью"}
4737{ Return "Изменена глобальная группа с включенной безопасностью"}
4743{ Return "Удалена учетная запись компьютера"}
4754{ Return "Создана универсальная группа с включенной безопасностью" }
4755{ Return "Изменена универсальная группа с включенной безопасностью"}
4756{ Return "Добавлен пользователь к универсальной группе с включенной безопасностью"}
4757{ Return "Удален пользователь из универсальной группы с включенной безопасностью"}
4758{ Return "Удалена универсальная группа с включенной безопасностью"}
4764{ Return "Изменен тип группы"}
4720{ Return "Создана учетна запись"}
4722{ Return "Включена учетна запись"}
4724{ Return "Сброс пароля пользователя"}
4725{ Return "Учетна запись пользователя отключена"}
4726{ Return "Учетна запись пользователя удалена"}
4738{ Return "Изменена учетна запись"}
4740{ Return "Учетна запись пользователя заблокирована"}
4767{ Return "Учетна запись пользователя разблокирована"}
4780{ Return "Список управления Доступом был установлен на учетные записи, которые являются членами группы администраторов"}
4781{ Return "Было изменено имя учетной записи"}
4794{ Return "Была предпринята попытка задать режим восстановления служб каталогов"}
5376{ Return "Диспетчер учетных данных: учетные данные были сохранены"}
5377{ Return "Диспетчер учетных данных: учетные данные были востановлены из резервной копии"}
4825{ Return "Запрeщен доступ к удаленному рабочемо столу, не входит в группу RDP"}
1102{ Return "Удален журнал Security"}
}
}
Затем понадобилось описать события, которые отслеживаются по маске доступа:
# Функция определения описания события по маске доступа
Function DefineReasonByAccessMask ($AccessMask){
switch($AccessMask){
"0xc0000064" { Return "Имя пользователя не существует" }
"0xc000006A" { Return "Верное имя, но не правильный пароль"}
"0xc0000234" { Return "Пользователь заблокирован" }
"0xc0000072" { Return "Учетка деактивирована"}
"0xc0000006F" { Return "Вход вне рабочее время"}
"0xc00000070" { Return "Ограничение локальной станции"}
"0xc00000193" { Return "Срок действия учетной записи истек"}
"0xc00000071" { Return "Срок действия пароля Истек"}
"0xc00000224" { Return "Необходимо сменить пароль при следующем входе"}
"0xc000015b" { Return "Пользователю запрещен вход на этой машине"}
"0xc000006d" { Return "Неверный пароль"}
}
}
Теперь мы знаем, за чем хотим следить. Следующий шаг при разработке скрипта по аудиту — это получение журнала безопасности в формате XML, так как если событий много, то построчная обработка занимает достаточно большое количество времени.
Чтобы получить события из журнала можно использовать одну из команд, в каждой из которых есть свои преимущества и недостатки:
1. Get-LogEvent security
Преимущества:
— быстрый доступ к свойствам события;
— не нужна предварительная обработка для доступа к свойствам события.
Недостатки:
— доступ только с системному журналу безопасности, который хранится по пути: Windows/System32/winevt/security.evtx;
— долгая обработка содержимого тега . Обработка происходит путем построчной сепарации с ликвидацией спецсимволов.
2. Get-WinEvent –path “D:/”
Преимущества:
— быстрая обработка журнала;
— доступ к любому журналу. Главное прописать полный путь.
Недостатки:
— для обработки полученного журнала требуется предварительная обработка.
Try {
$Events = Get-WinEvent -FilterHashTable $MyFilter
} Catch {"No events were found in $Log"; Continue}
ForEach ($Raw_Event in $Events)
{
Try{
$EventXML = [xml]$Raw_Event.ToXML()
} Catch {Write-Host "Unable to convert an event to XML"}
$Event = @{}
ForEach ($object in $EventXML.Event.EventData.Data) {
$Event.Add($object.name,$object.'#text')
}
$Event.Add("ID",$Raw_Event.ID)
$Event.Add("TimeCreated",$Raw_Event.TimeCreated)
Следующий шаг после того как мы получили доступ к журналу, это вытягивать из журнала требуемые события и принимать по ним соответствующие решения. В большинстве случаев – это отправка информационного сообщения на почту или логирование в отдельный файл.
Задать параметры, по которым будем вытягивать информацию, возможно, используя интерфейсное решения. Диалоговое окно с вводом параметров.
1. Первый параметр предполагает, что журналы периодически экспортируются в определенный каталог, который и следует задать. Если журнал один, то задается стандартный каталог для хранения журналов: «C:\Windows\System32\winevt\Logs».
2. Второй параметр определяет сервер, по которому будет искаться логи. Если сервер один, то ставим «*».
3. Третий параметр предельно понятен: * — ищем события за весь период, если задана дата, например, 30.11.2015, то ищем за эту дату. Поиск за период осуществляется вводом начальной и конечной даты через тире (01.11.2015-30.11.2015).
4. Указываем путь для сохранения результата работы, например, «D:\log.log». Ниже приведен код, позволяющий построить интерфейс для скрипта:
$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "Ввод исходных данных"
$objForm.Size = New-Object System.Drawing.Size(300,450)
$objForm.StartPosition = "CenterScreen"
# Events path
$objLabel1 = New-Object System.Windows.Forms.Label
$objLabel1.Location = New-Object System.Drawing.Size(10,20)
$objLabel1.Size = New-Object System.Drawing.Size(280,40)
$objLabel1.Text = "Введите полный путь к журналам в формате`nD:/.../.../ :"
$objForm.Controls.Add($objLabel1)
$objTextBox1 = New-Object System.Windows.Forms.TextBox
$objTextBox1.Location = New-Object System.Drawing.Size(10,60)
$objTextBox1.Size = New-Object System.Drawing.Size(280,20)
$objForm.Controls.Add($objTextBox1)
#Find Server mode
$objLabel2 = New-Object System.Windows.Forms.Label
$objLabel2.Location = New-Object System.Drawing.Size(10,90)
$objLabel2.Size = New-Object System.Drawing.Size(280,30)
$objLabel2.Text = "1. * - по всем серверам.`n2. Укажите Сервер."
$objForm.Controls.Add($objLabel2)
$objTextBox2 = New-Object System.Windows.Forms.TextBox
$objTextBox2.Location = New-Object System.Drawing.Size(10,120)
$objTextBox2.Size = New-Object System.Drawing.Size(280,30)
$objForm.Controls.Add($objTextBox2)
#Type Events Mode
$objLabel3 = New-Object System.Windows.Forms.Label
$objLabel3.Location = New-Object System.Drawing.Size(10,150)
$objLabel3.Size = New-Object System.Drawing.Size(280,45)
$objLabel3.Text = "1. * - по всем событиям.`n2. Укажите событие.`n3. Перечислите через запятую события"
$objForm.Controls.Add($objLabel3)
$objTextBox3 = New-Object System.Windows.Forms.TextBox
$objTextBox3.Location = New-Object System.Drawing.Size(10,195)
$objTextBox3.Size = New-Object System.Drawing.Size(280,30)
$objForm.Controls.Add($objTextBox3)
#Date Events mode
$objLabel4 = New-Object System.Windows.Forms.Label
$objLabel4.Location = New-Object System.Drawing.Size(10,225)
$objLabel4.Size = New-Object System.Drawing.Size(280,60)
$objLabel4.Text = "1. * - за весь период.`n2. Укажите дату в формате ДД.ММ.ГГГГ.`n3. Укажите интервал в формате ДД.ММ.ГГГГ-ДД.ММ.ГГГГ"
$objForm.Controls.Add($objLabel4)
$objTextBox4 = New-Object System.Windows.Forms.TextBox
$objTextBox4.Location = New-Object System.Drawing.Size(10,285)
$objTextBox4.Size = New-Object System.Drawing.Size(280,30)
$objForm.Controls.Add($objTextBox4)
#Save Result
$objLabel5 = New-Object System.Windows.Forms.Label
$objLabel5.Location = New-Object System.Drawing.Size(10,315)
$objLabel5.Size = New-Object System.Drawing.Size(280,30)
$objLabel5.Text = "Путь для сохранения результата поиска"
$objForm.Controls.Add($objLabel5)
$objTextBox5 = New-Object System.Windows.Forms.TextBox
$objTextBox5.Location = New-Object System.Drawing.Size(10,345)
$objTextBox5.Size = New-Object System.Drawing.Size(280,30)
$objForm.Controls.Add($objTextBox5)
# Кнопки ОК и Отмена. Обработчки добавлен только на нажатие кнопки ОК.
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(75,380)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.Add_Click({$objForm.Close()})
$objForm.Controls.Add($OKButton)
$OKButton.DialogResult=[System.Windows.Forms.DialogResult]::OK
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(150,380)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
$CancelButton.Add_Click({$objForm.Close()})
$objForm.Controls.Add($CancelButton)
$objForm.Topmost = $True
$objForm.Add_Shown({$objForm.Activate()})
$dialogResult = $objForm.ShowDialog()
# Описание интерфейса закончено
Получаем введенные данные:
# Определяем входящие параметры
if ($dialogResult -eq "OK"){
$Log_Path = $objTextBox1.Text
$FindServerMode = $objTextBox2.Text
$TypeEventsMode = $objTextBox3.Text
$DateEventsmode = $objTextBox4.Text
$SaveResult = $objTextBox5.Text
}
Если в поле дата есть символ "-", значит введен интервал, если этот символ введен ошибочно — ваши проблемы. Проводим сепарацию по символу "-", определяем начальную и конечную дату диапазона.
if ($DateEventsmode -match "-"){
$x = $DateEventsmode.split("-")
$StartDate = $x[0]
$EndDate = $x[1]
$StartDate = [DateTime]::parse($StartDate)
$StartDate
$EndDate = [DateTime]::parse($EndDate)
$EndDate
}
Если во введенном поле нет ни "-", ни "*", то значит введена конкретная дата.
if ($DateEventsmode -notmatch "-" -and $DateEventsmode -ne "*"){
$StartDate1 = [DateTime]::parse($DateEventsmode)
}
1. Поиск по всем серверам, по всем событиям, за весь период:
if ($FindServerMode -eq "*" -and $DateEventsmode -eq "*" -and $TypeEventsMode -eq "*" -and $Log_Path -ne ""){
Write-host "вошли в 1"
$ALL_LOGS = Get-ChildItem -Path $Log_Path -recurse| Where {$_.Extension -eq ".evtx"} | Sort LastWriteTime
$ALL_LOGS
foreach ($Log in $ALL_LOGS){
$LogFile = "Audit EventLog Security" +"`n"
($Log).FullName
$MyFilter = @{Path=($Log).FullName}
$i=0
Try {$Events = Get-WinEvent -FilterHashTable $MyFilter} Catch {"No events were found in $Log"; Continue}
ForEach ($Raw_Event in $Events){
Try{$EventXML = [xml]$Raw_Event.ToXML()} Catch {Write-Host "Unable to convert an event to XML"}
$Event = @{}
ForEach ($object in $EventXML.Event.EventData.Data) {
$Event.Add($object.name,$object.'#text')
}
$Event.Add("ID",$Raw_Event.ID)
$Event.Add("TimeCreated",$Raw_Event.TimeCreated)
$LogFile+= "EventID: " + $Raw_Event.ID +"`n"
$LogFile+= "Target User Name: " + $Event.TargetUserName +"`n"
$LogFile+= "Target Domain Name: " + $Event.TargetDomainName +"`n"
$LogFile+= "Status: " + $Event.Status +"`n"
$LogFile+= "TimeGenerated: " + $Event.TimeCreated +"`n"
$LogFile+= "Workstation Name: " + $Event.WorkstationName +"`n"
$LogFile+= "IpAddress: " + $Event.IpAddress +"`n"
$LogFile+= "Computer: " + [xml]$Raw_Event.ToXML().Event.System.Computer +"`n"
$Reason = DefineReason -Id $Raw_Event.ID
$AccessM = DefineReasonByAccessMask -AccessMask $Event.Status
$LogFile+= "Reason(RU): " + $Reason + " "+ $AccessM +"`n"
$LogFile+= "Reason(SYS): " + $Event.Message +"`n"
$LogFile+= "----------------------------------------------------------------`n"
$i++
}
}
}
2. Поиск по всем серверам, по фильтру событий, за весь период:
if ($FindServerMode -eq "*" -and $DateEventsmode -eq "*" -and $TypeEventsMode -ne "*" -and $Log_Path -ne ""){
Write-host "вошли в 2"
$ALL_LOGS = Get-ChildItem -Path $Log_Path | Where {$_.Extension -eq ".evtx"} | Sort LastWriteTime
$ALL_LOGS
foreach ($Log in $ALL_LOGS){
$LogFile = "Audit EventLog Security" +"`n"
($Log).FullName
$MyFilter = @{Path=($Log).FullName;ID=$TypeEventsMode}
Try {$Events = Get-WinEvent -FilterHashTable $MyFilter} Catch {"No events were found in $Log"; Continue}
ForEach ($Raw_Event in $Events){
Try{$EventXML = [xml]$Raw_Event.ToXML()} Catch {Write-Host "Unable to convert an event to XML"}
$Event = @{}
ForEach ($object in $EventXML.Event.EventData.Data) {
$Event.Add($object.name,$object.'#text')
}
$Event.Add("ID",$Raw_Event.ID)
$Event.Add("TimeCreated",$Raw_Event.TimeCreated)
$LogFile+= "EventID: " + $Event.ID +"`n"
$LogFile+= "Target User Name: " + $Event.TargetUserName +"`n"
$LogFile+= "Target Domain Name: " + $Event.TargetDomainName +"`n"
$LogFile+= "Status: " + $Event.Status +"`n"
$LogFile+= "TimeGenerated: " + $Event.TimeCreated +"`n"
$LogFile+= "Workstation Name: " + $Event.WorkstationName +"`n"
$LogFile+= "IpAddress: " + $Event.IpAddress +"`n"
$LogFile+= "Computer: " + [xml]$Raw_Event.ToXML().Event.System.Computer +"`n"
$Reason = DefineReason -Id $Raw_Event.ID
$AccessM = DefineReasonByAccessMask -AccessMask $Event.Status
$LogFile+= "Reason(RU): " + $Reason + " "+ $AccessM +"`n"
$LogFile+= "Reason(SYS): " + $Event.Message +"`n"
$LogFile+= "----------------------------------------------------------------`n"
}
}
}
3. Поиск по всем серверам, по всем событиям, за диапазон:
if ($FindServerMode -eq "*" -and $DateEventsmode -match "-" -and $TypeEventsMode -eq "*" -and $Log_Path -ne ""){
Write-host "вошли в 3"
$ALL_LOGS = Get-ChildItem -Path $Log_Path -Recurse| Where {$_.Extension -eq ".evtx" } | Sort LastWriteTime
$ALL_LOGS
foreach ($Log in $ALL_LOGS){
$LogFile = "Audit EventLog Security" +"`n"
($Log).FullName
$StartDate
$EndDate
$MyFilter = @{Path=($Log).FullName}
Try {$Events = Get-WinEvent -FilterHashTable $MyFilter} Catch {"No events were found in $Log"; Continue}
ForEach ($Raw_Event in $Events){
Try{$EventXML = [xml]$Raw_Event.ToXML()} Catch {Write-Host "Unable to convert an event to XML"}
$Event = @{}
ForEach ($object in $EventXML.Event.EventData.Data) {
$Event.Add($object.name,$object.'#text')
}
$Event.Add("ID",$Raw_Event.ID)
$Event.Add("TimeCreated",$Raw_Event.TimeCreated)
$Event.TimeCreated
if ($Event.TimeCreated -gt $StartDate -and $Event.TimeCreated -lt $EndDate){
$LogFile+= "EventID: " + $Raw_Event.ID +"`n"
$LogFile+= "Target User Name: " + $Event.TargetUserName +"`n"
$LogFile+= "Target Domain Name: " + $Event.TargetDomainName +"`n"
$LogFile+= "Status: " + $Event.Status +"`n"
$LogFile+= "TimeGenerated: " + $Event.TimeCreated +"`n"
$LogFile+= "Workstation Name: " + $Event.WorkstationName +"`n"
$LogFile+= "IpAddress: " + $Event.IpAddress +"`n"
$LogFile+= "Computer: " + [xml]$Raw_Event.ToXML().Event.System.Computer +"`n"
$Reason = DefineReason -Id $Raw_Event.ID
$AccessM = DefineReasonByAccessMask -AccessMask $Event.Status
$LogFile+= "Reason(RU): " + $Reason + " "+ $AccessM +"`n"
$LogFile+= "Reason(SYS): " + $Event.Message +"`n"
$LogFile+= "----------------------------------------------------------------`n"
}
}
}
}
4. Поиск по всем серверам, по всем событиям, за определенную дату:
if ($FindServerMode -eq "*" -and $DateEventsmode -notmatch "-" -and $DateEventsmode -ne "*" -and $TypeEventsMode -eq "*" -and $Log_Path -ne ""){
Write-host "вошли в 5"
$ALL_LOGS = Get-ChildItem -Path $Log_Path -Recurse| Where {$_.Extension -eq ".evtx" -and $StartDate1 -ne "null" } | Sort LastWriteTime
$ALL_LOGS
foreach ($Log in $ALL_LOGS){
$LogFile = "Audit EventLog Security" +"`n"
($Log).FullName
$Log.LastWriteTime
$StartDate
$EndDate
$MyFilter = @{Path=($Log).FullName}
Try {$Events = Get-WinEvent -FilterHashTable $MyFilter} Catch {"No events were found in $Log"; Continue}
ForEach ($Raw_Event in $Events){
Try{$EventXML = [xml]$Raw_Event.ToXML()} Catch {Write-Host "Unable to convert an event to XML"}
$Event = @{}
ForEach ($object in $EventXML.Event.EventData.Data) {
$Event.Add($object.name,$object.'#text')
}
$Event.Add("ID",$Raw_Event.ID)
$Event.Add("TimeCreated",$Raw_Event.TimeCreated)
if ($Event.TimeCreated.Day -eq $StartDate1.Day -and $Event.TimeCreated.Month -eq $StartDate1.Month -and $Event.TimeCreated.Year -eq $StartDate1.Year){
$LogFile+= "EventID: " + $Raw_Event.ID +"`n"
$LogFile+= "Target User Name: " + $Event.TargetUserName +"`n"
$LogFile+= "Target Domain Name: " + $Event.TargetDomainName +"`n"
$LogFile+= "Status: " + $Event.Status +"`n"
$LogFile+= "TimeGenerated: " + $Event.TimeCreated +"`n"
$LogFile+= "Workstation Name: " + $Event.WorkstationName +"`n"
$LogFile+= "IpAddress: " + $Event.IpAddress +"`n"
$LogFile+= "Computer: " + [xml]$Raw_Event.ToXML().Event.System.Computer +"`n"
$Reason = DefineReason -Id $Raw_Event.ID
$AccessM = DefineReasonByAccessMask -AccessMask $Event.Status
$LogFile+= "Reason(RU): " + $Reason + " "+ $AccessM +"`n"
$LogFile+= "Reason(SYS): " + $Event.Message +"`n"
$LogFile+= "----------------------------------------------------------------`n"
}
}
}
}
5. Поиск по всем серверам, по фильтру событий, за определенный период:
if ($FindServerMode -eq "*" -and $DateEventsmode -match "-" -and $DateEventsmode -ne "*" -and $TypeEventsMode -ne "*" -and $Log_Path -ne ""){
Write-host "вошли в 4"
$ALL_LOGS = Get-ChildItem -Path $Log_Path -Recurse| Where {$_.Extension -eq ".evtx" -and $StartDate1 -ne ""} | Sort LastWriteTime
$ALL_LOGS
foreach ($Log in $ALL_LOGS){
$LogFile = "Audit EventLog Security" +"`n"
($Log).FullName
$Log.LastWriteTime
$StartDate
$EndDate
$MyFilter = @{Path=($Log).FullName;ID=$TypeEventsMode}
Try {$Events = Get-WinEvent -FilterHashTable $MyFilter} Catch {"No events were found in $Log"; Continue}
ForEach ($Raw_Event in $Events){
Try{$EventXML = [xml]$Raw_Event.ToXML()} Catch {Write-Host "Unable to convert an event to XML"}
$Event = @{}
ForEach ($object in $EventXML.Event.EventData.Data) {
$Event.Add($object.name,$object.'#text')
}
$Event.Add("ID",$Raw_Event.ID)
$Event.Add("TimeCreated",$Raw_Event.TimeCreated)
if ($Event.TimeCreated.Day -eq $StartDate1.Day -and $Event.TimeCreated.Month -eq $StartDate1.Month -and $Event.TimeCreated.Year -eq $StartDate1.Year){
$LogFile+= "EventID: " + $Raw_Event.ID +"`n"
$LogFile+= "Target User Name: " + $Event.TargetUserName +"`n"
$LogFile+= "Target Domain Name: " + $Event.TargetDomainName +"`n"
$LogFile+= "Status: " + $Event.Status +"`n"
$LogFile+= "TimeGenerated: " + $Event.TimeCreated +"`n"
$LogFile+= "Workstation Name: " + $Event.WorkstationName +"`n"
$LogFile+= "IpAddress: " + $Event.IpAddress +"`n"
$LogFile+= "Computer: " + [xml]$Raw_Event.ToXML().Event.System.Computer +"`n"
$Reason = DefineReason -Id $Raw_Event.ID
$AccessM = DefineReasonByAccessMask -AccessMask $Event.Status
$LogFile+= "Reason(RU): " + $Reason + " "+ $AccessM +"`n"
$LogFile+= "Reason(SYS): " + $Event.Message +"`n"
$LogFile+= "----------------------------------------------------------------`n"
}
}
}
}
6. Поиск по всем серверам, по фильтру событий, за определенную дату:
if ($FindServerMode -eq "*" -and $TypeEventsMode -ne "*" -and $DateEventsmode -notmatch "-" -and $DateEventsmode -ne "*" -and $Log_Path -ne "") {
Write-host "вошли в 6"
$ALL_LOGS = Get-ChildItem -Path $Log_Path -Recurse| Where {$_.Extension -eq ".evtx" -and $StartDate1 -ne "" } | Sort LastWriteTime
$ALL_LOGS
foreach ($Log in $ALL_LOGS){
$LogFile = "Audit EventLog Security" +"`n"
($Log).FullName
$Log.LastWriteTime
$StartDate
$EndDate
$MyFilter = @{Path=($Log).FullName;ID=$TypeEventsMode}
Try {$Events = Get-WinEvent -FilterHashTable $MyFilter} Catch {"No events were found in $Log"; Continue}
ForEach ($Raw_Event in $Events){
Try{$EventXML = [xml]$Raw_Event.ToXML()} Catch {Write-Host "Unable to convert an event to XML"}
$Event = @{}
ForEach ($object in $EventXML.Event.EventData.Data) {
$Event.Add($object.name,$object.'#text')
}
$Event.Add("ID",$Raw_Event.ID)
$Event.Add("TimeCreated",$Raw_Event.TimeCreated)
if ($Event.TimeCreated.Day -eq $StartDate1.Day -and $Event.TimeCreated.Month -eq $StartDate1.Month -and $Event.TimeCreated.Year -eq $StartDate1.Year){
$LogFile+= "EventID: " + $Raw_Event.ID +"`n"
$LogFile+= "Target User Name: " + $Event.TargetUserName +"`n"
$LogFile+= "Target Domain Name: " + $Event.TargetDomainName +"`n"
$LogFile+= "Status: " + $Event.Status +"`n"
$LogFile+= "TimeGenerated: " + $Event.TimeCreated +"`n"
$LogFile+= "Workstation Name: " + $Event.WorkstationName +"`n"
$LogFile+= "IpAddress: " + $Event.IpAddress +"`n"
$LogFile+= "Computer: " + [xml]$Raw_Event.ToXML().Event.System.Computer +"`n"
$Reason = DefineReason -Id $Raw_Event.ID
$AccessM = DefineReasonByAccessMask -AccessMask $Event.Status
$LogFile+= "Reason(RU): " + $Reason + " "+ $AccessM +"`n"
$LogFile+= "Reason(SYS): " + $Event.Message +"`n"
$LogFile+= "----------------------------------------------------------------`n"
}
}
}
}
7. Поиск на определенном, сервере поиск по всем событиям, за весь период:
if ($FindServerMode -ne "*" -and $DateEventsmode -eq "*" -and $TypeEventsMode -eq "*" -and $Log_Path -ne ""){
Write-host "вошли в 7"
$ALL_LOGS = Get-ChildItem -Path $Log_Path -Recurse| Where {$_.Extension -eq ".evtx" -and $_.FullName -match $FindServerMode} | Sort LastWriteTime
$ALL_LOGS
foreach ($Log in $ALL_LOGS){
$LogFile = "Audit EventLog Security" +"`n"
($Log).FullName
$MyFilter = @{Path=($Log).FullName}
Try {$Events = Get-WinEvent -FilterHashTable $MyFilter} Catch {"No events were found in $Log"; Continue}
ForEach ($Raw_Event in $Events){
Try{$EventXML = [xml]$Raw_Event.ToXML()} Catch {Write-Host "Unable to convert an event to XML"}
$Event = @{}
ForEach ($object in $EventXML.Event.EventData.Data) {
$Event.Add($object.name,$object.'#text')
}
$Event.Add("ID",$Raw_Event.ID)
$Event.Add("TimeCreated",$Raw_Event.TimeCreated)
$LogFile+= "EventID: " + $Raw_Event.ID +"`n"
$LogFile+= "Target User Name: " + $Event.TargetUserName +"`n"
$LogFile+= "Target Domain Name: " + $Event.TargetDomainName +"`n"
$LogFile+= "Status: " + $Event.Status +"`n"
$LogFile+= "TimeGenerated: " + $Event.TimeCreated +"`n"
$LogFile+= "Workstation Name: " + $Event.WorkstationName +"`n"
$LogFile+= "IpAddress: " + $Event.IpAddress +"`n"
$LogFile+= "Computer: " + [xml]$Raw_Event.ToXML().Event.System.Computer +"`n"
$Reason = DefineReason -Id $Raw_Event.ID
$AccessM = DefineReasonByAccessMask -AccessMask $Event.Status
$LogFile+= "Reason(RU): " + $Reason + " "+ $AccessM +"`n"
$LogFile+= "Reason(SYS): " + $Event.Message +"`n"
$LogFile+= "----------------------------------------------------------------`n"
}
}
}
8. Поиск на определенном сервере, по фильтру событий, за весь период:
if ($FindServerMode -ne "*" -and $DateEventsmode -eq "*" -and $TypeEventsMode -ne "*" -and $Log_Path -ne ""){
Write-host "вошли в 8"
$ALL_LOGS = Get-ChildItem -Path $Log_Path -Recurse| Where {$_.Extension -eq ".evtx" -and $_.FullName -match $FindServerMode} | Sort LastWriteTime
$ALL_LOGS
foreach ($Log in $ALL_LOGS){
$LogFile = "Audit EventLog Security" +"`n"
($Log).FullName
$MyFilter = @{Path=($Log).FullName;ID=$TypeEventsMode}
Try {$Events = Get-WinEvent -FilterHashTable $MyFilter} Catch {"No events were found in $Log"; Continue}
ForEach ($Raw_Event in $Events){
Try{$EventXML = [xml]$Raw_Event.ToXML()} Catch {Write-Host "Unable to convert an event to XML"}
$Event = @{}
ForEach ($object in $EventXML.Event.EventData.Data) {
$Event.Add($object.name,$object.'#text')
}
$Event.Add("ID",$Raw_Event.ID)
$Event.Add("TimeCreated",$Raw_Event.TimeCreated)
$LogFile+= "EventID: " + $Event.ID +"`n"
$LogFile+= "Target User Name: " + $Event.TargetUserName +"`n"
$LogFile+= "Target Domain Name: " + $Event.TargetDomainName +"`n"
$LogFile+= "Status: " + $Event.Status +"`n"
$LogFile+= "TimeGenerated: " + $Event.TimeCreated +"`n"
$LogFile+= "Workstation Name: " + $Event.WorkstationName +"`n"
$LogFile+= "IpAddress: " + $Event.IpAddress +"`n"
$LogFile+= "Computer: " + [xml]$Raw_Event.ToXML().Event.System.Computer +"`n"
$Reason = DefineReason -Id $Raw_Event.ID
$AccessM = DefineReasonByAccessMask -AccessMask $Event.Status
$LogFile+= "Reason(RU): " + $Reason + " "+ $AccessM +"`n"
$LogFile+= "Reason(SYS): " + $Event.Message +"`n"
$LogFile+= "----------------------------------------------------------------`n"
}
}
}
9. Поиск на конкретном сервере, по всем событиям, за период:
if ($FindServerMode -ne "*"-and $DateEventsmode -match "-" -and $TypeEventsMode -eq "*" -and $Log_Path -ne ""){
Write-host "вошли в 9"
$ALL_LOGS = Get-ChildItem -Path $Log_Path -Recurse| Where {$_.Extension -eq ".evtx" -and $_.FullName -match $FindServerMode -and $StartDate -ne "null" -and $EndDate -ne "null"} | Sort LastWriteTime
$ALL_LOGS
foreach ($Log in $ALL_LOGS){
$LogFile = "Audit EventLog Security" +"`n"
($Log).FullName
$Log.LastWriteTime
$StartDate
$EndDate
$MyFilter = @{Path=($Log).FullName}
Try {$Events = Get-WinEvent -FilterHashTable $MyFilter} Catch {"No events were found in $Log"; Continue}
ForEach ($Raw_Event in $Events){
Try{$EventXML = [xml]$Raw_Event.ToXML()} Catch {Write-Host "Unable to convert an event to XML"}
$Event = @{}
ForEach ($object in $EventXML.Event.EventData.Data) {
$Event.Add($object.name,$object.'#text')
}
$Event.Add("ID",$Raw_Event.ID)
$Event.Add("TimeCreated",$Raw_Event.TimeCreated)
if ($Event.TimeCreated -gt $StartDate -and $Event.TimeCreated -lt $EndDate){
$LogFile+= "EventID: " + $Raw_Event.ID +"`n"
$LogFile+= "Target User Name: " + $Event.TargetUserName +"`n"
$LogFile+= "Target Domain Name: " + $Event.TargetDomainName +"`n"
$LogFile+= "Status: " + $Event.Status +"`n"
$LogFile+= "TimeGenerated: " + $Event.TimeCreated +"`n"
$LogFile+= "Workstation Name: " + $Event.WorkstationName +"`n"
$LogFile+= "IpAddress: " + $Event.IpAddress +"`n"
$LogFile+= "Computer: " + [xml]$Raw_Event.ToXML().Event.System.Computer +"`n"
$Reason = DefineReason -Id $Raw_Event.ID
$AccessM = DefineReasonByAccessMask -AccessMask $Event.Status
$LogFile+= "Reason(RU): " + $Reason + " "+ $AccessM +"`n"
$LogFile+= "Reason(SYS): " + $Event.Message +"`n"
$LogFile+= "----------------------------------------------------------------`n"
}
}
}
}
10. Поиск на конкретном сервере, по фильтру событий, за период:
if ($FindServerMode -ne "*" -and $DateEventsmode -match "-" -and $DateEventsmode -ne "*" -and $TypeEventsMode -ne "*" -and $Log_Path -ne ""){
Write-host "вошли в 10"
$ALL_LOGS = Get-ChildItem -Path $Log_Path | Where {$_.Extension -eq ".evtx" -and $_.FullName -match $FindServerMode -and $StartDate -ne "null" -and $EndDate -ne "null"} | Sort LastWriteTime
$ALL_LOGS
foreach ($Log in $ALL_LOGS){
$LogFile = "Audit EventLog Security" +"`n"
($Log).FullName
$Log.LastWriteTime
$StartDate
$EndDate
$MyFilter = @{Path=($Log).FullName;ID=$TypeEventsMode}
Try {$Events = Get-WinEvent -FilterHashTable $MyFilter} Catch {"No events were found in $Log"; Continue}
ForEach ($Raw_Event in $Events){
Try{$EventXML = [xml]$Raw_Event.ToXML()} Catch {Write-Host "Unable to convert an event to XML"}
$Event = @{}
ForEach ($object in $EventXML.Event.EventData.Data) {
$Event.Add($object.name,$object.'#text')
}
$Event.Add("ID",$Raw_Event.ID)
$Event.Add("TimeCreated",$Raw_Event.TimeCreated)
if ($Event.TimeCreated -gt $StartDate -and $Event.TimeCreated -lt $EndDate){
$LogFile+= "EventID: " + $Raw_Event.ID +"`n"
$LogFile+= "Target User Name: " + $Event.TargetUserName +"`n"
$LogFile+= "Target Domain Name: " + $Event.TargetDomainName +"`n"
$LogFile+= "Status: " + $Event.Status +"`n"
$LogFile+= "TimeGenerated: " + $Event.TimeCreated +"`n"
$LogFile+= "Workstation Name: " + $Event.WorkstationName +"`n"
$LogFile+= "IpAddress: " + $Event.IpAddress +"`n"
$LogFile+= "Computer: " + [xml]$Raw_Event.ToXML().Event.System.Computer +"`n"
$Reason = DefineReason -Id $Raw_Event.ID
$AccessM = DefineReasonByAccessMask -AccessMask $Event.Status
$LogFile+= "Reason(RU): " + $Reason + " "+ $AccessM +"`n"
$LogFile+= "Reason(SYS): " + $Event.Message +"`n"
$LogFile+= "----------------------------------------------------------------`n"
}
}
}
}
11. Поиск по конкретному серверу, по всем событиям, за определенную дату:
if ($FindServerMode -ne "*" -and $DateEventsmode -notmatch "-" -and $DateEventsmode -ne "*" -and $TypeEventsMode -eq "*" -and $Log_Path -ne ""){
Write-host "вошли в 11"
$ALL_LOGS = Get-ChildItem -Path $Log_Path -Recurse| Where {$_.Extension -eq ".evtx" -and $StartDate1 -ne "null" } | Sort LastWriteTime
$ALL_LOGS
foreach ($Log in $ALL_LOGS){
$LogFile = "Audit EventLog Security" +"`n"
($Log).FullName
$Log.LastWriteTime
$StartDate
$EndDate
$MyFilter = @{Path=($Log).FullName}
Try {$Events = Get-WinEvent -FilterHashTable $MyFilter} Catch {"No events were found in $Log"; Continue}
ForEach ($Raw_Event in $Events){
Try{$EventXML = [xml]$Raw_Event.ToXML()} Catch {Write-Host "Unable to convert an event to XML"}
$Event = @{}
ForEach ($object in $EventXML.Event.EventData.Data) {
$Event.Add($object.name,$object.'#text')
}
$Event.Add("ID",$Raw_Event.ID)
$Event.Add("TimeCreated",$Raw_Event.TimeCreated)
if ($Event.TimeCreated.Day -eq $StartDate1.Day -and $Event.TimeCreated.Month -eq $StartDate1.Month -and $Event.TimeCreated.Year -eq $StartDate1.Year){
$LogFile+= "EventID: " + $Raw_Event.ID +"`n"
$LogFile+= "Target User Name: " + $Event.TargetUserName +"`n"
$LogFile+= "Target Domain Name: " + $Event.TargetDomainName +"`n"
$LogFile+= "Status: " + $Event.Status +"`n"
$LogFile+= "TimeGenerated: " + $Event.TimeCreated +"`n"
$LogFile+= "Workstation Name: " + $Event.WorkstationName +"`n"
$LogFile+= "IpAddress: " + $Event.IpAddress +"`n"
$LogFile+= "Computer: " + [xml]$Raw_Event.ToXML().Event.System.Computer +"`n"
$Reason = DefineReason -Id $Raw_Event.ID
$AccessM = DefineReasonByAccessMask -AccessMask $Event.Status
$LogFile+= "Reason(RU): " + $Reason + " "+ $AccessM +"`n"
$LogFile+= "Reason(SYS): " + $Event.Message +"`n"
$LogFile+= "----------------------------------------------------------------`n"
}
}
}
}
12. Поиск по конкретному серверу, по фильтру событий, за определенную дату:
if ($FindServerMode -ne "*" -and $TypeEventsMode -ne "*" -and $DateEventsmode -notmatch "-" -and $DateEventsmode -ne "*" -and $Log_Path -ne ""){
Write-host "вошли в 12"
$ALL_LOGS = Get-ChildItem -Path $Log_Path -Recurse| Where {$_.Extension -eq ".evtx" -and $StartDate1 -ne "null" } | Sort LastWriteTime
$ALL_LOGS
foreach ($Log in $ALL_LOGS){
$LogFile = "Audit EventLog Security" +"`n"
($Log).FullName
$Log.LastWriteTime
$StartDate
$EndDate
$MyFilter = @{Path=($Log).FullName;ID=$TypeEventsMode}
Try {$Events = Get-WinEvent -FilterHashTable $MyFilter} Catch {"No events were found in $Log"; Continue}
ForEach ($Raw_Event in $Events){
Try{$EventXML = [xml]$Raw_Event.ToXML()} Catch {Write-Host "Unable to convert an event to XML"}
$Event = @{}
ForEach ($object in $EventXML.Event.Message) {
$Event.Add($object.name,$object.'#text')
}
$Event.Add("ID",$Raw_Event.ID)
$Event.Add("TimeCreated",$Raw_Event.TimeCreated)
$Event
if ($Event.TimeCreated.Day -eq $StartDate1.Day -and $Event.TimeCreated.Month -eq $StartDate1.Month -and $Event.TimeCreated.Year -eq $StartDate1.Year){
$LogFile+= "EventID: " + $Raw_Event.ID +"`n"
$LogFile+= "Target User Name: " + $Event.TargetUserName +"`n"
$LogFile+= "Target Domain Name: " + $Event.TargetDomainName +"`n"
$LogFile+= "Status: " + $Event.Status +"`n"
$LogFile+= "TimeGenerated: " + $Event.TimeCreated +"`n"
$LogFile+= "Workstation Name: " + $Event.WorkstationName +"`n"
$LogFile+= "IpAddress: " + $Event.IpAddress +"`n"
$LogFile+= "Computer: " + [xml]$Raw_Event.ToXML().Event.System.Computer +"`n"
$Reason = DefineReason -Id $Raw_Event.ID
$AccessM = DefineReasonByAccessMask -AccessMask $Event.Status
$LogFile+= "Reason(RU): " + $Reason + " "+ $AccessM +"`n"
$LogFile+= "Reason(SYS): " + $Event.Message +"`n"
$LogFile+= "----------------------------------------------------------------`n"
}
}
}
}
В конце месяца (период индивидуально задается администраторами) журнал безопасности архивируется на сервер-хранилище, с указанием имени сервера и даты архивации.
После того как мы описали все варианты поиска событий. Полученный результат нам необходимо сохранить в файл, путь к которому прописал пользователь в последнем поле. Если путь задан, то результат сохраняется в файл. После отработки скрипта файл автоматически запускается. Если путь для сохранения результата не задан, то лог будет сохранен в рабочем каталоге под именем «log.log».
if ($SaveResult -ne ""){
$LogFile | Out-File $SaveResult -Encoding utf8
Invoke-Item $SaveResult
$Event2= @{}
$Event = @{}
$Log_Path=""
}
else{
$LogFile | Out-File ".\log.log" -Encoding utf8
Write-Host $LogFile
$Event2= @{}
$Event = @{}
$Log_Path=""
}
Спасибо за внимание.
Во время написания скрипта очень полезной оказалась статья "PowerShell и аудит безопасности", спасибо автору.
Комментарии (8)
padla2k
30.11.2015 20:14+31. Форму удобнее нарисовать на xaml и оформить отдельным файлом. В скрипте только создавать и показывать. Делается не сложно — если нужен пример — могу поделиться. После создания формы можно навесить на элементы нужные функции в качестве обработчиков событий.
2. Парсинг дат из текста — лишние телодвижения, ещё и не защищенные от ошибок. Если уж нарисовали форму, то почему бы не задействовать DatePicker и чек-бокс для скрытия/показа второго DataPicker'а?
3. Чем вам не угодил командлет Get-EventLog? Если уж так нужно пробежаться по всем-всем логам в системе то вот вам в помощь:
Get-EventLog -List | %{Get-EventLog -LogName $_.Log} | ?{<#тут делаем все что угодно с КАЖДОЙ записью лога#>}
Опять же если осуществлять поиск по ВСЕМ логам (а их в системе ну ОЧЕНЬ МНОГО, особенно если сервер не молодой), то желательно использовать powershell 3.0+ и конструкции workflow и foreach -parallel. Это как минимум сэкономит вам время.
В общем вижу некоторое количество костылей, которые сам делал будучи молодым скриптописателем… но все приходит с опытом. =)JunJa
30.11.2015 22:323. Чем вам не угодил командлет Get-EventLog? Если уж так нужно пробежаться по всем-всем логам в системе то вот вам в помощь:
Get-EventLog -List | %{Get-EventLog -LogName $_.Log} | ?{<#тут делаем все что угодно с КАЖДОЙ записью лога#>}
Сохраните журнал на диск Д и попробуйте его получить? Получиться сделать это при помощи команды?
По поводу остальных замечательных, попробую учесть при написании след. скриптов. Спасибо.padla2k
01.12.2015 07:54+1А зачем сохранять логи на диск? Оперативные логи есть в системе, если нужный диапазон времени не влазит в файл лога — увеличиваем его максимальный размер. Актуальность старых логов (кроме security) представляется мне сомнительной.
n01d
02.12.2015 11:11Форму удобнее нарисовать на xaml и оформить отдельным файлом
Использую для рисования форм софтину PrimalForms от Sapien. Очень удобная штука: построение форм по принципу Visual Studio. К сожалению, в свободном доступе больше недоступен…
workflow и foreach -parallel
Ужасная вещь (особенно при неумелом использовании), но иногда экономит тысячи времени, да. Стараюсь использовать как можно реже, но при сборе инфы с 1000+ компов — просто спасает. Главноеthrottlelimit
правильно подобрать, чтобы всю оперативку не сожрало ;-)
Dal
А все одним архивчиком есть?
JunJa
www.fayloobmennik.net/5560566 пароль 0000