为了简化这个最简单的例子:
我有一个具有DHCP服务器angular色的Windows 2008 R2标准DC。 它通过各种IPv4范围提供IP,在那里没有问题。
我想创build通知/事件日志条目/类似的方式,只要设备获得DHCP地址租约,并且该设备不是 Active Directory中join域的计算机。 Powershell是不是自定义的Powershell等等
底线= 我想知道什么时候非域设备在networking上,而不使用802.1X。 我知道这不会占静态IP设备。 我有监控软件,可以扫描networking和查找设备,但是细节上并没有这么详细。
我没有看到任何内置日志logging的可能性。
是的,我知道802.1X,并有能力在这个位置长期实施,但我们有一段时间这样的项目,虽然这将解决networking身份validation问题,这对我仍然是有帮助的802.1X目标。
我已经四处寻找一些脚本位等,可能会certificate是有用的,但我发现的事情导致我相信,我的谷歌眼下正在失败的时刻。
我相信下面的逻辑是正确的( 假设没有一些现有的解决scheme ):
如果有人有任何想法如何正确地做到这一点,我真的很感激。 我不是在寻找一个“gimme codez”,但很想知道是否有上面列表的替代scheme,或者如果我没有想清楚,另有一种方法来收集这些信息。 如果你有代码段/ PS命令,你想分享,以帮助完成这一切,更好。
非常感谢ErikE和这里的其他人,我走了一条路……我不会说这是正确的道路,但是我所提出的Powershell脚本能够做到这一点。
代码如下,如果有人想要它。 只需手动指向每个DHCP服务器或安排它(再次指向脚本中的每个DHCP服务器)。
脚本做了什么:
你需要什么:
该脚本使用AD模块( import-module activedirectory
),因此最好在运行DHCP的AD DC上运行。 如果情况并非如此,则可以安装AD PowerShell模块: http : //blogs.msdn.com/b/rkramesh/archive/2012/01/17/how-to-add-active-directory-模块function于PowerShell的在窗口,7.aspx
您还需要在此处findQuest的AD PowerShell cmdlet: http : //www.quest.com/powershell/activeroles-server.aspx 。 安装这些之前运行脚本,否则将失败。
脚本本身(消毒,你需要设置一些variables来满足你的需求,如input文件名,连接域,连接到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="[email protected]" $to="[email protected]" $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)
希望能帮助别人!
好吧,我不确定我在这里做礼仪,但是发布了第二个答案,而不是编辑我之前的答案,因为它包含了一些可能对某人有用的信息,即使被certificate与这种情况无关。 如果这让我在这个论坛白痴随意通知我的错误的方式。
问题分为几个部分,这里是我觉得最有趣的build议。 没有来自日志的例子,这是我能做的最好的,所以这只是build议,而不是解决scheme。
要parsing日志,请使用get-content
和-wait
参数。 对于我的用例,在错误日志中find错误就足够了。
这是我为自己的用例工作,原谅格式:
get-content E:\temp13\log.txt -tail(1) -wait | where {$_ -match "ERROR"} | foreach { send-mailmessage ` -port 25 ` -smtpserver my.mail.server ` -from logmon@ab ` -to erike@ab ` -subject "test logmonitor" ` -body "ERROR found: $_" ` }
而不是$_ -match "ERROR"
您需要以某种方式将日志ID字段和计算机名称分开。 我不知道如何以最好的方式去解决这个问题,但是由于where-object -match
支持正则expression式,所以我猜这可能是一个选项。 你也可以开始将$ _variables存储在另一个新的variables中,以便在稍后的pipe道中,在嵌套的foreach循环等内部方便的时候把它拿起来。
假设你可以得到计算机名,我猜get-adcomputer
cmdlet是你查询你的AD最简单的方法( import-module activedirectory
),我猜错误发送邮件?
使用import-csv
当然会更优雅一些,但是我不知道有什么方法拖拽它(如果有人正好读这个,那么请把这个胡同弄好,请分享一下)。
假设您确定了事件ID,并且没有其他事件在DHCP日志中logging此ID,但是您感兴趣的事件,推送确实是一个选项。
1)打开服务器pipe理器,转到事件查看器中的DHCP日志。
2)find你想要附加你的行动的代表性条目。 select它并右键单击。
3)select“附加任务到这个事件”。
4)任务创build向导打开,从那里拿走…
实际上有一个明确的电子邮件选项,但是如果您需要更多的逻辑,那么您当然可以免费使用启动程序选项来启动powershell.exe并为其添加脚本。 有很多优秀的googleable howtos如何让任务pipe理器运行powershell脚本,如果你需要指导。
我看到的直接select是通过使用PowerShell按预定的时间间隔parsing事件日志来使用pull。 “微软脚本专家”,又名Ed Wilson编写了一些关于如何使用不同版本的PowerShell中可用的cmdletparsing事件日志的精彩的博客文章,所以以他的博客为出发点将是我的build议。
至于实际的小命令,我现在没有时间去抽出一些方便的代码片段,但是在一两天之后再看一次,如果没有其他人select了一些,或者你没有select,没有解决这一切由自己:-)
虽然这不能解决您所期望的解决scheme,但是可以实现您的目标的一个选项是利用arpwatch
( 链接 )在networking上看到新的(以前未见过的)主机时通知您。
一个Windows替代arpwatch
似乎是decaffeinatid,但我从来没有使用过,所以不能说它的好或坏。