Server DHCP di Windows: ricevi una notifica quando un dispositivo unito non AD riceve un indirizzo IP


15

SCENARIO

Per semplificare questo fino al suo esempio più semplice:

Ho un controller di dominio standard di Windows 2008 R2 con il ruolo del server DHCP. Distribuisce IP tramite vari ambiti IPv4, nessun problema lì.

COSA MI PIACCIONO

Vorrei un modo per creare una voce di notifica / eventlog / simile ogni volta che un dispositivo riceve un contratto di locazione di indirizzi DHCP e quel dispositivo NON È un computer collegato a dominio in Active Directory. Non importa se è Powershell personalizzato, ecc.

Bottom line = Vorrei un modo per sapere quando i dispositivi non di dominio sono sulla rete senza utilizzare 802.1X al momento. So che questo non terrà conto dei dispositivi IP statici. Ho un software di monitoraggio che scansionerà la rete e troverà i dispositivi, ma non è così granulare nei dettagli.

RICERCA FATTA / OPZIONI CONSIDERATE

Non vedo tali possibilità con la registrazione integrata.

Sì, sono a conoscenza di 802.1X e ho la possibilità di implementarlo a lungo termine in questa posizione, ma siamo a un po 'di distanza da un progetto del genere, e mentre ciò risolverebbe i problemi di autenticazione di rete, questo è ancora utile per me al di fuori di obiettivi 802.1X.

Ho cercato alcuni bit di script, ecc. Che potrebbero rivelarsi utili, ma le cose che sto trovando mi portano a credere che il mio google-fu mi stia fallendo al momento.

Credo che la logica di seguito sia corretta ( supponendo che non esista una soluzione esistente ):

  1. Il dispositivo riceve l'indirizzo DHCP
  2. La voce del registro eventi viene registrata (l'ID evento 10 nel registro di controllo DHCP dovrebbe funzionare (poiché un nuovo contratto di locazione è ciò di cui sarei più interessato, non i rinnovi): http://technet.microsoft.com/en-us/library /dd759178.aspx )
  3. A questo punto una sceneggiatura di qualche tipo dovrebbe probabilmente prendere il posto dei rimanenti "PASSI" di seguito.
  4. In qualche modo interrogare questo registro DHCP per questi ID evento 10 (mi piacerebbe spingere, ma immagino che pull sia l'unica risorsa qui)
  5. Analizzare la query per il nome del dispositivo a cui è stato assegnato il nuovo contratto di locazione
  6. Richiesta AD per il nome del dispositivo
  7. Se non trovato in AD, invia un'email di notifica

Se qualcuno ha qualche idea su come farlo correttamente, lo apprezzerei davvero. Non sto cercando un "dammi il codez" ma mi piacerebbe sapere se ci sono alternative all'elenco sopra o se non sto pensando in modo chiaro ed esiste un altro metodo per raccogliere queste informazioni. Se hai frammenti di codice / comandi PS che desideri condividere per aiutarti, tanto meglio.


Stai cercando di bloccarli o semplicemente ricevere una notifica se ottengono un IP?
HostBits

@Cheekaleak - ricevi una notifica.
TheCleaner

Che dire delle stampanti di rete che utilizzano DHCP?
jftuga,

@jftuga: utilizziamo IP statici per le stampanti di rete.
TheCleaner

Risposte:


6

Grazie mille a ErikE e agli altri qui, ho intrapreso una strada ... Non dirò che è la strada giusta, ma lo script di Powershell che ho inventato fa il trucco.

Il codice è sotto se qualcuno lo vuole. Basta eseguirlo manualmente puntando su ciascun server DHCP o programmarlo (di nuovo puntando a ciascun server DHCP nello script).

Cosa fa lo script:

  1. Ottiene informazioni sul lease dal server DHCP (leasing ipv4)
  2. Emette i contratti di locazione in un file CSV
  3. Rileva in quel file CSV per l'interrogazione di AD
  4. Interroga AD per il computer
  5. Se non trovato, restituisce un nuovo file txt
  6. Crea un file txt finale di elenco univoco da quello creato in # 5 sopra (poiché possono esserci duplicati se il client si registra più di una volta o con più di un adattatore)
  7. invia il contenuto del file di output finale a un amministratore

Di cosa hai bisogno:

Lo script utilizza il modulo AD ( import-module activedirectory), quindi è consigliabile eseguirlo su un controller di dominio Active Directory che esegue DHCP. Se questo non è il tuo caso, puoi installare il modulo PowerShell AD: http://blogs.msdn.com/b/rkramesh/archive/2012/01/17/how-to-add-active-directory- module-in-PowerShell-in-finestre-7.aspx

Avrai anche bisogno dei cmdlet di Quest Powershell di AD disponibili qui: http://www.quest.com/powershell/activeroles-server.aspx . Installare QUESTI PRIMA di eseguire lo script o fallirà.

Lo script stesso (sterilizzato, dovrai impostare alcune delle variabili per soddisfare le tue esigenze come i nomi dei file di input, il dominio a cui connettersi, il server dhcp a cui connettersi, le impostazioni e-mail verso la fine, ecc.):

# 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)

Spero che aiuti qualcun altro!


3

OK, non sono sicuro di seguire l'etichetta qui, ma sto postando una seconda risposta invece di modificare la mia precedente, poiché conteneva alcune informazioni che potrebbero essere utili a qualcuno anche se dimostrate irrilevanti per questo caso. Se questo mi rende un idiota in questo forum, sentiti libero di informarmi dei miei modi errati.

Il problema è diviso in più parti, ecco alcuni suggerimenti per quelli che trovo più interessanti. Senza esempi dal registro, questo è il massimo che posso fare, quindi sono solo suggerimenti e non soluzioni.

Per analizzare il registro, utilizzare get-contentcon il -waitparametro Per il mio caso d'uso è sufficiente trovare un errore in un registro errori.

Questo è ciò che ha funzionato per il mio caso d'uso, perdona la formattazione:

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: $_" `
        }

Invece di quello $_ -match "ERROR"dovresti separare in qualche modo il campo ID registro e il nome del computer. Non sono sicuro di come procedere nel migliore dei modi in questo momento, ma dato che where-object -matchoffre supporto regex credo che potrebbe essere un'opzione. Puoi anche iniziare memorizzando la variabile $ _ in un'altra nuova variabile, per poterla raccogliere a tuo piacimento più avanti nella pipeline, all'interno di cicli foreach annidati ecc.

Supponendo che tu possa ottenere dal nomecomputer, suppongo che il get-adcomputercmdlet sarebbe il tuo modo più semplice di interrogare il tuo annuncio (import-module activedirectory ) e immagino che l'errore invii posta?

import-csvOvviamente l'uso del sarebbe molto più elegante nel tuo caso, ma non sono a conoscenza di alcun modo per seguirlo (se qualcuno capisce di leggerlo e conosce un trucco su quel vicolo, per favore, per favore, per favore).


Grazie ErikE, corro con questo e ti faccio sapere. Avrò bisogno di trovare un modo per afferrare le informazioni, interrogare AD, quindi dopo la "segnalazione" ignorare i futuri controlli di quella stessa linea di input. Ad esempio, se interroga il file ogni cinque minuti, non voglio che analizzi le stesse informazioni e invii un avviso dupe ogni 5 minuti.
TheCleaner

Due cose che trovo leggermente ordinate: se lasci semplicemente eseguire lo script, il parametro wait lo farà attendere costantemente che appaia una nuova riga. Non è necessario rieseguire la sceneggiatura. Questo darà un effetto push anziché pull. Inoltre, la coda (1) avrà solo l'analisi dell'ultima 1 riga all'avvio. Pertanto, se il gestore attività rileva che è necessario riavviare lo script e si trova un modo per iniettare una riga di segnaposto che sposta l'ultima riga per attivare un avviso, si sarà disarmato il fastidio degli allarmi.
ErikE

1
Erik, ho trovato un modo per esportare i contratti di locazione dal DHCP (che il 2012 ha un cmdlet PS per esso, ma il 2008 no) in un file CSV. In questo modo non scherzo con i registri di controllo effettivi e non devo preoccuparmi di interrompere nulla con l'input. Inizierò a fare casino con il resto del codice e aggiornerò presto.
TheCleaner

1

Partendo dal presupposto che si è certi dell'ID evento e che nessun altro evento accede a questo ID nel registro DHCP ma quelli a cui si è interessati, push è effettivamente un'opzione.

1) Apri Server Manager, vai al registro DHCP nel Visualizzatore eventi.

2) Trova una voce rappresentativa alla quale desideri allegare la tua azione. Selezionalo e fai clic con il tasto destro.

3) Scegli "Allega attività a questo evento".

4) Si apre la Creazione guidata attività, portala via da lì ...

In realtà esiste un'opzione di posta elettronica esplicita, ma se hai bisogno di più logica di quella, sei ovviamente libero di usare l'opzione di avvio di un programma per avviare powershell.exe e allegare uno script ad esso. Esistono molti ottimi tutorial su Google su come consentire al Task Manager di eseguire script PowerShell se hai bisogno di assistenza.

L'alternativa immediata che vedo è usare pull analizzando il registro eventi usando PowerShell a intervalli programmati. "The Microsoft Scripting Guy", alias Ed Wilson, ha scritto alcuni fantastici post sul blog su come analizzare il registro eventi utilizzando i cmdlet disponibili nelle diverse versioni di PowerShell, quindi prendere il suo blog come punto di partenza sarebbe il mio suggerimento.

Per quanto riguarda i cmdlet effettivi, non ho il tempo di estrarre la mia scorta di frammenti utili, ma ricercherò tra uno o due giorni e potrei contribuire se nessun altro si è presentato con alcuni ben scelti, o tu non hai Non hai risolto tutto da solo :-)


2
Erik, grazie. Il problema qui è che DHCPsrvlog- "giorno" in C: \ windows \ system32 \ DHCP (con controllo DHCP abilitato nella GUI del server DHCP), non scrive in alcun registro del Visualizzatore eventi incluso il registro del Visualizzatore eventi DHCP-Server in Applications and Services Logs(finora basato sulla mia ricerca / test)
TheCleaner

Mi ero dimenticato di quei registri. Ma credo che questo sia un luogo possibile: analizzare il registro di testo usando get-content con le direttive -wait e -tail. Questo è simile alla coda in * nix. Per assicurarsi che un'istanza analizzi sempre il registro, Task Manager può pianificare lo script all'avvio del sistema, quindi avviare ogni (intervallo più breve possibile) ma consentire solo un'istanza in esecuzione. Se il tuo evento viene visualizzato, attiva la logica.
ErikE,

Risulta che ho un simile problema di analisi dei log da risolvere su Windows, pubblicherò i miei risultati su quella particolare parte quando sono sicuro che funzioni, e probabilmente alcuni altri blocchi che ho intorno che dovrebbero essere utili per te. Potresti incollare un paio di righe rappresentative ma offuscate dal tuo registro dhcp? Sono particolarmente interessato al formato del nome del dispositivo.
ErikE,

1

Sebbene ciò non risolva la soluzione desiderata, un'opzione che può raggiungere il tuo obiettivo è quella di utilizzare arpwatch( link ) per avvisarti quando un nuovo host (precedentemente non visto) viene visto sulla rete.

Un'alternativa a Windows arpwatchsembra essere decaffeinatide ma non l'ho mai usata, quindi non posso parlarne in modo positivo o negativo.


Grazie. L'idea è sana. Potrei percorrere quella strada se necessario.
TheCleaner

Il vantaggio aggiuntivo è che ciò catturerebbe anche le nuove macchine che utilizzano IP statici, che non rientrava nel campo di applicazione dichiarato, ma probabilmente dovrebbe esserlo.
mfinni,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.