Windows DHCP服务器-当非AD加入的设备获得IP地址时获得通知


15

场景

为了简化到最简单的例子:

我有一个具有DHCP服务器角色的Windows 2008 R2标准DC。它通过各种IPv4范围分发IP,在那里没有问题。

我会喜欢什么

我想要一种在设备获得DHCP地址租约且该设备不是 Active Directory中加入域的计算机时创建通知/事件日志条目/类似对象的方法。对我来说,这是否是定制Powershell等都无关紧要。

底线= 我想知道一种方式,无需使用802.1X即可知道网络上何时有非域设备。 我知道这不会考虑静态IP设备。我确实有监视软件,可以扫描网络并查找设备,但是在细节上并不太详细。

研究完成/考虑的选项

我看不到内置日志记录有任何这种可能性。

是的,我知道802.1X并有能力在此位置长期实施,但是我们距离这样的项目还有一段时间,尽管这可以解决网络身份验证问题,但在外面对我仍然有帮助802.1X目标。

我到处寻找一些脚本位,等等,这些脚本可能被证明是有用的,但是我发现的事情使我相信,我的google-fu目前使我失败了。

我相信下面的逻辑是合理的(假设没有现有的解决方案):

  1. 设备收到DHCP地址
  2. 记录了事件日志条目(DHCP审核日志中的事件ID 10应该起作用(因为新租约是我最感兴趣的,而不是续约):http : //technet.microsoft.com/zh-cn/library /dd759178.aspx
  3. 此时,某种脚本可能必须接管下面剩余的“ STEPS”。
  4. 以某种方式在此DHCP日志中查询这些事件ID 10(我希望推送,但是我猜pull是这里的唯一方法)
  5. 解析查询以获取分配了新租约的设备的名称
  6. 查询AD以获取设备名称
  7. 如果不是在AD中发现,发送电子邮件通知

如果有人对如何正确执行此操作有任何想法,我将非常感谢。我不是在寻找“代码编解码器”,而是想知道是否有上述列表的替代方法,或者我是否想清楚,是否存在另一种收集此信息的方法。如果您想共享代码片段/ PS命令​​以帮助完成此任务,那就更好了。


您是要阻止它们,还是只是获得它们的IP通知?
HostBits

@Cheekaleak-刚收到通知。
TheCleaner

那使用DHCP的网络打印机呢?
jftuga

@jftuga-我们将静态IP用于网络打印机。
TheCleaner

Answers:


6

非常感谢ErikE和这里的其他人,我已经走了一条路...我不会说这是正确的路,但是我想出的Powershell脚本可以解决问题。

如果有人需要,下面的代码。只需手动指向每个DHCP服务器运行或计划它(再次指向脚本中的每个DHCP服务器)即可。

该脚本的作用:

  1. 从DHCP服务器获取租约信息(ipv4租约)
  2. 将租约输出到csv文件
  3. 读回该CSV文件以查询AD
  4. 查询计算机的广告
  5. 如果找不到,则输出到新的txt文件
  6. 从以上#5中创建的列表中创建一个唯一的列表最终txt文件(因为如果客户端注册一次以上或使用多个适配器,则可能会有重复)
  7. 通过电子邮件将最终输出文件的内容发送给管理员

您需要什么:

该脚本使用AD模块(import-module activedirectory),因此最好在运行DHCP的AD DC上运行。如果您不是这种情况,则可以安装AD powershell模块:http : //blogs.msdn.com/b/rkramesh/archive/2012/01/17/how-to-add-active-directory- Windows 7.aspx中的Powershell模块

您还需要在此处找到Quest的AD Powershell cmdlet: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>&nbsp;<BR>'
$mailer = new-object Net.Mail.SMTPclient($smtpserver)
$msg = new-object Net.Mail.MailMessage($from,$to,$subject,$body)
$msg.IsBodyHTML = $true
$mailer.send($msg)

希望对别人有帮助!


3

好的,我不确定我是否遵循此处的礼节,但我发布的是第二个答案,而不是编辑我的上一个答案,因为它确实包含一些信息,即使已证明与本案无关,也可能对某些人有用。如果那使我成为这个论坛中的白痴,请随时告诉我我的错误方式。

该问题分为几个部分,以下是我最感兴趣的部分的建议。没有日志中的示例,这是我能做的最好的事情,因此,它只是建议而不是解决方案。

要分析日志使用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"您需要以某种方式分隔日志ID字段和计算机名称。我现在不确定如何以最佳方式解决这个问题,但是由于where-object -match提供了正则表达式支持,我想这可能是一个选择。您还可以先将$ _变量存储在另一个新变量中,以便以后在管道中,嵌套的foreach循环中等方便时使用它。

假设您可以使用计算机名,那么我猜该get-adcomputercmdlet是查询AD(import-module activedirectory)的最简单方法,并且我猜在发送邮件时出错了吗?

import-csv在您的情况下,使用该方法当然会更优雅,但是我不知道有什么拖尾的方法(如果有人碰巧读了此书,并且知道了一条小巷的窍门,请分享)。


谢谢ErikE,我将继续进行介绍,并告诉您。我需要找出一种获取信息,查询广告的方法,然后在“警告”之后忽略对同一行输入的将来检查。例如,如果它每五分钟查询一次文件,我不希望它重新解析相同的信息并每五分钟发送一次重复警报。
TheCleaner 2013年

我发现有两点很简洁:如果只让脚本运行,wait参数将使它不断等待新行的出现。您不必重新运行脚本。他将提供推力效果而不是拉力。另外,tail(1)将在开始时仅解析最后1行。因此,如果任务管理器发现它必须重新启动脚本,并且您找到了一种方法来注入占位符行来代替最后一行来触发警报,那么您将消除对Realerts的烦恼。
ErikE

1
埃里克(Erik),我找到了一种方法,可以将DHCP的租借(2012年有PS cmdlet,但2008年没有PS cmdlet)导出为csv文件。这样,我就不会混淆实际的审核日志,也不必担心会破坏输入内容。我将开始处理其余的代码,并尽快进行更新。
TheCleaner

1

假设您确定事件ID,并且没有其他事件记录到DHCP日志中的该ID中,而是您感兴趣的事件,则push实际上是一种选择。

1)打开服务器管理器,在事件查看器中转到DHCP日志。

2)找到您要附加动作的代表条目。选择它并右键单击。

3)选择“将任务附加到此事件”。

4)任务创建向导打开,将其从那里拿走...

实际上有一个显式的电子邮件选项,但是如果您需要的逻辑更多,您当然可以使用启动程序选项启动powershell.exe并将脚本附加到它。如果需要指导,有很多关于如何让任务管理器运行Powershell脚本的出色的Google可操作方法。

我看到的直接替代方法是通过按计划的时间间隔使用powershell解析事件日志来使用pull。“ Microsoft脚本专家”(又名Ed Ed Wilson)撰写了一些很棒的博客文章,内容涉及如何使用不同版本的Powershell中提供的cmdlet解析事件日志,因此我的建议是以他的博客为起点。

至于实际的cmdlet,我现在没有时间抽出我的便携式代码段,但是会在一两天内再次查看,如果没有其他人选择一些精心挑选的代码,或者您没有不能自己解决所有问题:-)


2
埃里克,谢谢你。这里的问题是C:\ windows \ system32 \ DHCP中的DHCPsrvlog-“ day”(在DHCP服务器GUI中启用了DHCP审核),不会写入任何事件查看器日志,包括下面的DHCP服务器事件查看器日志Applications and Services Logs(到目前为止,根据我的研究/测试)
TheCleaner

我已经忘记了那些日志。但是我认为这是一个可能的场所:使用带有-wait和-tail指令的get-content解析文本日志。这类似于* nix中的tail。为了确保实例始终在解析日志,任务管理器可以安排脚本在系统启动时进行调度,然后启动每个脚本(可能的最短间隔),但只允许一个正在运行的实例。如果您的事件弹出,请触发逻辑。
ErikE

事实证明,我在Windows上有一个类似的日志解析问题要解决,我将在确定可以工作时将发现发布到该特定部分上,并且可能还有其他一些构建基块,这对您很有用。您能否从dhcp日志中粘贴几个有代表性但混淆的行?我对设备名称格式特别感兴趣。
ErikE

1

尽管这不能解决您所需要的解决方案,但是可以实现您的目标的一个选项是,当网络上出现新的(以前看不见的)主机时,利用arpwatchlink)通知您。

Windows替代品arpwatch似乎没有咖啡因,但我从未使用过,因此不能说它的好坏。


谢谢。那里的想法很合理。如有必要,我可能会走这条路。
TheCleaner 2013年

额外的好处是,这还将捕获使用静态IP的新计算机,这不在您声明的范围内,但应该是。
mfinni
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.