Windows DHCP 伺服器 - 當未加入 AD 的設備獲得 IP 地址時收到通知
設想
將其簡化為最簡單的範例:
我有一個具有 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 中找不到,請發送通知電子郵件
如果有人對如何正確執行此操作有任何想法,我將不勝感激。我不是在尋找“給我程式碼”,而是想知道是否有上述列表的替代品,或者我是否想清楚並且存在另一種收集此資訊的方法。如果您有想要共享的程式碼片段/PS 命令來幫助完成此任務,那就更好了。
非常感謝 ErikE 和這裡的其他人,我已經走上了一條道路……我不會說這是正確的道路,但我想出的 Powershell 腳本可以解決問題。
如果有人想要,程式碼如下。只需手動執行它指向每個 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-模組在-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],"\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)
希望對其他人有所幫助!