Tuesday 5 December 2017

Powershell/Powercli: remove disabled NICs.

Hi.

Today I had some interesting task, to remove/modify disabled NICs in Windows OS. Information I had was just list of VMs.

"Easy"- I thought - "I''ll take MAC addresses of disabled adapters, compare them against adapters present in VM, done".
 As it turned out, it's not as straight forward as I assumed. When adapters are disabled in OS, driver is unloaded and no info about NIC's MAC or IP is provided. So no WMI.
There is Get-NetAdapter cmdlet, which can return MAC of disabled NIC, but I had issues with PSremoting, and I didn't have access to OS itself.

So I decided to turn a flaw into a advantage. VMtools grabs info about NIC and present it in
 $currentvm.ExtensionData.Guest.Net ($currentvm is of course variable holding VM object):


We have all nice info about active adapters in OS. So, if adapter is disabled, it's not present here.

I then grabbed list of MACs from Get-Networkadapter cmdlet:





Now it's just comparing the lists, adding some logic in case there are more than one active adapter present in OS, and I'll ended up with this script:

$vms = Get-Content .\vms.txt

foreach ($vm in $vms) {
$currentvm = get-vm $vm
$workingmac = $currentvm.ExtensionData.Guest.net.macaddress
$currentvmadapters = $currentvm|Get-NetworkAdapter
$macstoremove = $currentvmadapters.MacAddress

 if ($workingmac.count -ge 1) {
  $workingmac|foreach {
  $removeme = $_
  $macstoremove = $macstoremove|sls -NotMatch "$removeme"
 
   }

  }
  
 $macstoremove|foreach {
 $mac = $_
 $currentvmadapters|where {$_.macaddress -like "$mac" }|Set-NetworkAdapter -StartConnected:$false -Connected:$false

 }

}



I'm using simple Select-String cmdlet to filter out MAC addresses currently used from list of MACs to be modified. 
I'm just disconnecting NICs here, but of course it can delete them.


Update:

Turned out that Remove-NetworkAdapter cmdlet works only with powered off VMs. Bummer.

But thanks to amazing LucD from vmware forums, it can be done by device change task for each device. Here's the thread.

So final code may look like this:

$vms = Get-Content .\vms.txt

foreach ($vm in $vms) {
$currentvm = get-vm $vm
$workingmac = $currentvm.ExtensionData.Guest.net.macaddress
$vmos = $currentvm.ExtensionData.Config.GuestFullName
$currentvmadapters = $currentvm|Get-NetworkAdapter
$macstoremove = $currentvmadapters.MacAddress
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$nicstoremove = @()

if ($vmos -notlike "*windows*") {
$currentvm|select name,@{n="OS";e={$vmos}}|Out-File -Force -Append nonwindows_OS.txt
write-host -ForegroundColor Yellow "$($currentvm.name) is not the Windows VM..."
}
else {


if ($workingmac.count -ge 1) {
$workingmac|foreach {
 $removeme = $_
 $macstoremove = $macstoremove|sls -NotMatch "$removeme"
 
  }
 }

 Write-host -ForegroundColor Green "Processing $($currentvm.name) VM..."
  
 $macstoremove|foreach {
 $mac = $_
 $nicstoremove += $currentvmadapters|where {$_.macaddress -like "$mac" }
 }
 }
 $nicstoremove|select parent, macaddress, type, networkname|Export-Csv NicsToRemove.csv -Append -NoTypeInformation

$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
  foreach($Adapter in $nicstoremove){
      $devSpec = New-Object VMware.Vim.VirtualDeviceConfigSpec
      $devSpec.operation = "remove"
      $devSpec.device += $Adapter.ExtensionData
      $spec.deviceChange += $devSpec
    }
  $currentvm.ExtensionData.ReconfigVM_Task($spec)|Out-Null


 }