Чтобы упростить это до самого простого примера:
У меня стандартный контроллер домена Windows 2008 R2 с ролью DHCP-сервера. Он раздает IP-адреса через различные области IPv4, здесь нет проблем.
Мне нужен способ создать запись уведомления / журнала событий / аналогичную всякий раз, когда устройство получает аренду DHCP-адреса и это устройство НЕ ЯВЛЯЕТСЯ компьютер, присоединенный к домену в Active Directory. Для меня не имеет значения, кастомный ли это Powershell и т. Д.
Итог = Мне нужен способ узнать, когда в сети находятся устройства, не относящиеся к домену, без использования 802.1X в данный момент. Я знаю, что это не будет учитывать статические IP-устройства. У меня есть программное обеспечение для мониторинга, которое сканирует сеть и находит устройства, но оно не так детально.
Я не вижу таких возможностей со встроенным логированием.
Да, я знаю о 802.1X и имею возможность реализовать его в долгосрочной перспективе в этом месте, но мы находимся некоторое время вдали от подобного проекта, и хотя это решит проблемы сетевой аутентификации, это все еще полезно для меня за пределами целей 802.1X.
Я поискал некоторые фрагменты сценария и т. Д., Которые могут оказаться полезными, но то, что я нахожу, заставляет меня поверить, что мой google-fu подводит меня в данный момент.
Я считаю, что приведенная ниже логика верна (при условии, что нет какого-либо существующего решения):
Если у кого-то есть идеи, как это правильно сделать, я буду очень признателен. Я не ищу «дай мне код», но хотел бы знать, есть ли альтернативы приведенному выше списку, или я не думаю ясно, и существует другой метод для сбора этой информации. Если у вас есть фрагменты кода / команды PS, которыми вы хотели бы поделиться, чтобы помочь в этом, тем лучше.
Большое спасибо ErikE и остальным здесь, я пошел по пути ... Я не скажу, что это правильный путь, но скрипт Powershell, который я придумал, помогает.
Код ниже, если кто-то этого хочет. Просто запустите его вручную, указывая на каждый DHCP-сервер, или запланируйте его (снова указывая на каждый DHCP-сервер в сценарии).
Что делает сценарий:
Что вам понадобится:
Скрипт использует модуль AD (import-module activedirectory
), поэтому его лучше всего запускать на AD DC с DHCP. Если это не ваш случай, вы можете установить модуль PowerShell AD: http://blogs.msdn.com/b/rkramesh/archive/2012/01/17/how-to-add-active-directory-module-in-powershell-in-windows-7.aspx
Вам также понадобятся командлеты Quest AD Powershell, которые можно найти здесь: http://www.quest.com/powershell/activeroles-server.aspx . Установите ЭТИ ПЕРЕД запуск скрипта, иначе он не удастся.
Сам скрипт (очищенный, вам нужно будет настроить некоторые переменные в соответствии с вашими потребностями, такие как имена входных файлов, домен для подключения, сервер DHCP для подключения, настройки электронной почты в конце и т. Д.):
# Get-nonADclientsOnDHCP.ps1
# Author : TheCleaner http://serverfault.com/users/7861/thecleaner with a big thanks for a lot of the lease grab code to Assaf Miron on code.google.com
# Description : This Script grabs the current leases on a Windows DHCP server, outputs it to a csv
# then takes that csv file as input and determines if the lease is from a non-AD joined computer. It then emails
# an administrator notification. Set it up on a schedule of your choosing in Task Scheduler.
# This helps non-802.1X shops keep track of rogue DHCP clients that aren't part of the domain.
#
# Input : leaselog.csv
# Output: Lease log = leaselog.csv
# Output: Rogue Clients with dupes = RogueClients.txt
# Output: Rogue Clients - unique = RogueClientsFinal.txt
$DHCP_SERVER = "PUT YOUR SERVER NAME OR IP HERE" # The DHCP Server Name
$LOG_FOLDER = "C:\DHCP" # A Folder to save all the Logs
# Create Log File Paths
$LeaseLog = $LOG_FOLDER+"\LeaseLog.csv"
#region Create Scope Object
# Create a New Object
$Scope = New-Object psobject
# Add new members to the Object
$Scope | Add-Member noteproperty "Address" ""
$Scope | Add-Member noteproperty "Mask" ""
$Scope | Add-Member noteproperty "State" ""
$Scope | Add-Member noteproperty "Name" ""
$Scope | Add-Member noteproperty "LeaseDuration" ""
# Create Each Member in the Object as an Array
$Scope.Address = @()
$Scope.Mask = @()
$Scope.State = @()
$Scope.Name = @()
$Scope.LeaseDuration = @()
#endregion
#region Create Lease Object
# Create a New Object
$LeaseClients = New-Object psObject
# Add new members to the Object
$LeaseClients | Add-Member noteproperty "IP" ""
$LeaseClients | Add-Member noteproperty "Name" ""
$LeaseClients | Add-Member noteproperty "Mask" ""
$LeaseClients | Add-Member noteproperty "MAC" ""
$LeaseClients | Add-Member noteproperty "Expires" ""
$LeaseClients | Add-Member noteproperty "Type" ""
# Create Each Member in the Object as an Array
$LeaseClients.IP = @()
$LeaseClients.Name = @()
$LeaseClients.MAC = @()
$LeaseClients.Mask = @()
$LeaseClients.Expires = @()
$LeaseClients.Type = @()
#endregion
#region Create Reserved Object
# Create a New Object
$LeaseReserved = New-Object psObject
# Add new members to the Object
$LeaseReserved | Add-Member noteproperty "IP" ""
$LeaseReserved | Add-Member noteproperty "MAC" ""
# Create Each Member in the Object as an Array
$LeaseReserved.IP = @()
$LeaseReserved.MAC = @()
#endregion
#region Define Commands
#Commad to Connect to DHCP Server
$NetCommand = "netsh dhcp server \\$DHCP_SERVER"
#Command to get all Scope details on the Server
$ShowScopes = "$NetCommand show scope"
#endregion
function Get-LeaseType( $LeaseType )
{
# Input : The Lease type in one Char
# Output : The Lease type description
# Description : This function translates a Lease type Char to it's relevant Description
Switch($LeaseType){
"N" { return "None" }
"D" { return "DHCP" }
"B" { return "BOOTP" }
"U" { return "UNSPECIFIED" }
"R" { return "RESERVATION IP" }
}
}
function Check-Empty( $Object ){
# Input : An Object with values.
# Output : A Trimmed String of the Object or '-' if it's Null.
# Description : Check the object if its null or not and return it's value.
If($Object -eq $null)
{
return "-"
}
else
{
return $Object.ToString().Trim()
}
}
function out-CSV ( $LogFile, $Append = $false) {
# Input : An Object with values, Boolean value if to append the file or not, a File path to a Log File
# Output : Export of the object values to a CSV File
# Description : This Function Exports all the Values and Headers of an object to a CSV File.
# The Object is recieved with the Input Const (Used with Pipelineing) or the $inputObject
Foreach ($item in $input){
# Get all the Object Properties
$Properties = $item.PsObject.get_properties()
# Create Empty Strings - Start Fresh
$Headers = ""
$Values = ""
# Go over each Property and get it's Name and value
$Properties | %{
$Headers += $_.Name + ","
$Values += $_.Value
}
# Output the Object Values and Headers to the Log file
If($Append -and (Test-Path $LogFile)) {
$Values | Out-File -Append -FilePath $LogFile -Encoding Unicode
}
else {
# Used to mark it as an Powershell Custum object - you can Import it later and use it
# "#TYPE System.Management.Automation.PSCustomObject" | Out-File -FilePath $LogFile
$Headers | Out-File -FilePath $LogFile -Encoding Unicode
$Values | Out-File -Append -FilePath $LogFile -Encoding Unicode
}
}
}
#region Get all Scopes in the Server
# Run the Command in the Show Scopes var
$AllScopes = Invoke-Expression $ShowScopes
# Go over all the Results, start from index 5 and finish in last index -3
for($i=5;$i -lt $AllScopes.Length-3;$i++)
{
# Split the line and get the strings
$line = $AllScopes[$i].Split("-")
$Scope.Address += Check-Empty $line[0]
$Scope.Mask += Check-Empty $line[1]
$Scope.State += Check-Empty $line[2]
# Line 3 and 4 represent the Name and Comment of the Scope
# If the name is empty, try taking the comment
If (Check-Empty $line[3] -eq "-") {
$Scope.Name += Check-Empty $line[4]
}
else { $Scope.Name += Check-Empty $line[3] }
}
# Get all the Active Scopes IP Address
$ScopesIP = $Scope | Where { $_.State -eq "Active" } | Select Address
# Go over all the Adresses to collect Scope Client Lease Details
Foreach($ScopeAddress in $ScopesIP.Address){
# Define some Commands to run later - these commands need to be here because we use the ScopeAddress var that changes every loop
#Command to get all Lease Details from a specific Scope - when 1 is amitted the output includes the computer name
$ShowLeases = "$NetCommand scope "+$ScopeAddress+" show clients 1"
#Command to get all Reserved IP Details from a specific Scope
$ShowReserved = "$NetCommand scope "+$ScopeAddress+" show reservedip"
#Command to get all the Scopes Options (Including the Scope Lease Duration)
$ShowScopeDuration = "$NetCommand scope "+$ScopeAddress+" show option"
# Run the Commands and save the output in the accourding var
$AllLeases = Invoke-Expression $ShowLeases
$AllReserved = Invoke-Expression $ShowReserved
$AllOptions = Invoke-Expression $ShowScopeDuration
# Get the Lease Duration from Each Scope
for($i=0; $i -lt $AllOptions.count;$i++)
{
# Find a Scope Option ID number 51 - this Option ID Represents the Scope Lease Duration
if($AllOptions[$i] -match "OptionId : 51")
{
# Get the Lease Duration from the Specified line
$tmpLease = $AllOptions[$i+4].Split("=")[1].Trim()
# The Lease Duration is recieved in Ticks / 10000000
$tmpLease = [int]$tmpLease * 10000000; # Need to Convert to Int and Multiply by 10000000 to get Ticks
# Create a TimeSpan Object
$TimeSpan = New-Object -TypeName TimeSpan -ArgumentList $tmpLease
# Calculate the $tmpLease Ticks to Days and put it in the Scope Lease Duration
$Scope.LeaseDuration += $TimeSpan.TotalDays
# After you found one Exit the For
break;
}
}
# Get all Client Leases from Each Scope
for($i=8;$i -lt $AllLeases.Length-4;$i++)
{
# Split the line and get the strings
$line = [regex]::split($AllLeases[$i],"\s{2,}")
# Check if you recieve all the lines that you need
$LeaseClients.IP += Check-Empty $line[0]
$LeaseClients.Mask += Check-Empty $line[1].ToString().replace("-","").Trim()
$LeaseClients.MAC += $line[2].ToString().substring($line[2].ToString().indexOf("-")+1,$line[2].toString().Length-1).Trim()
$LeaseClients.Expires += $(Check-Empty $line[3]).replace("-","").Trim()
$LeaseClients.Type += Get-LeaseType $(Check-Empty $line[4]).replace("-","").Trim()
$LeaseClients.Name += Check-Empty $line[5]
}
# Get all Client Lease Reservations from Each Scope
for($i=7;$i -lt $AllReserved.Length-5;$i++)
{
# Split the line and get the strings
$line = [regex]::split($AllReserved[$i],"\s{2,}")
$LeaseReserved.IP += Check-Empty $line[0]
$LeaseReserved.MAC += Check-Empty $line[2]
}
}
#endregion
#region Create a Temp Scope Object
# Create a New Object
$tmpScope = New-Object psobject
# Add new members to the Object
$tmpScope | Add-Member noteproperty "Address" ""
$tmpScope | Add-Member noteproperty "Mask" ""
$tmpScope | Add-Member noteproperty "State" ""
$tmpScope | Add-Member noteproperty "Name" ""
$tmpScope | Add-Member noteproperty "LeaseDuration" ""
#endregion
#region Create a Temp Lease Object
# Create a New Object
$tmpLeaseClients = New-Object psObject
# Add new members to the Object
$tmpLeaseClients | Add-Member noteproperty "IP" ""
$tmpLeaseClients | Add-Member noteproperty "Name" ""
$tmpLeaseClients | Add-Member noteproperty "Mask" ""
$tmpLeaseClients | Add-Member noteproperty "MAC" ""
$tmpLeaseClients | Add-Member noteproperty "Expires" ""
$tmpLeaseClients | Add-Member noteproperty "Type" ""
#endregion
#region Create a Temp Reserved Object
# Create a New Object
$tmpLeaseReserved = New-Object psObject
# Add new members to the Object
$tmpLeaseReserved | Add-Member noteproperty "IP" ""
$tmpLeaseReserved | Add-Member noteproperty "MAC" ""
#endregion
# Go over all the Client Lease addresses and export each detail to a temporary var and out to the log file
For($l=0; $l -lt $LeaseClients.IP.Length;$l++)
{
# Get all Scope details to a temp var
$tmpLeaseClients.IP = $LeaseClients.IP[$l] + ","
$tmpLeaseClients.Name = $LeaseClients.Name[$l] + ","
$tmpLeaseClients.Mask = $LeaseClients.Mask[$l] + ","
$tmpLeaseClients.MAC = $LeaseClients.MAC[$l] + ","
$tmpLeaseClients.Expires = $LeaseClients.Expires[$l] + ","
$tmpLeaseClients.Type = $LeaseClients.Type[$l]
# Export with the Out-CSV Function to the Log File
$tmpLeaseClients | out-csv $LeaseLog -append $true
}
#Continue on figuring out if the DHCP lease clients are in AD or not
#Import the Active Directory module
import-module activedirectory
#import Quest AD module
Add-PSSnapin Quest.ActiveRoles.ADManagement
#connect to AD
Connect-QADService PUTTHEFQDNOFYOURDOMAINHERE_LIKE_DOMAIN.LOCAL | Out-Null
# get input CSV
$leaselogpath = "c:\DHCP\LeaseLog.csv"
Import-csv -path $leaselogpath |
#query AD for computer name based on csv log
foreach-object `
{
$NameResult = Get-QADComputer -DnsName $_.Name
If ($NameResult -eq $null) {$RogueSystem = $_.Name}
$RogueSystem | Out-File C:\DHCP\RogueClients.txt -Append
$RogueSystem = $null
}
Get-Content C:\DHCP\RogueClients.txt | Select-Object -Unique | Out-File C:\DHCP\RogueClientsFinal.txt
Remove-Item C:\DHCP\RogueClients.txt
#send email to netadmin
$smtpserver = "SMTP SERVER IP"
$from="DHCPSERVER@domain.com"
$to="TheCleaner@domain.com"
$subject="Non-AD joined DHCP clients"
$body= (Get-Content C:\DHCP\RogueClientsFinal.txt) -join '<BR> <BR>'
$mailer = new-object Net.Mail.SMTPclient($smtpserver)
$msg = new-object Net.Mail.MailMessage($from,$to,$subject,$body)
$msg.IsBodyHTML = $true
$mailer.send($msg)
Надеюсь, это поможет кому-то другому!
Хорошо, я не уверен, что соблюдаю правила этикета, но отправляю второй ответ вместо редактирования предыдущего, так как он содержал некоторую информацию, которая может быть кому-то полезна, даже если окажется, что она не имеет отношения к данному делу. Если это делает меня идиотом на этом форуме, не стесняйтесь сообщать мне о моих ошибочных действиях.
Задача разделена на несколько частей, вот предложения по наиболее интересным. Без примеров из журнала это лучшее, что я могу сделать, так что это просто предложения, а не решения.
Для анализа журнала используйте get-content
с -wait
параметр. Для моего случая использования достаточно найти ошибку в журнале ошибок.
Вот что сработало для моего собственного варианта использования, простите за форматирование:
get-content E:\temp13\log.txt -tail(1) -wait | where {$_ -match "ERROR"} |
foreach {
send-mailmessage `
-port 25 `
-smtpserver my.mail.server `
-from logmon@a.b `
-to erike@a.b `
-subject "test logmonitor" `
-body "ERROR found: $_" `
}
Вместо $_ -match "ERROR"
вам нужно как-то разделить поле идентификатора журнала и имя компьютера. Я не знаю, как это сделать наилучшим образом прямо сейчас, но поскольку where-object -match
дает поддержку регулярных выражений, я думаю, это может быть вариант. Вы также можете начать с сохранения переменной $ _ в другой новой переменной, чтобы иметь возможность забрать ее в удобное для вас время в конвейере, внутри вложенных циклов foreach и т. Д.
Предполагая, что вы можете получить имя компьютера, я думаю, что get-adcomputer
командлет будет вашим самым простым способом запроса вашего AD (import-module activedirectory
), а я догадываюсь об ошибке отправить почту?
Используя import-csv
было бы, конечно, гораздо более элегантно в вашем случае, но я не знаю, как с этим справиться (если кто-нибудь прочитает это и знает трюк в этом переулке, пожалуйста, поделитесь).
Хотя это не касается вашего желаемого решения, вариант, который может достичь вашей цели, - это использовать arpwatch
(ссылка на сайт), чтобы уведомить вас, когда в сети появляется новый (ранее невидимый) хост.
Альтернатива Windows для arpwatch
по-видимому декафеинатид но я никогда не использовал его, поэтому не могу сказать, хорошо это или плохо.
Если вы уверены в идентификаторе события и что в журнале DHCP с этим идентификатором не регистрируются никакие другие события, кроме тех, которые вам интересны, push действительно возможен.
1) Откройте диспетчер серверов, перейдите в журнал DHCP в средстве просмотра событий.
2) Найдите репрезентативную запись, к которой вы хотите прикрепить свое действие. Выберите его и щелкните правой кнопкой мыши.
3) Выберите «Присоединить задачу к этому событию».
4) Откроется Мастер создания задачи, забери оттуда ...
На самом деле существует явный вариант электронной почты, но если вам нужно больше логики, вы, конечно, можете использовать параметр start-a-program, чтобы запустить powershell.exe и прикрепить к нему сценарий. Существует множество отличных руководств, которые можно использовать в Google, о том, как разрешить диспетчеру задач запускать сценарии PowerShell, если вам нужно руководство.
Прямая альтернатива, которую я вижу, - использовать pull, анализируя журнал событий с помощью PowerShell через запланированные интервалы. «Microsoft Scripting Guy», он же Эд Уилсон, написал несколько замечательных сообщений в блогах о том, как анализировать журнал событий с помощью командлетов, доступных в различных версиях PowerShell, поэтому я бы посоветовал взять его блог в качестве отправной точки.
Что касается настоящих командлетов, у меня сейчас нет времени, чтобы вытащить свой запас удобных фрагментов, но я загляну снова через день или два и может внести свой вклад, если никто другой не представился с некоторыми хорошо подобранными или у вас нет Сам не решил :-)