VMware: VM löschen samt DNS, DHCP und Active Directory
Aktuell entwickeln wir eine Automatisierungslösung, die künfig den namen "ADDY" tragen soll, was für "Admins Buddy" steht. Die Lösung soll es ermöglichen Tasks automatisiert nach Vorgabe anzusteuern und auszuführen.
Ein entscheidender Teil davon ist natürlich das Lifecycle-Management von virtuellen Maschinen. Denn irgendwann ist bei jeder viruellen Maschine die Lebenszeit vorbei und dann muss alles abgebaut bzw. deprovisioniert werden. Häufig vergisst man dabei DNS A Records zu löschen, hinterlässt eine DHCP Reservierung, die dazu beiträgt, dass die DHCP Range immer voller wird und das Computerobject im Active Directory liegt ohne Aufgabe rum.
Der folgende Auszug aus einem Powershell Script (Voraussetzung ist die PowerCLI von VMware) soll es einem ermöglichen, über ADDY VMs und Komponenten wie AD, DNS und DHCP aufzuräumen. Das ausführen des Powershell Snippets erfolgt auf eigene Gefahr. Bitte berücksichtigt, dann das hier nur ein Ausszug aus dem kompletten Workflow ist. Themen wir Zugriff auf Benutzerebene geben wir hier natürlich nicht bekannt.
#initialize Data
$VMname = "vmtodelete" #this is the VM name in vSphere
$debugScript = 1 #this will give you some time, to read the outputs
write-host "Cleanup VMware vSphere VM: $VMname"
write-host "Cleanup DNS, DHCP, Active Directory"
if ($debugScript -eq 1) { start-sleep 5 }
#read VM data (Name, IP und MAC ermitteln)
write-host "Checking the credentials. "
######getting the credentials for a different account
#HERE IS THE PART WHERE YOU SHOULD DO SOMETHING TO GET YOUR CREDENTIALS
$vcentercreds = New-Object System.Management.Automation.PSCredential -ArgumentList $credUsername,$credPassword
$VCenterServer = $TYPEINYOURVCENTERINFQDN
try {
$connectViServer = Connect-VIServer $VCenterServer -Credential $vcentercreds
$ErrorMessage = ""
}
catch {
$ErrorMessage = "ErrorMessage: "+$Error[0]
}
finally {
if ($connectViServer -eq $NULL) {
write-host "Login to vCenter not successfully" -f red
write-host "ErrorMessage: $ErrorMessage"
} else {
write-host "Login to vCenter successfully" -f green
}
}
if ($debugScript -eq 1) { start-sleep 5 }
write-host "Get some information about the VM $VMname" -f DarkYellow
$VMelement = Get-VM -name $VMname | Select-Object *, @{N="IP Address";E={@($_.guest.IPAddress[0])}},@{N="DnsName"; E={$_.ExtensionData.Guest.Hostname}}
$vmNetAdapterData = Get-NetworkAdapter -vm $VMname
$tryToGetIPviaDNS = $false
if ($VMelement.PowerState -eq "PoweredOff") {
write-host "The Machine is offline. Cannot fetch the IP Address from VM data"
$tryToGetIPviaDNS = $true
} else {
write-host "IP: $($VMelement.'IP Address')" -f Yellow
if ($($VMelement.'IP Address') -as [IPAddress] -as [Bool]) {
write-host "IP Address is valid"
write-host "Saving IP Address to variable"
$VMipAddress = $($VMelement.'IP Address')
write-host "DNS Name: $($VMelement.DnsName)"
} else {
write-host "IP Address is not valid. "
}
}
write-host "MAC-Address: $($vmNetAdapterData.MacAddress)" -f DarkYellow
write-host "NetworkName: $($vmNetAdapterData.NetworkName)" -f DarkYellow
write-host "NumCpu: $($VMelement.NumCpu)" -f DarkYellow
write-host "MemoryGB: $($VMelement.MemoryGB)" -f DarkYellow
write-host "HardDisks Count: $($VMelement.HardDisks.Count)" -f DarkYellow
if ($tryToGetIPviaDNS -eq $true) {
write-host "Trying to get the IP Address via DNS"
$DNSresolveRecord = Resolve-DnsName -Name $VMname -ErrorAction 0 #$VMname
if ($DNSresolveRecord) {
write-host "DNS exists"
$VMipAddress = $DNSresolveRecord.IPAddress
$DeleteDNSRecord = $true
} else {
write-host "DNS Resolve failed"
$DeleteDNSRecord = $false
}
}
if ($debugScript -eq 1) { start-sleep 5 }
#shutdown the vm if the VM is up
if ($VMelement.PowerState -eq "PoweredOn") {
write-host "The VM is running. I will shutdown the VM..."
Get-VM -name $VMname | Shutdown-VMGuest -Confirm:$false
$maxTries = 20
for ($i = 1; $i -lt $maxTries; $i++) {
write-host "Checking VM status... "
if ($(Get-VM -name $VMname).PowerState -eq "PoweredOff") {
write-host "VM powered off"
$i = $maxTries
} else {
write-host "VM is not powered off yet"
write-host "current VM power state: $($(Get-VM -name $VMname).PowerState)"
start-sleep 5
}
}
#check, if the machine is really down
if ($(Get-VM -name $VMname).PowerState -ne "PoweredOff") {
write-host "the $VMname is not powered off. " -f red
write-host "PowerState: $($(Get-VM -name $VMname).PowerState)" -f red
start-sleep 2
write-host "If there is a human how read THIS... You have now 50 seconds to shutdown the VM with your stuff. Why? I should delete only VMs with the power state off." -f darkyellow
start-sleep 50
}
if ($(Get-VM -name $VMname).PowerState -ne "PoweredOff") {
write-host "The VM $VMname has already an power state unlike PoweredOff." -f red
write-host "PowerState: $($(Get-VM -name $VMname).PowerState)" -f red
write-host "I will abort the next steps"
$errorCount++
} else {
write-host "The VM $VMname is powered off right now. Puh." -f green
}
}
if ($VMelement.PowerState -eq "PoweredOff") {
write-host "The VM is already down. Go ahead."
}
if ($debugScript -eq 1) { start-sleep 5 }
###################################################### START: DNS DELETE A RECORD AND PTR #################################################
#DNS - Remove DNS A Record
if ($DeleteDNSRecord -eq $true) {
write-host "Remove the DNS Record"
write-host "IPAddress: $($VMipAddress )"
write-host "Checking credentials."
######getting the credentials for a different account
#HERE IS THE PART WHERE YOU SHOULD DO SOMETHING TO GET YOUR CREDENTIALS
$dnscreds = New-Object System.Management.Automation.PSCredential -ArgumentList $credUsername,$credPassword
if ($debugScript -eq 1) { start-sleep 5 }
$resultInvoke = Invoke-Command -scriptblock {
param($VMname,$VMipAddress)
$DNSerrorCount = 0; $returnArray = @();
$RecordName = $VMname
$DNSServer = $PUTHEREYOURDNSSERVERFQDN
$ZoneName = $PUTHEREYOURZONE
$errorMessages = ""
$NodeARecord = Get-DnsServerResourceRecord -ZoneName $ZoneName -ComputerName $DNSServer -Name $RecordName -ErrorAction SilentlyContinue
if ($NodeARecord.RecordData.IPv4Address.IPAddressToString -eq $VMipAddress) {
write-Output "IP Check successfully"
} else {
write-Output "IP Check not successfully"
$errorMessages += "IP Check not successfully" #further with `n
$DNSerrorCount++
}
if ($DNSerrorCount -eq 0) {
if($NodeARecord){
Remove-DnsServerResourceRecord -ZoneName $ZoneName -ComputerName $DNSServer -InputObject $NodeARecord -Force #-whatif:$bTest
Write-Output "A record deleted: $($NodeARecord.HostName)"
} else {
write-Output "No record found"
}
} else {
write-output "Some errors occured. I dont delete the A record"
}
#And now the PTR
if ($DNSerrorCount -eq 0) {
if ($NodeARecord){
$IPAddress = $NodeARecord.RecordData.IPv4Address.IPAddressToString
$IPAddressArray = $IPAddress.Split(".")
$IPAddressFormatted = ($IPAddressArray[3]+"."+$IPAddressArray[2])
$ZonePrefix = ($IPAddressArray[1]+"."+$IPAddressArray[0])
$ReverseZoneName = "$ZonePrefix`.in-addr.arpa"
$NodePTRRecord = Get-DnsServerResourceRecord -ZoneName $ReverseZoneName -ComputerName $DNSServer -Node $IPAddressFormatted -RRType Ptr -ErrorAction SilentlyContinue
if($NodePTRRecord -eq $null){
Write-Output "No PTR record found"
} else {
Remove-DnsServerResourceRecord -ZoneName $ReverseZoneName -ComputerName $DNSServer -InputObject $NodePTRRecord -Force #-WhatIf:$bTest
Write-Output "PTR Record Deleted: $($IPAddressFormatted)"
write-Output "Reverse Zone: $ReverseZoneName"
}
} else {
Write-Output "No record for $RecordName found at $DNSServer"
}
} else {
write-output "Some errors occured. I dont delete the PTR Record"
}
#return the errors
$returnArray = @{
'errorMessages' = $errorMessages
'DNSerrorCount' = $DNSerrorCount
}
return $returnArray
} -ArgumentList @($VMname,$VMipAddress) -ComputerName $DNSServer -Credential $dnscreds # -Session $DNSpssession
if ($resultInvoke.DNSerrorCount -eq 0) {
write-host "DNS Record (A Record and PTR Record) cleanup successfully"
} else {
write-host "DNS not successfully. $($resultInvoke.errorMessages)"
}
if ($debugScript -eq 1) { start-sleep 10 }
}
###################################################### END: DNS DELETE A RECORD AND PTR #################################################
###################################################### START: AD DELETE COMPUTER OBJECT #################################################
#deleting computerobject if exists
write-host "Cleanup Active Directory"
if ($debugScript -eq 1) { start-sleep 5 }
$ADcomputerObject = $NULL
try{
$ADcomputerObject = Get-ADComputer $VMname -ErrorAction Stop
write-host "Computer object exists"
}
catch{
write-host "Computer object does not exists"
}
if ($ADcomputerObject -ne $NULL) {
write-host "The following object will be deleted from the Active Directory"
write-host $ADcomputerObject
start-sleep 5
if ($ADcomputerObject.DNSHostName -like "$($VMname).*") {
write-host "The Computerobject DNShostname contains the Hostname of the VM"
} else {
write-host "The Computerobject DNS Hostname is not like the VM Hostname. Thats not good"
$errorCount++
}
if ($errorCount -eq 0) {
write-host "The computer object will be delete in 3 seconds"
$ADcomputerObject
if ($debugScript -eq 1) { start-sleep 8 }
Remove-ADComputer -Identity $ADcomputerObject -Credential $dnscreds -Confirm:$false
write-host "... delete done"
}
} else {
write-host "There is nothing to delete"
}
if ($debugScript -eq 1) { start-sleep 5 }
###################################################### END: AD DELETE COMPUTER OBJECT #################################################
###################################################### START: DHCP DELETE RESERVATION #################################################
write-host "Cleanup DHCP reservation"
write-host "Checking credentials."
######getting the credentials for a different account
#HERE IS THE PART WHERE YOU SHOULD DO SOMETHING TO GET YOUR CREDENTIALS
$dhcpcreds = New-Object System.Management.Automation.PSCredential -ArgumentList $credUsername,$credPassword
if ($debugScript -eq 1) { start-sleep 5 }
$dhcpErrorCount = 0
$pgVMvlan = $vmNetAdapterData.NetworkName
$VMvlan = #DO HERE SOME THINGS TO GET YOUR VLAN#
$DHCPscopeArray = Invoke-Command -scriptblock {
Get-DhcpServerv4Scope -ComputerName $YOURDHCPSERVERFQDN
} -ComputerName $YOURDHCPSERVERFQDN -Credential $dhcpcreds
$DHCPscopeElement = $DHCPscopeArray | Where-Object {$_.Name -eq $VMvlan}
if ($debugScript -eq 1) { start-sleep 5 }
if ($DHCPscopeElement -eq $NULL) {
write-host "There is no DHCP-Scope with the name $VMvlan" -f Red
$dhcpErrorCount++;
} else {
write-host "DHCP-Scope $VMvlan found" -f darkyellow
write-host "Name: $($DHCPscopeElement.Name)" -f DarkYellow
write-host "ScopeId: $($DHCPscopeElement.ScopeId)" -f DarkYellow
write-host "SubnetMask: $($DHCPscopeElement.SubnetMask)" -f DarkYellow
write-host "State: $($DHCPscopeElement.State)" -f DarkYellow
write-host "StartRange: $($DHCPscopeElement.StartRange)" -f DarkYellow
write-host "EndRange: $($DHCPscopeElement.ScopeId)" -f DarkYellow
write-host "ScopeId: $($DHCPscopeElement.EndRange)" -f DarkYellow
write-host "LeaseDuration: $($DHCPscopeElement.LeaseDuration)" -f DarkYellow
}
if ($debugScript -eq 1) { start-sleep 5 }
if ($dhcpErrorCount -eq 0) {
$scopeId = $DHCPscopeElement.ScopeId
write-host "ScopeId identified: $scopeId "
} else {
write-host "Some errors occured when I taking some DHCP actions..."
}
if ($debugScript -eq 1) { start-sleep 10 }
#go ahead and check the reservation
write-host "I will now check, if there is an reservation" -f DarkYellow
$DHCPgetReservationResult = Invoke-Command -scriptblock {
param($VMipAddress,$scopeId)
$currentDHCPreservationData = Get-DhcpServerv4Lease -ComputerName $YOURDHCPSERVERFQDN -IPAddress $VMipAddress -ErrorAction SilentlyContinue
$currentDHCPreservationData #send the return
} -ComputerName "$YOURDHCPSERVERFQDN" -Credential $dhcpcreds -ArgumentList @($VMipAddress,$scopeId)
write-host "Checking the DHCP result" -f DarkYellow
if ($DHCPgetReservationResult -eq $NULL) {
write-host "There is no DHCP Reservation or Lease for this IP" -f DarkYellow
start-sleep 3
} else {
write-host "There is a result" -f DarkYellow
start-sleep 1
$DHCPgetReservationResult
if ($debugScript -eq 1) { start-sleep 5 }
write-host "Checking if the hostname sounds equal."
if ($DHCPgetReservationResult.HostName -like "*$VMname*") {
write-host "The hostname from the DHCP reservation is ($($DHCPgetReservationResult.HostName)) and contains the hostname from the VM ($VMname)" -f DarkYellow
} else {
write-host "the hostname from the DHCP reservation is ($($DHCPgetReservationResult.Hostname)) and DO NOT contains the hostname from the VM ($VMname)" -f Red
#send a warning to ADDY
}
if ($debugScript -eq 1) { start-sleep 5 }
write-host "Checking if the MAC-Address is the same (DHCP Reservation to VM) ." -f DarkYellow
#convert the address to check
# MAC Address
$dhcpreservationMacAddress = $DHCPgetReservationResult.ClientId
# Delimiter in the current MAC address
$DhcpReservationDelimiter = "-"
$dhcpreservationMacAddress = $dhcpreservationMacAddress -replace "$DhcpReservationDelimiter","" #$vmMacAddress = $vmMacAddress -replace "$Delimiter",""
Write-Host "DHCP Reservation MAC Address: "$dhcpreservationMacAddress -f DarkYellow
#convert the MAC address vom the VM
$Delimiter = ":" # Delimiter in the current MAC address
$vmMacAddress = $vmNetAdapterData.MacAddress -replace "$Delimiter","" #$vmMacAddress = $vmMacAddress -replace "$Delimiter",""
Write-Host "VMware MAC Address: "$vmMacAddress -f DarkYellow
if ($debugScript -eq 1) { start-sleep 5 }
if ($dhcpreservationMacAddress -eq $vmMacAddress) {
write-host "The MAC Adresses are equal. " -f DarkYellow
$DHCPdeleteresult = Invoke-Command -scriptblock {
param($VMipAddress)
$returnRemove = Remove-DhcpServerv4Reservation -ComputerName $YOURDHCPSERVERFQDN -IPAddress $VMipAddress
$returnRemove
} -ComputerName "$YOURDHCPSERVERFQDN" -Credential $dhcpcreds -ArgumentList @($VMipAddress)
$DHCPdeleteresult
write-host "DHCP Reservation delete successfully"
} else {
write-host "The MAC Addresses are not the same. I will not delete anything on the DHCP. Please do it manually"
#send a warning to ADDY
}
}
if ($debugScript -eq 1) { start-sleep 5 }
###################################################### END: DHCP DELETE RESERVATION #################################################
###################################################### START: VMWARE DELETE VM #################################################
if ($errorCount -eq 0) {
write-host "Removing VM from vSphere."
Remove-VM -vm $VMname -DeletePermanently -Confirm:$false
}
###################################################### END: VMWARE DELETE VM #################################################