Powershell : suppression d'enregistrements DNS depuis un import CSV

Ce snippet permet de supprimer les enregistrements DNS à partir d'une liste au format CSV passée en paramètre.

Le script sera appelé de cette manière :

.\win_dns-deletion.ps1 -zone superdomaine.local -csv exportdns.csv

Seuls les enregistrements de type A sont supprimés par ce code ; le paramètre peut se modifier pour cibler un autre type. Par défaut, la commande demande confirmation avant suppression ; le paramètre -Force permet de passer outre cette confirmation. Attention au moment d'exécuter le script.

param([string]$zone, [string]$csv)
$records = Import-CSV $csv
foreach($record in $records){
Remove-DnsServerResourceRecord -ZoneName $zone -RRType "A" -Name $record.Name -Force
}

Powershell : harmonisation de la configuration DNS

Afin d'harmoniser la configuration DNS sur des serveurs situés sur différents sites géographiques, j'ai développé un script Powershell lié à une GPO qui l'exécute au démarrage.

Ce script récupère grâce au nom du serveur son emplacement et applique en fonction de ce dernier les bonnes adresses IP. Naturellement, il faudra adapter l'extraction de l'emplacement dans le nom de la machine en fonction de l'environnement sur lequel le script sera déployé ; de plus, le domaine sur lequel la carte est connectée sert d'identification de la carte réseau employée pour la résolution DNS.

$location = (hostname).Substring(2,3)
switch($location){
"PAR" { $dnslist = '("192.168.1.1","192.168.1.2","192.168.2.1")' }
"BXL" { $dnslist = '("192.168.2.1","192.168.2.2","192.168.1.1")' }
"BER" { $dnslist = '("192.168.3.1","192.168.3.2","192.168.2.1")' }
"LDN" { $dnslist = '("192.168.4.1","192.168.4.2","192.168.3.1")' }
"NYC" { $dnslist = '("192.168.5.1","192.168.1.1","192.168.4.1")' }
}
$cards = Get-NetIPConfiguration
foreach($card in $cards){
if($card.NetProfile.Name -eq "dundermifflin.local") { $index = $card.InterfaceIndex }
}

$query = "Set-DnsClientServerAddress -InterfaceIndex $index -ServerAddresses $dnslist"
Invoke-Expression $query

Ce snippet fonctionne si par exemple mes serveurs ont une nomenclature de nommage comme celle-ci : <OS><Environnement><Emplacement><Rôle><ID>, qui pourrait donner par exemple pour un contrôleur de domaine de production WPLDNDC01 ou un serveur PostgreSQL de recette LRBXLPG03.

Ce script est disponible dans une version commentée sur le miroir de téléchargement.

Powershell : listing d'enregistrements DNS

J'ai développé un (plutôt deux, à vrai dire) script(s) Powershell permettant de remplacer la fonction de filtre présente sur la console DNS. En effet, celle-ci est un peu pénible à utiliser car il faut attendre que toute la zone soit chargée dans la console si le filtre n'est pas encore actif, puis il faut rafraîchir... et il est persistant après fermeture, ce qui fait qu'il faut réinitialiser le filtre et actualiser lorsqu'on souhaite revenir à une vision d'ensemble.

A l'exécution, le script demande le nom ou l'IP du serveur DNS à interroger, ainsi que la chaîne de caractères à trouver dans le nom de l'enregistrement. Le joker * est utilisable, ce qui permet à la fois de rechercher une expression ou une chaîne stricte.

La version basique du script renvoie ses résultats dans la console avec uniquement le nom de l'enregistrement :

Write-Host "=========================================="
Write-Host "DNS records listing script - Basic Version"
Write-Host "=========================================="
$dnsnode = Read-Host "DNS Server to query"
$lfseq = Read-Host "Character sequence to look for ('*' tokens accepted)"
Write-Host "Connecting to DNS Server and retrieving DNS zones"
$dnszones = Get-DNSServerZone -ComputerName $dnsnode | Where-Object {$_.IsReverseLookupZone -eq $false}
foreach($dnszone in $dnszones){
Write-Host "Zone currently parsed:" $dnszone.ZoneName
$dnsrecords = Get-DnsServerResourceRecord -ComputerName $dnsnode -ZoneName $dnszone.ZoneName | Where-Object {$_.HostName -like "$lfseq"} | ft HostName
if($dnsrecords.length -gt 0) { $dnsrecords }
else { Write-Host "No matching records found." }
Write-Host "`r"
}
Write-Host "Parsing over."
Write-Host "Bye."

La version améliorée renvoie les résultats dans la console, mais génère un fichier CSV offrant plus d'informations (type d'enregistrement et données de l'enregistrement) et effectue une suppression des doublons : nécessaire car la commande Powershell peut renvoyer plusieurs fois le même enregistrement si il est dans une sous-zone. Par exemple, en considérant la zone infra.local, si un enregistrement s'appelle sql dans la sous-zone prod, il apparaîtra alors deux fois : une fois en tant que sql.prod et une fois en tant que sql.prod.infra.local.

Write-Host "============================================="
Write-Host "DNS records listing script - Enhanced Version"
Write-Host "============================================="
$dnsnode = Read-Host "DNS Server to query"
$lfseq = Read-Host "Character sequence to look for ('*' tokens accepted)"
$today = Get-Date -f yyyyMMdd
$path = "dns-$today.csv"
$csvheader = "Hostname,Zone,RecordType,RecordData"
Add-Content -Value $csvheader -Path $path
Write-Host "Connecting to DNS Server and retrieving DNS zones"
$dnszones = Get-DNSServerZone -ComputerName $dnsnode | Where-Object {$_.IsReverseLookupZone -eq $false}
foreach($dnszone in $dnszones){
Write-Host "Zone currently parsed:" $dnszone.ZoneName
$dnsrecords = Get-DnsServerResourceRecord -ComputerName $dnsnode -ZoneName $dnszone.ZoneName | Where-Object {$_.HostName -like "$lfseq"}
if($dnsrecords.length -gt 0){
foreach($dnsrecord in $dnsrecords){
Write-Host "Record: "$dnsrecord.Hostname
switch($dnsrecord.RecordType){
"A" {$recorddata = $dnsrecord.RecordData.IPv4Address.IpAddressToString}
"CNAME" {$recorddata = $dnsrecord.RecordData.HostNameAlias}
}
if($dnsrecord.HostName.SubString($dnsrecord.HostName.Length-$dnszone.ZoneName.Length,$dnszone.ZoneName.Length) -ne $dnszone.ZoneName) {
$row = $dnsrecord.Hostname+","+$dnszone.ZoneName+","+$dnsrecord.RecordType+","+$recorddata
Add-Content -Value $row -Path $path
}
}
Write-Host "DNS records found:"$dnsrecords.length
}
else { Write-Host "No matching records found." }
Write-Host "`r"
}
Write-Host "Parsing over, cleaned duplicates, hence the difference between the number of lines in the CSV file and the number displayed in console. Please find the output CSV file named $path in $pwd."
Write-Host "Bye."
explorer $pwd

Ces deux scripts sont téléchargeables dans des versions commentées depuis le serveur grâce aux liens suivants : simple - amélioré

Les VM d'un hôte ESXi ne sont plus à l'heure

Je me suis aperçu d'un dysfonctionnement aujourd'hui alors que j'étais connecté sur deux de mes machines virtuelles sur mon hyperviseur ESXi. En effet, l'heure des deux machines Windows et GNU/Linux étaient en avance de 9 minutes par rapport à l'heure réelle.

Mes machines Windows prennent le temps sur le contrôleur de domaine qui lui même prend le temps sur l'ESX, et mes machines GNU/Linux prennent leur temps sur l'ESX. Etant donné que j'avais le même décalage et qu'une interrogation de w32tm sur ma machine Windows me donnait un retour satisfaisant quant à la synchronisation de l'horloge par rapport à l'un de mes DC, j'en ai déduit que le problème était localisé côté ESX.

En effet, pour une raison inconnue, mes paramètres NTP avaient sauté, et le service était arrêté. J'ai donc ajouté des serveurs NTP sur lesquels se synchroniser, puis j'ai activé le démarrage automatique du service ainsi que le service lui-même :

Mais toujours rien, quelques minutes plus tard je n'obtiens toujours pas d'horloge correcte et le décalage est toujours présent. Je m'interroge donc sur le bon fonctionnement de mes serveurs NTP. J'interroge donc avec watch ntpq mes serveurs de temps, mais cela ne semble pas fonctionner :

En réalité, mon ESXi est incapable de résoudre les noms, ce qui fait que les noms des serveurs NTP ne peuvent être traduits en IP, d'où le dysfonctionnement actuel quant à mes requêtes NTP sur le pool que j'ai choisi. Un coup d'oeil rapide à la liste des règles du firewall me confirme mon impression : le client DNS est bloqué. Une fois le client activé, la résolution DNS se fait bien dans la console.

Une fois la résolution fonctionnelle, je relance par précaution le service NTP avec /etc/init.d/ntpd restart, puis une actualisation dans l'interface web vSphere me confirme que tout est revenu à la normale.

Concernant l'origine de ce dysfonctionnement, j'ai procédé au blocage de quelques règles pare-feu il y a quelques temps, et il est fort probable que je me sois aperçu de la désynchronisation de l'horloge qu'aujourd'hui.