TagPowerCLI

#PowerCLI: Distributed switch portgroup usage. Good vs. bad vs. Max Power approach

From now on there are three ways of doing things: the right way, the wrong way, and the Max Power way.

Isn’t that the wrong way?

Yes! But faster!

This quote from Homer Simpsons came directly into my mind when I was doing some PowerCLI scripting during the week.

maxpower

I started with the wrong / Max Power way and suddenly came to a much more smarter solution – the right way.

The task was to gather the usage on the virtual distributed switch portgroups within a world-wide environment with around 30 vCenter. (Final script on the bottom of this blog)

Once again I realized there are many roads to Rome and even with PowerCLI you can either go there by crawling or using a plane.

My first approach was to get each portgroup and have a look through each port if it has a connection to the virtual network adapter of a VM (each VM only has 1 Network adapter).

$ports = Get-VDSwitch | Get-VDPort -VDPortgroup $pg
$portsconnected = $ports | Where {$_.ConnectedEntity.Name -eq 'Network adapter 1'}

That approach was incredibly slow (> 12 hours) since it took a while to get all port objects of the distributed switch (more than 5000 per vDS).

Thanks to Brian Graf‘s great blog article we know how to access vSphere objects extension data in a much more elegant way.

$networks = Get-View -viewtype Network
Foreach ($network in $networks){
    $pgname = $network.Name
    $connectedports = ($network.VM).count 
}

Doing it that way it took 15 minutes instead of 12++ hours.

It really makes a huge difference if you code something right or wrong. That’s counts for Software, SQL-queries and also for all kind of scripts we use and built in our daily IT-infrastructure world.

The final script gives you an csv output file with the values

Datacenter, PortgroupName, VLANID, NumberOfConnectedPorts

Make sure to use Powershell 3.0++ so you can use the -append option in the export-csv cmdlet.

Enjoy.

Good one

$results = @()

$cluster = get-cluster | Sort-Object -Property Name
$dcName = (Get-Datacenter).Name
$networks = Get-View -viewtype Network

Foreach ($network in $networks){
    $pgname = $network.Name
    $pg = Get-VDPortgroup -Name $pgname
    $vlanid = $pg.vlanConfiguration.VlanID
    $connectedports = ($network.VM).count

    $details = @{
        PortgroupName = $pgname
        VLANID = $vlanId
        NumberOfConnectedPorts = $connectedports
        Datacenter = $dcName
    }

    $results += New-Object PSObject -Property $details
}

$results | export-csv -Append -Path c:\temp\newvDSnetworkConnected.csv -NoTypeInformation

 Bad one

$results = @()

$dcName = (Get-Datacenter).Name
$pgs = Get-VDSwitch | Get-VDPortgroup | Where {$_.IsUplink -ne 'True'}

foreach ($pg in $pgs){

    $ports = Get-VDSwitch | Get-VDPort -VDPortgroup $pg
    $portsconnected = $ports | Where {$_.ConnectedEntity.Name -eq 'Network adapter 1'}

    $pgname = $pg.name
    $vlanId = $pg.VlanConfiguration.VlanId

    $connectedports = $portsconnected.count
    $details = @{
        PortgroupName = $pgname
        VLANID = $vlanId
        NumberOfConnectedPorts = $connectedports
        Datacenter = $dcName
    }
    $results += New-Object PSObject -Property $details 
} 

$results | export-csv -Append -Path c:\temp\vDSnetworkConnected.csv -NoTypeInformation

Automatic virtual hardware change after shutdown – vCenter alarms and #PowerCLI

Teaching an Optimize and Scale class this week I was asked if there is chance to automatically change the virtual hardware once a VM has been shut down or powered off.

Scenario – Customer wants to change the CPU / RAM of their XenDesktops with minimal impact on the end-user. If a VM is powered off vCenter should change the hardware and wait until another components powers the VM on again.

At first I was not sure how this can be done. Using PowerCLI for changing the virtual hardware? – easy… but how can we call this script once the VM is powered off? After a minute I remebered that we can use vCenter alarms to trigger more than just snmp/email actions if a specific Event/Condition occurs. We can also run cmds and therefore call a PowerCLI script.

Requirements:

Using AD-based authentication for the PowerCLI script makes it easier regarding the Authentication mechanism. Therefore the vCenter server must run with Active Directory Service Account that has the proper permissions on the vCenter level

vcenteralarmaction01

vcenteralarmaction02

Chapter 1:  Easy going – Hardcode the CPU count in the script

Create the PowerCLI script

Now we create the modify-cpu.ps1 script that will be stored in the C:\scripts\

with the following content. (Note: the CPU count must be hardcoded in the script by changing the $numCPU parameter. Be aware of that this script changes the count of Cores and stays with 1 virtual socket.

Complete Script – modify-cpu.ps1:

param(
[string]$vmname
)

$vCenter = 'localhost'

$numCPU = 4
####
# Include VMware-PowerCLI SnapIn
if(!(Get-PSSnapin | Where {$_.name -eq "vmware.vimautomation.core"}))
{
    try
    {
        Write-Host "Adding PowerCLI snap in"
        Add-PSSnapin VMware.VimAutomation.Core -ea 0| out-null
    }
    catch
    {
        throw "Could not load PowerCLI snapin"
    }
}

Connect-VIServer $vCenter

$vm = get-vm $vmname
$spec=New-Object –Type VMware.Vim.VirtualMAchineConfigSpec –Property @{"NumCoresPerSocket" = $numCPU;"numCPUs" = $numCPU}
$vm.ExtensionData.ReconfigVM_Task($spec) | out-null

Disconnect-VIServer $vCenter -confirm:$false

 

Create the vCenter alarm that will call the script above with the VM name as parameter

Select the VM you want the virtual CPU count be changed after a shutdown and create a vCenter alarm (wow I am really using the webclient)

Give it a valuable name and describiton and select to monitor for a specific event

vcenteralarmaction03

As an event where the alarm and therefore the action will be triggered we select VM – Powered off

vcenteralarmaction04

And finally as an action we call our created PowerCLI script in C:\scripts with the following statement:

“c:\windows\system32\cmd.exe” “/c echo.|powershell.exe -nologo -noprofile -noninteractive C:\scripts\modify-cpu.ps1 {targetName}”

With the {targetName} variable we can transfer the name of the virtual machine that caused the Trigger.

vcenteralarmaction05

And voila. If the VM is now getting powered-off -> the change of the virtual hardware will be done.

vcenteralarmaction06

(German language, hm!? Doesn’t sound it quiet nice :P)

vcenteralarmaction07

If the configuration is not working as expected, validate the functionality by call cmd with the user that is running the vCenter service:

> Open CMD

> runas /user:Domain\vCenteruser cmd

> “c:\windows\system32\cmd.exe” “/c echo.|powershell.exe -nologo -noprofile -noninteractive C:\scripts\modify-hardware.ps1 {targetName}”

Chapter 2:  Make it more awesome by using VMs and Templates Folders

To be more flexible on the hardware configuration I wanted to have the following functionality:

Drag and Drop a VM in a specific folder. If the VM is powered off change the virtual hardware based on specific settings. The settings should be extracted from the folder name.

Foldername specification: modify_ressourcetype_value

for example I create 4 Folders:

  • modify_cpu_2
  • modify_cpu_4
  • modify_ram_4
  • modify_ram_8

If you drag a VM in the modify_ram_8 folder and power it off, the VM will be configured with 8GB memory.

So I needed to change my script in a way that it gathers the folder the of the VM that is transmitted with the script call:

Complete Script – modify-hardware.ps1:

$vm = get-vm $vmname
$vmFolderName = $vm.Folder.Name

and split the foldername at the ‘_’ chars:

$items = $vmFolderName.Split('_')
$ressourceType = $items[1]
$amount = $items[2]

Now I can select the change RAM or CPU logic with a ‘switch’ statement:

switch($ressourceType){

    'cpu'
     {
         $vCPu= $amount
         $spec=New-Object –Type VMware.Vim.VirtualMAchineConfigSpec –Property @{"NumCoresPerSocket" =          
         $vCPu;"numCPUs" = $vCPu}
         $vm.ExtensionData.ReconfigVM_Task($spec) | out-null
      }
    'ram'
     {
          $NmbrRam = $amount
          set-vm -VM $vm -memoryGb $NmbrRam -confirm:$false
     } 
     default
     {
         write-verbose 'Wrong folder name specification'
     }
}

If the VM is not in a folder that matches the specification. Nothing will happen.

Transfer the following modify-hardware.ps1 script into C:\scripts\ and configure this time the alarms in the same way as described above – but now on the specific folder we have created for this solution.

The action call this time needs to be renamed since I created another script:

“c:\windows\system32\cmd.exe” “/c echo.|powershell.exe -nologo -noprofile -noninteractive C:\scripts\modify-hardware.ps1 {targetName}”

vcenteralarmaction08

Complete Script – modify-hardware.ps1:

param(
[string]$vmname
)

$vCenter = 'localhost'

###

# Include VMware-PowerCLI SnapIn
if(!(Get-PSSnapin | Where {$_.name -eq "vmware.vimautomation.core"}))
{
    try
    {
        Write-Host "Adding PowerCLI snap in"
        Add-PSSnapin VMware.VimAutomation.Core -ea 0| out-null
    }
    catch
    {
        throw "Could not load PowerCLI snapin"
    }
}

Connect-VIServer $vCenter

#Gather Objects and Data
$vm = get-vm $vmname
$vmFolderName = $vm.Folder.Name

#Split the folder name to extract parameter - Foldername must be modify_ressource_x
#while ressource must be ram or cpu and X the number of CPU or amount of RAM in GB

$items = $vmFolderName.Split('_')
$ressourceType = $items[1]
$amount = $items[2]
$items

switch($ressourceType){

    'cpu'
     {
         $vCPu= $amount
         $spec=New-Object –Type VMware.Vim.VirtualMAchineConfigSpec –Property @{"NumCoresPerSocket" =          
         $vCPu;"numCPUs" = $vCPu}
         $vm.ExtensionData.ReconfigVM_Task($spec) | out-null
      }
    'ram'
     {
          $NmbrRam = $amount
          set-vm -VM $vm -memoryGb $NmbrRam -confirm:$false
     } 
     default
     {
         write-verbose 'Wrong folder name specification'
     }
}

Disconnect-ViServer $vCenter -confirm:$false

Maybe some of you will benefit from this little script-collection. Have fun with it 😉

Killing me softly/hardly/forcely. How to kill a VM via #PowerCLI

Having observed some problems with VMs that were not able to be shutdown/powered-off properly via PowerCLI I tried to find a solution.

From time to time Shutdown-VMGuest didn’t worked and even an Stop-VM with the kill option were not working as expected. I knew that ESXTOP and ESXCLI have the options to kill a VM process/world if there are no other options. But since I wanted to achieve this in PowerCLI this blog post from the year 2011 gave me the correct hint.

We can use ESXCLI via PowerCLI to fulfil that task  😉 *whoopwhoop*.

I was missing a feature to kill those worlds without authenticating directly against an ESXi-host and since ESXCLI and it’s namespaces have changed a little within the last years I wanted to document now how this can be achieved in vSphere 5.X.

First of all connect to the vCenter via

Connect-VIServer $vCenterFQDN

Get the VM-Object you are going to kill

$vm = Get-VM $nameOfTheVM

find the ESXi-Host where the VM is running on

$esxi = Get-VMHost -VM $vm

and load the ESXCLI functionality

$esxcli = Get-EsxCli -VMhost $esxi

Now it’s time to extract the WorldID out of the ESXCLI VM PROCESS LIST data

$worldid = $esxcli.vm.process.list() | where{$_.Displayname -eq $hostname} | Select WorldID

and kill the VM with the options soft, hard, force

$esxcli.vm.process.kill("force",$worldid.WorldID)

VOILA the VM should be definitely killed right now. This ESXCLI commands is  not being tracked by the VPXA, so no events of the ‘kill’ are written down in the database. (With great knowledge comes great responsibility, right? ;-))

If you are running this command against a VM as part of an HA-Cluster. The HA-mechanism will reboot the VM after the kill. In this scenario you need to disable the HA-protection of the VM (so it is removed from the HA protected list) before you are going to kill it via.

$vm | Set-VM -HARestartPriority Disabled

I hope this information might be useful to some of you guys.

Please use the Code-Snippet here to see the fully-functional (Kill-VM.ps1) script.

Kill-VM.ps1

 

IMO: #VMworld 2014 recap Automation & Orchestration (part 5)

Sitting here at the airport in Bucharest I thought I can finally write down my IMO thoughts about the whole automation/orchestration topic.

As I had more fun in writing about automation instead of vSAN/vVol I did it like George Lucas and mixed the orders of my parts/episodes 😉

IMO: #VMworld 2014 recap on VMware NSX (part 1)

IMO: #VMworld 2014 recap VMware EVO:RAIL (part 2)

IMO: #VMworld 2014 recap VMware vCloud Air (part 3)

IMO: #VMworld 2014 recap vSAN and vVol (part 4)

IMO: #VMworld 2014 recap Automation & Orchestration (part 5)

I visited a lot of breakout sessions regarding automation and scripting. Some of them were really really good with some great core-messages, for other sessions my skill-set of scripting or programming was not honestly not good enough to get it all ;-).

2014 was kind of a PowerCLI year for myself. I was automating a lot of stuff in a huge project with PowerCLI. I did not just used PowerCLI for interacting or automating vSphere object (VM, Clusters, Datastore,…) related things, but also to automate/optimize operational or implementation tasks (vCenter / SQL installation, Automatic Setup …). There are just so many amazing things you can do with Powershell/PowerCLI.

So IMO whoever is going to read this (if you are one of my students you will know this message):

Don’t be afraid of learning automation via scripts because it is related to programming.

In my opinion (and I meet/teach around 100 people a year from all kind of IT-infrastructure background) so many people are afraid because they have never been good at programming. This might be definitely correct, but there is no need to worry. I am definitely not a programmer and to be honest I am not considering me as a powershell/powercli professional as well. Nevertheless Powershell/PowerCLI makes it really easy to get started, because …

  • … the community is so f***** great.
  • … you have some sense of achievement pretty soon (I mean having an output of ‘hello world’ never really made me proud, but creating 50 VMs out of a template within 1-line in 2 minutes is somehow a really cool thing.
  • … the community is so f***** great ;-).

Automation is the future in the IT-infrastructure especially now that we are heading step-by-step towards the software-defined datacenter. Each component in the infrastructure is opening itself up via an API where we can run our code against. So what is the next step for me personally? Evolve from scripting to orchestrating.

During VMworld the session MGT2525 Chasing the White Rabbit all the Way to Wonderland: Extending vCloud Automation Center Requests with vCenter Orchestrator ()had a great outcome which order of automation is the best.

Policy driven (think about vVol/vSAN) things are probably not the things in the nearer future I will implement (I’m not a developer…….yet :P). Anyway I might be able to get much more into the whole orchestration (vCenter/vRealize Orchestrator) topic.

Working a lot in the automation field with script languages like Powershell, I realized the benefits and weaknesses of purely scripted solutions. If you want to have an automation engine done via a script language (e.g. Powershell/PowerCLI) it works pretty fine. But among other features you have to reinvent the wheel all the time. How can an object within a workflow be stored persistently? How can a workflow be pause/resumed? Functionality-extension via standardized plug-ins? How can I scale such an automation engine up? A lot of thinks will come up during the development, which have to be dealt with. Those topics are reasons where I believe that professional Orchestration solution are a much better choice. I will try to find this out and be more specific within the next months ;-).

So do we start learning this stuff? Having some chats after a #vBrownbag Session with Joerg Lew ( @joerglew – He was introduced to myself and is obviously the orchestration guru) he gave me some good advices how to start with when I want to learn about vR/vC Orchestrator.

That’s exactly what I am going to do in the next months…. When 2014 was my year of PowerCLI, 2015 will be my year of Orchestration.

So you wanna see how I am doing learning it? I try to keep you informed right here on this blog…stay tuned…

(And if I have not made any progress on automation at the end of next year…feel free to kick my ass if you see me 😉 )

Using OVFtool via Powercli with a session ticket – lessons learned

Powercli is a really great tool for automation. Nevertheless from time to time we need other tools as well to fullfil our needs. If you want to automize the distribution of templates in your environment the OVFtool is a really nice way to achieve this. Since I wanted to deploy the template to multiple Clusters in an environment, the following would do the trick.

Having 2 arrays which stores all the vCenter and all the Clusters in the environment the following would do the trick.

function DistributeTemplates 
(
	[Parameter(Mandatory=$True)]
	[String]$templateLocation
)
 
$ovftool = "C:\Program Files\VMware\OVFtool\ovftool.exe"
 
foreach ($vCenter in $vCenterlist) {
    Connect-VIServer $vCenter
    foreach ($cluster in $clusterList) {
 
        $arglist = ' --name=TemplateName --network=NetworkName -ds=DatastoreName $($templateLocation) vi://vCenterUser:Password@$($vCenter)/DCNAME/host/$($cluster)'  		 		
        $process = Start-Process $ovftool -Argumentlist ($arglist) -wait
    }
}

Eventhough it was working I was not happy about how the authentication mechanism was used (Password in cleartext…nooooo way).

Luckily I found a post at geekafterfive.com who explained how we can use a ticketing automatism in OVFTool.

$Session = Get-View -Id Sessionmanager
$ticket = $session.AcquireCloneTicket()
Unfortunatley struggeld with two things:

1. Make sure you are only connected to one vCenter, otherwise

 $ticket = $session.AcquireCloneTicket()

will throw an error Method invocation failed because [System.Object[]] doesn’t contain a method named ‘AcquireCloneTicket’.”

powercli_error2. I could only upload the templates to the first cluster. The second one was always failing. It seems that my ticket was not valid anymore. Luckily a closer look to the vSphere SDK Programming guide told me that “A client application executing on behalf of a remoteuser can invoke the AcquireCloneTicket operation of SessionManager to obtain a onetime user name and password for logging on without entering a subsequent password” …. ahhh…one time password…I thought the ticket will be valid for multiple operations once I’m connected to a vCenter. But since my thoughts don’t count on this topic (*yeahyeah…what a rough world) I needed to create a new ticket before every OVFTool operation.

So the following script was completly satisfying my (template-automation) needs.

function DistributeTemplates 
(
	[Parameter(Mandatory=$True)]
	[String]$templateLocation
)
 
$ovftool = "C:\Program Files\VMware\OVFtool\ovftool.exe"
 
foreach ($vCenter in $vCenterlist) {
    Connect-VIServer $vCenter
    foreach ($cluster in $clusterList) {
        $Session = Get-View -Id Sessionmanager
        $Ticket = $Session.AcquireCloneTicket()
        $arglist = ' --I:targetSessionTicket=$($Ticket) --name=TemplateName --network=NetworkName -ds=DatastoreName $($templateLocation) vi://$($vCenter)/DCNAME/host/$($cluster)'  		 		
        $process = Start-Process $ovftool -Argumentlist ($arglist) -wait
    }
}

Now a ticket of the vCenter authentication is generated after the usage and I haven’t had to deal with storing any credentials while deploying a template to the whole wide world :)…yeha…

PowerCLI – Waiting for Guest Customization to Finish

Only a couple of days ago, a customer asked for a script to deploy hundreds of VMs with a couple of tasks to be done after the VM was available on the network. Like move into a different OU, or register with XenDesktop, etc. The challenge about this was to have the PowerCLI script wait for the VM to be actually done with the Sysprep process and be available on the network before the remaining tasks are executed.

I found an article from Alan Renouf on blogs.vmware.com about this topic but was unable to do it the way he suggested. I didn’t really figure out why it seemed to work for him but not in my case, but for example the way he tested for the Event type and a couple of other things did not work out and created syntax errors etc. While his code showed me how to do it in general, I decided to write my own code. Own code is always better for personal understanding, too icon wink PowerCLI – Waiting for Guest Customization to Finish AND my code is way simpler as it does not simultaneously monitor multiple VMs but only one at a time.

function StartVMAndWaitForSysprep
(
	[Parameter(Mandatory=$True)]
	[Vmware.VIMAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl]$vmRef
)
{
	$vm = Start-VM $vmRef -Confirm:$False -ErrorAction:Stop
 
	# wait until VM has started
	Write-Host "Waiting for VM to start ..."
	while ($True)
	{
		$vmEvents = Get-VIEvent -Entity $vm
 
		$startedEvent = $vmEvents | Where { $_.GetType().Name -eq "VMStartingEvent" }
 
		if ($startedEvent) 
		{
			break
		}
		else
		{
			Start-Sleep -Seconds 2	
		}	
	}
 
	# wait until customization process has started	
	Write-Host "Waiting for Customization to start ..."
	while($True)
	{
		$vmEvents = Get-VIEvent -Entity $vm 
		$startedEvent = $vmEvents | Where { $_.GetType().Name -eq "CustomizationStartedEvent" }
 
		if ($startedEvent)
		{
			break	
		}
		else 	
		{
			Start-Sleep -Seconds 2
		}
	}
 
	# wait until customization process has completed or failed
	Write-Host "Waiting for customization ..."
	while ($True)
	{
		$vmEvents = Get-VIEvent -Entity $vm
		$succeedEvent = $vmEvents | Where { $_.GetType().Name -eq "CustomizationSucceeded" }
		$failEvent = $vmEvents | Where { $_.GetType().Name -eq "CustomizationFailed" }
 
		if ($failEvent)
		{
			Write-Host "Customization failed!"
			return $False
		}
 
		if($succeedEvent)
		{
			Write-Host "Customization succeeded!"
			return $True
		}
 
		Start-Sleep -Seconds 2			
	}
}

Finally, but not not worth its own posting, we have a function to wait for the guest to have an IP address:

function WaitForToolsToReportIP
(
	[Parameter(Mandatory=$True)]
	[Vmware.VIMAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl]$vmRef
)
{
	$ping = New-Object System.Net.NetworkInformation.Ping
 
	while ($True) 
	{	
		$vm = Get-VM $vmRef
 
		$guestInfo = $vm.guest
 
		if($guestInfo.IPAddress -and $guestInfo.IPAddress[0])
		{
			return $True
		}
		else
		{
			Start-Sleep -Seconds 2
		}
	}	
}

As you can see, I check whether VMware Tools report an IP address. The advantage of this is that I don’t have to rely on the OS to respond to pings.

Hope that helps!

© 2017 v(e)Xpertise

Theme by Anders NorenUp ↑