From e7b06258bfd944f9d487f24aae88c837120b27fc Mon Sep 17 00:00:00 2001 From: Nicolas Lang Date: Sun, 17 Dec 2023 01:11:55 +0100 Subject: [PATCH] =?UTF-8?q?Cr=C3=A9ation=20script?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Windows/dhcp_check.ps1 | 689 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 689 insertions(+) create mode 100644 Windows/dhcp_check.ps1 diff --git a/Windows/dhcp_check.ps1 b/Windows/dhcp_check.ps1 new file mode 100644 index 0000000..2b26449 --- /dev/null +++ b/Windows/dhcp_check.ps1 @@ -0,0 +1,689 @@ +#Script créé par Nicolas Lang - Sous licence CC-BY-SA +#https://nicolaslang.fr + + +$scriptPath = $null +$answer = "z" +if ((Get-Host).Version.Major -le 2) +{ + $scriptPath = split-path -parent $MyInvocation.MyCommand.Definition +} +else +{ + $scriptPath = $PSScriptRoot +} +$configfile = Join-Path $scriptPath "config.ini" +try +{ + $configuration = Get-Content $configfile -ErrorAction Stop +} +catch +{ +#region CONFIGFILECREATION + + While($answer.tolower()[0] -ne "y" -and $answer.tolower()[0] -ne "n") + { + $answer = Read-host "Impossible d'accéder au fichier $configfile `nVoulez vous le créer? (Y/N)" + } + if ($answer.ToLower()[0] -eq "n") + { + throw("Fin du script") + } + else + { + #region DHCPPOOLS + $answer = "z" + while($answer.tolower()[0] -ne "y") + { + $ippoolarray = @() + $answer = "z" + Write-Host "Saisissez les plages DHCP, une par ligne. Entrez une ligne vide pour terminer." + do + { + $ippool = "Add_pools" + while($ippool -as [System.Net.IPAddress] -isnot [System.Net.IPAddress] -and $ippool -ne "") + { + $ippool = Read-Host "=>" + } + if ($ippool -ne "") + { + Write-host "$(([System.Net.IPAddress]$ippool).Ipaddresstostring) ajouté!" + $ippoolarray += $ippool + } + }while ($ippool -ne "") + $ippoolarray = $ippoolarray | Sort-Object -Unique + Write-Host "Vous avez choisi les pools suivants :`n" + $ippoolarray + while ($answer.tolower()[0] -ne "y" -and $answer.tolower()[0] -ne "n") + { + $answer = Read-Host "Est-ce correct? (Y/N)" + } + + } + #endregion + #region DHCPSERVERS + $answer = "z" + while($answer.tolower()[0] -ne "y") + { + $dhcpserversarray = @() + $answer = "z" + Write-Host "Saisissez les noms ou ips des serveurs DHCP, un par ligne. Entrez une ligne vide pour terminer." + do + { + $dhcpserver = "Add_server" + while($dhcpserver -ne "") + { + $dhcpserver = Read-Host "=>" + + + if ($dhcpserver -ne "") + { + Write-host "$dhcpserver ajouté!" + $dhcpserversarray += $dhcpserver + } + } + }while ($dhcpserver -ne "") + $dhcpserversarray = $dhcpserversarray | Sort-Object -Unique + Write-Host "Vous avez choisi les serveurs suivants :`n" + $dhcpserversarray + while ($answer.tolower()[0] -ne "y" -and $answer.tolower()[0] -ne "n") + { + $answer = Read-Host "Est-ce correct? (Y/N)" + } + $answertotest = "z" + while ($answertotest.tolower()[0] -ne "y" -and $answertotest.tolower()[0] -ne "n" -and $answer -ne "n") + { + $answertotest = Read-Host "voulez vous tester la connexion aux serveurs? (Y/N)" + } + if ($answertotest.ToLower()[0] -eq "y") + { + $iserror = $false + foreach ($server in $dhcpserversarray) + { + $message = "Succès!" + $color = "Green" + + if (!(Test-Connection $server -Count 1 -Quiet -ErrorAction Stop)) + { + $iserror = $true + $message = "Echec! :c" + $color = "Red" + } + Write-host $server " => " $message -ForegroundColor $color + } + + if ($iserror -eq $false) + { + Write-host "Tous les tests sont passés :)" + } + else + { + Write-Host "Une ou plusieurs erreurs sont arrivées." + do + { + $answer = Read-host "Voulez vous continuer malgré tout? (Y/N)" + }while ($answer.tolower()[0] -ne "y" -and $answer.tolower()[0] -ne "n") + if ($answer.tolower()[0] -eq "n") + { + throw("Vous avez arrêté le script") + } + } + + } + + } + + + #endregion + + #region MAIL + $answertomail = "z" + while($answertomail.ToLower()[0] -ne "y") + { + do + { + Write-Host "Renseignez le nom du SMTP de messagerie" + $mailserver = Read-Host "=>" + Write-Host "Renseignez l'adresse de l'EXPEDITEUR" + $from = Read-Host "=>" + Write-Host "Renseignez l'adresse du DESTINATAIRE" + $to = Read-Host "=>" + $mailconfiguration = [pscustomobject]@{ + "Mailserver"=$mailserver + "From" = $from + "To" = $to + } + $mailconfiguration | ft + $answertomail = Read-Host "Est-ce correct? (Y/N)" + }while($answertomail.ToLower()[0] -ne "y" -and $answertomail.ToLower()[0] -ne "n") + $answertosendmail = "z" + $mailreceived = "z" + if ($answertomail.ToLower()[0] -eq "y") + { + while($answertosendmail -ne "n") + { + do + { + $answertosendmail = Read-Host "Voulez vous envoyer un mail de test? (Y/N)" + } while($answertosendmail.ToLower()[0] -ne "y" -and $answertosendmail.ToLower()[0] -ne "n") + if ($answertosendmail.ToLower()[0] -eq "y") + { + $sendmailerror = $false + try + { + Send-MailMessage -From $from -To $to -Subject "Test mail du script Powershell" -SmtpServer $mailserver + } + catch + { + $sendmailerror = $true + Write-host "Une erreur s'est produite durant l'envoi du mail!" + } + if ($sendmailerror -eq $false) + { + do + { + $mailreceived = read-host "Le mail a été envoyé. L'avez vous recu? (Y/N)." + }while ($mailreceived.ToLower()[0] -ne "y" -and $mailreceived.ToLower()[0] -ne "n") + if ($mailreceived.ToLower()[0] -eq "n") + { + do + { + $answertomail = Read-Host "Voulez vous continuer et reconfigurer? (Y/N)" + }while ($answertomail.ToLower()[0] -ne "y" -and $answertomail.ToLower()[0] -ne "n") + switch ($answertomail.tolower()[0]) + { + "y" { $answertomail = "n";$answertosendmail = "n" } + "n" { throw("Impossible d'envoyer le mail. Arrêt du script") } + } + } +else + { + $answertosendmail = "n" + } + } + + } + } + } + } + #endregion + #region CHEMIN + $answer = "z" + $path = $null + do + { + do + { + $path = Read-Host "Entrez un chemin (local ou UNC) pour l'enregistrement des données du script`n=>" + $answerpathtest = Read-Host "Voulez vous tester le chemin :`n$path`n(Y/N) =>" + } until ($answerpathtest.ToLower()[0] -eq "y" -or $answerpathtest.ToLower()[0] -eq "n") + if ($answerpathtest -eq "y") + { + $answerpathretry = "z" + if (Test-Path $path) + { + + Write-host -ForegroundColor Green "Le chemin est valide.`nTest d'écriture." + $testfilename = [string](get-date).Ticks+".test" + $answer = "y" + try + { + New-Item -ItemType File (Join-Path $path $testfilename) -Force + } + catch + { + Write-Host "Impossible d'écrire dans $path `nVeuillez selectionner un autre dossier." + $answer = "z" + } + Remove-Item (Join-Path $path $testfilename) -Force -ErrorAction SilentlyContinue + } + else + { + do + { + Write-Host "La destination n'existe pas. Voulez-vous la créer? (Y/N)" + $answerpathretry = Read-Host "=>" + } until ($answerpathretry.ToLower()[0] -eq "y" -or $answerpathretry.ToLower()[0] -eq "n") + if ($answerpathretry.ToLower()[0] -eq "n") + { + throw("Arrêt du script") + } + $answer = "z" + + } + } + + } until ($answer.ToLower()[0] -eq "y" -or $answer.ToLower()[0] -eq "n") + $answer = "z" + do + { + $answer = Read-Host "Voulez vous surveiller les réservations DHCP également? (Y/N)" + } until($answer.ToLower()[0] -eq "y" -or $answer.ToLower()[0] -eq "n") + #endregion + $dhcprescheck = $true + if ($answer.ToLower()[0] -eq "n") + { + $dhcprescheck = $false + } + } + + try + { + $configurationarray = New-Object PSCUSTOMOBJECT + $configurationarray | Add-Member -Name pools -MemberType NoteProperty -Value $ippoolarray + $configurationarray | Add-Member -name servername -MemberType NoteProperty -Value $dhcpserversarray + $configurationarray | Add-Member -Name mailconfiguration -MemberType NoteProperty -Value $mailconfiguration + $configurationarray | Add-Member -Name path -MemberType NoteProperty -Value $path + $configurationarray | Add-Member -Name rescheck -MemberType NoteProperty -Value $dhcprescheck + } + catch + { + Write-Host -ForegroundColor Red "Une erreur s'est produite durant l'assemblage des infos de configuration. Voici l'état actuel de l'objet représentant la configuration :`n$configurationarray" + } + try + { + $configurationarray | Export-Clixml $configfile -ErrorAction Stop + } + catch + { + Write-Host -ForegroundColor Red "Impossible d'enregistrer le fichier de configuration. Le script va s'arrêter" + } +#endregion +} #end catch + +$configurationarray = Import-Clixml $configfile -ErrorAction Stop + +#region fichiers + + #Précisez le chemin du fichier ou seront sauvegardées les données des PC détectés +$path = $configurationarray.path +$filename = "outsidedomain.xml" #Nom a donner au fichier. +$staticfile = "staticaddress.xml" #Nom a donner au fichier. +$exceptionfile = "exceptions.txt" #Nom du fichier d'exceptions +$exceptionpath = Join-Path $path $exceptionfile +$fullpath = Join-Path $path $filename +$staticpath = Join-Path $path $staticfile +$dateforcsv = Get-Date -Format "yyyy_MM" +#endregion + +#region DHCP +$plages = $configurationarray.pools #Plage(s) à surveiller +$servername = $configurationarray.servername #nom de serveur(s) DHCP +#endregion + +#region MAIL +$from = $configurationarray.mailconfiguration.From #Adresse mail de l'expéditeur +$to = $configurationarray.mailconfiguration.To #Adresse mail du destinataire +$smtpserver = $configurationarray.mailconfiguration.Mailserver #Serveur SMTP + +$encoding = [System.Text.UTF8Encoding]::UTF8 #Encodage en UTF8 pour éviter les problèmes d'accents, entre autre +#endregion + +#region jobs +$maximaljobperserver = 4 +#endregion + +#region variables +try +{ + Import-module ActiveDirectory +} +catch +{ + Write-host "Impossible de charger le module Active Directory pour Powershell. Ce module est-il bien installé et activé?" + Start-Sleep -Seconds 5 + throw("No AD Module") +} +$computerlist = Get-ADComputer -filter * +$arraylist = New-Object System.Collections.ArrayList +$notindomainarraylist = New-Object System.Collections.ArrayList +$resultingarray = New-Object System.Collections.ArrayList +$staticresults = New-Object System.Collections.ArrayList +$staticmodified = New-Object System.Collections.ArrayList + +$monitorstatic = $true +#endregion + +function Report-StaticChange { +param( +[string]$Raison = "non spécifiée", +[string]$NewIP = $null, +[string]$OldIP = $null, +[string]$NewMAC = $null, +[string]$OldMAC = $null) + + + $staticmodified.Add([pscustomobject]@{ + "Raison" = $Raison + "Nouvelle_IP" = $NewIP + "Ancienne_IP" = $OldIP + "Nouvelle_MAC" = $NewMAC + "Ancienne_MAC" = $OldMAC}) | Out-Null + +} + +try { + $staticresultsprevious = Import-Clixml $staticpath +} +catch +{ + "Aucun fichier précedent d'IP reservées" +} +try{ + $exceptions = Get-content $exceptionpath -erroraction stop +} +catch +{ + Try + { + New-Item -ItemType File $exceptionpath -Force + } + catch + { + "Impossible de créer le fichier d'exception. Arrêt du script" + Start-Sleep -Seconds 5 + throw("STOP FICHIER EXCEPT.") + } +} + +try +{ + $fichiernondomaine = Import-Clixml $fullpath +} +catch +{ + Write-Output "Aucun fichier de précedence à $fullpath, vérification du chemin." + if (!(Test-Path $fullpath)) + { + + Write-Output "Chemin inexistant, création du fichier" + try + { + New-Item -ItemType File $fullpath -Force -ErrorAction Stop + } + catch + { + Write-Output "Impossible de créer le fichier, arret du script." + Start-Sleep -Seconds 5 + throw($error[0].Exception) + } + } +} + + +foreach($plage in $plages) +{ + foreach ($server in $servername) + { + if ($monitorstatic -eq $true) + { + if ((get-job -Name "$server*" | Where-Object {$_.state -eq "Running"}).count -ge $maximaljobperserver) + { + Write-Output "Plus de $maximaljobperserver jobs actifs sur $server. En attente de la libération de jobs." + + do + { + Start-Sleep -Seconds 1 + } while ((get-job -Name "$server*" | Where-Object {$_.state -eq "Running"}).count -ge $maximaljobperserver) + } + + Start-Job -Name $($server+"_"+$plage+"_static") -ScriptBlock { + param($plage,$server) + $jobstaticresults = New-Object System.Collections.ArrayList + $staticstats = Invoke-Command -computername $server -scriptblock {powershell.exe "chcp 1252;Netsh dhcp server scope $($args[0]) show reservedip"} -ArgumentList $plage + foreach ($entry in $staticstats) + { + if ($entry.trim() -match "(?\d+.\d+.\d+.\d+)\W+-\W+(?\w+-\w+-\w+-\w+-\w+-\w+)") + { + $jobstaticresults.Add([PSCUSTOMOBJECT]@{ + "IP" = $Matches.IP + "MAC" = $Matches.MAC + }) | Out-Null + } + } + return $jobstaticresults + } -ArgumentList $plage,$server #end start-job + } #end if ($monitostatic -eq $true) + if ((get-job -Name "$server*" | Where-Object {$_.state -eq "Running"}).count -ge $maximaljobperserver) + { + Write-Output "Plus de $maximaljobperserver jobs actifs sur $server. En attente de la libération de jobs. (leases)" + + do + { + Start-Sleep -Seconds 1 + } while ((get-job -Name "$server*" | Where-Object {$_.state -eq "Running"}).count -ge $maximaljobperserver) + } + + Start-Job -Name $($server+"_"+$plage+"_leases") -ScriptBlock { + param($plage,$server) + $jobarraylist = New-Object System.Collections.ArrayList + $stats = Invoke-Command -computername $server -scriptblock {powershell.exe "chcp 1252;Netsh dhcp server scope $($args[0]) show clients 1"} -ArgumentList $plage + foreach ($entry in $stats) + { + + if ($entry.trim() -match "(?\d+.\d+.\d+.\d+.)\W+-\W+(?\d+.\d+.\d+.\d+.).*?[^\w+](?\w+-\w+-\w+-\w+-\w+-\w+).*?[^\d+](?\d+/\d+/\d+\s+\d+:\d+:\d+).*?[^\w+](?\w+).*?[^\w+](?\w+.*)$") + { + $jobarraylist.Add([pscustomobject]@{ + "IP" = $Matches.ip + "Masque" = $Matches.MASQUE + "MAC" = $Matches.MAC + "PC" = $Matches.PC + "Type" = $Matches.TYPE + "Date" = (get-date $Matches.Bail ) + }) | Out-Null + + } + } + return $jobarraylist + } -ArgumentList $plage,$server #end start-job + } +} +Get-job | Wait-Job +$joblist = Get-Job | Where-Object {$_.State -eq "Completed"} +Write-Output "Obtention des résultats d'IP statiques" + foreach ($job in ($joblist |Where-Object {$_.name -like "*static"})) + { + $value = Receive-Job $job + if ($value -ne $null) + { + try + { + $staticresults.AddRange($value) | Out-Null + } + catch + { + try + { + $staticresults.Add($value) | Out-Null + } + catch + { + Write-Output "Erreur lors de l'ajout des données du job $($job.name) avec comme valeur $($value)" + } + } + } + Remove-Job $job + } +$joblist = Get-Job + + +foreach ($job in $joblist) +{ + $value = Receive-Job $job + if ($value -ne $null) + { + try{ + $arraylist.AddRange($value) | Out-Null + } + catch + { + try + { + $arraylist.Add($value) | Out-Null + } + catch + { + Write-Output "Erreur sur l'ajout de données du job $($job.name) avec comme valeur $($value)" + } + } + + } + Remove-Job $job -ErrorAction stop +} + +foreach ($job in Get-Job) +{ + Write-Output "Erreur sur $job. $Job.state" + Receive-Job $job +} + +foreach ($computer in $arraylist) +{ + $results = $arraylist | Where-Object {$_.pc -eq $computer.PC} + foreach ($result in $results) + { + if ($computerlist.dnshostname -notcontains $result.pc) + { + "$($result.pc) N'EST PAS CONNU DANS L'AD." + $notindomainarraylist.Add($result) | Out-Null + } + + } + +} +#Filtrage en fonction des exceptions. Ne garder que ce qui n'a pas d'adresse mac et de nom correspondant à la liste. +$notindomainwithexceptions = $notindomainarraylist | Where-Object {$_.MAC -notin $exceptions -and $_.PC -notin $exceptions} + +if ($fichiernondomaine -ne $null) +{ + foreach ($computer in $notindomainwithexceptions) + { + if ($fichiernondomaine.pc.contains($computer.pc)) + { + + #Recherche du pc X avec l'adresse mac Y + $results = $fichiernondomaine | Where-Object {$_.pc -eq $computer.pc -and $_.MAC -eq $computer.MAC} | Sort-Object -property ip,date -Unique + if ($results -eq $null) + { + "results eq null" + #L'ordinateur est trouvé, mais sous une autre carte réseau + $index = $notindomainwithexceptions.pc.IndexOf($computer.pc) #changé $_.pc en $computer.pc + $item = $notindomainwithexceptions[$index] + $item | Add-Member -MemberType NoteProperty -Name "Raison" -Value "Nouvelle carte réseau" -force + $resultingarray.Add($item) | Out-Null + } + elseif ($results.ip -contains $computer.ip) + { + + #L'ordinateur est trouvé dans le DHCP, on vérifie si le bail expire à la même date. + + #On filtre uniquement sur l'objet ayant la même adresse que l'ordinateur + + $item = $results | Where-Object {$_.ip -eq $computer.ip} + + if ($computer.Date -gt $item.Date) + { + #La valeur date est plus grande, il a donc eu un renouvellement de bail + $item | Add-Member -MemberType NoteProperty -Name "Raison" -Value "Renouvellement du bail DHCP" -Force + $resultingarray.Add($item) | Out-Null + } + #Sinon, on enregistre pas, on avertit pas. + + } + } + else + { + #Si le fichier xml importé ne comporte pas l'ordinateur, c'est donc une nouvelle connexion + $item = $computer + $item | Add-Member -MemberType NoteProperty -Name "Raison" -Value "Nouvelle connexion" -Force + $resultingarray.Add($item) | Out-Null + + } + } + + $notindomainarraylist | Export-Clixml $fullpath + + if ($resultingarray -ne $null) + { + $resultingarray = $resultingarray | Select-object -property IP,Masque,Mac,PC,Type,Date,Raison + Send-MailMessage -From $from -To $to -Subject "Nouvelles connexions détectées" -Bodyashtml $([string]($resultingarray | ConvertTo-Html -PreContent "Type : N - AUCUN, D - DHCP B - BOOTP, U - NON SPÉCIFIÉ, R - RÉSERVATION IP" -Head "")) -Encoding $encoding -SmtpServer $smtpserver + $resultingarray | Export-Csv (join-path $configurationarray.path $("out_domain_"+ $dateforcsv +".csv")) -NoTypeInformation -Append -Delimiter ";" -Encoding UTF8 + } +} +else +{ + Write-Output "Aucun fichier de précedence du DHCP trouvé. Enregistrement des données actuelles en tant que reference" + $notindomainarraylist | Export-Clixml $fullpath + Send-MailMessage -From $from -To $to -Subject "Première analyse faite. Surveillance de ces entrées." -Bodyashtml $([string]($notindomainwithexceptions | ConvertTo-Html -PreContent "Type : N - AUCUN, D - DHCP B - BOOTP, U - NON SPÉCIFIÉ, R - RÉSERVATION IP" -Head "")) -Encoding $encoding -SmtpServer $smtpserver + + +} + +#Gestion des IP Statiques +if ($monitorstatic -eq $true) +{ + $staticresults = $staticresults | Select-object -property IP,MAC | Sort-Object -Property "ip","mac" -Unique + if ($staticresultsprevious -eq $null) + { + Write-Output "Aucun fichier de précedence des réservations trouvé. Enregistrement des données actuelles en tant que reference" + $staticresults | Export-Clixml $staticpath + } + else + { + foreach ($entry in $staticresults) + { + #Si l'ip est bien dans la liste des résultats précedents... + if ($entry.ip -in $staticresultsprevious.ip) + { + #On reprends l'objet de la fois précedente... + $check = $staticresultsprevious | Where-Object {$_.ip -eq $entry.ip} + #Si leurs macs différent, l'adresse mac a été changée + if ($entry.MAC -ne $check.MAC) + { + "Mac." + Report-StaticChange -Raison "Mac Changée" -OldIP $check.ip -NewIP $entry.ip -OldMAC $check.mac -NewMAC $entry.MAC + + } + } + #Si l'ip n'est pas dans la liste des résultats précédents + #MAIS que la MAC y est... L'IP a donc changé + elseif ($entry.mac -in $staticresultsprevious.mac) + { + "ip" + $check = $staticresultsprevious | Where-Object {$_.mac -eq $entry.mac} + Report-StaticChange -Raison "IP Changée" -OldIP $check.ip -NewIP $entry.ip -OldMAC $check.mac -NewMAC $entry.MAC + + } + #Si ni MAC ni IP, alors c'est une nouvelle entrée + else + { + "new" + Report-StaticChange -Raison "Nouvelle entrée" -OldIP $null -NewIP $entry.ip -NewMAC $entry.MAC + } + + } + #On loop et vérifie que chaque ancien résultat est toujours présent pour s'assurer que rien n'est supprimé + foreach ($staticresultprevious in $staticresultsprevious) + { + #Si l'IP n'est pas dans la liste actuelle, et que la MAC n'est pas dans la liste actuelle + if ($staticresultprevious.ip -notin $staticresults.ip -and $staticresultprevious.mac -notin $staticresults.mac) + { + #On regarde si l'adresse et la mac ne sont pas dans les dernières détections de changement MAC / IP + #afin de ne pas marquer une entrée comme retirée alors qu'elle est simplement modifiée + if ($staticresultprevious.ip -notin $staticmodified.ip -or $staticresultprevious.mac -notin $staticmodified.mac) + { + Report-StaticChange -Raison "Entrée retirée" -OldIP $null -NewIP $staticresultprevious.ip -NewMAC $staticresultprevious.MAC + } + } + + } + $staticresults | Export-Clixml $staticpath + if ($staticmodified.Count -gt 0) + { + Send-MailMessage -From $from -To $to -Subject "Modifications des reservations DHCP" -Bodyashtml $([string]($staticmodified | ConvertTo-Html -PreContent "Liste des modifications détectées sur les réservations du DHCP" -Head "")) -Encoding $encoding -SmtpServer $smtpserver + $staticmodified | Export-Csv (join-path $configurationarray.path $("reserved_changed_"+ $dateforcsv +".csv")) -NoTypeInformation -Append -Delimiter ";" -Encoding UTF8 + + } + } +} +