要将其简化为最简单的示例:
我有一个带有DHCP服务器角色的Windows 2008 R2标准DC.它通过各种IPv4范围分发IP,没问题.
我喜欢什么
我想要一种方法来创建一个通知/事件日志条目/类似设备获得DHCP地址租约和该设备不是一个域加入Active Directory中的计算机.对我来说无论是自定义Powershell等都没关系.
底线=我想知道什么时候非域设备在网络上而不使用802.1X.我知道这不会考虑静态IP设备.我确实有扫描网络和查找设备的监控软件,但它的细节并不是那么精细.
研究过程/考虑的选择
我没有看到内置日志记录的任何可能性.
是的,我知道802.1X并且能够在这个位置长期实现它,但我们离这样的项目还有一段时间,虽然这样可以解决网络身份验证问题,但这对我来说仍然有帮助的802.1X目标.
我四处寻找可能有用的脚本等等,但我发现的东西让我相信我的google-fu现在让我失望了.
我相信下面的逻辑是合理的(假设没有一些现有的解决方案):
>设备接收DHCP地址
>记录事件日志条目(DHCP审核日志中的事件ID 10应该起作用(因为新租约是我最感兴趣的,而不是续订):http://technet.microsoft.com/en-us/library/dd759178.aspx)
>此时,某种脚本可能不得不接管下面的剩余“步骤”.
>以某种方式查询这个事件ID 10的DHCP日志(我很乐意
推,但我猜拉是这里唯一的办法)
>解析查询所分配新租约的设备的名称
>查询AD以获取设备的名称
>如果在AD中找不到,请发送通知电子邮件
如果有人对如何正确地做到这一点有任何想法,我真的很感激.我不是在寻找“gimme the codez”,但是我很想知道上面列表是否有替代方案,或者我是否认为没有清楚,并且存在收集此信息的另一种方法.如果你有代码片段/ PS命令,你想分享以帮助实现这一目标,那就更好了.
如果有人想要,代码如下.只需手动指向每个DHCP服务器或计划它(再次指向脚本中的每个DHCP服务器).
脚本的作用:
>从DHCP服务器获取租约信息(ipv4租约)
>将租约输出到csv文件
>回读该CSV文件以查询AD
>查询计算机的AD
>如果未找到输出到新的txt文件
>从上面#5中创建的文件中创建一个唯一的列表最终txt文件(因为如果客户端多次注册或使用多个适配器,则可能存在欺骗)
>将最终输出文件的内容通过电子邮件发送给管理员
你需要什么:
该脚本使用AD模块(import-module activedirectory),因此最好在运行DHCP的AD DC上运行.如果您不是这种情况,则可以安装AD powershell模块: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 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],}") $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)
希望能帮助别人!