Multiple vCenters and MAC address conflicts

VMware KB article 1024025 explains an issue with MAC address conflicts due to multiple vCenter configurations with the same instance ID. Here is a technical description straight from the KB article:

Each vCenter Server system has a vCenter Server instance ID. This ID is a number between 0 and 63 that is randomly generated at installation time, but can be reconfigured after installation. 

vCenter Server uses the vCenter instance ID to generate MAC addresses and UUIDs for virtual machines. If two vCenter Server systems have the same vCenter instance ID, they might generate identical MAC addresses for virtual machines. This can cause conflicts if the virtual machines are on the same network, leading to packet loss and other problems. 

The solution is to verify that all of your vCenter configurations use different instance IDs for MAC address generation. This wouldn’t be difficult if you only had two or three vCenters, but as you scale out it becomes more of a challenge. Here is some PowerCLI code that will help you check for duplicate instance IDs.


# Virtual machine MAC address conflicts - http://kb.vmware.com/kb/1024025
$vCentersToCheck = "vcenter1","vcenter2","vcenter3"

$config = Get-PowerCLIConfiguration 
if($config.DefaultVIServerMode -eq "Single"){Set-PowerCLIConfiguration -DefaultVIServerMode Multiple}
foreach ($vCenter in $vCentersToCheck){connect-viserver $vCenter | Out-Null}

$myReport = @()
$global:DefaultVIServers | %{
	$si = Get-View ServiceInstance -Server $_.Name
	$set = Get-View $si.Content.Setting -Server $_.Name
	$myReport += new-object -type PSObject -Property @{
		InstanceID = ($set.Setting.GetEnumerator() | where {$_.key -eq "instance.id"}).value
		vCenter = $_.Name
	}
}

$myResults = $myReport | Group-Object InstanceID | where {$_.Count -gt 1} | select -ExpandProperty Group | select vCenter, InstanceID 
if ($myResults.count -gt 1) { $myResults } else { "No duplicate InstanceIDs were identified in the vCenters checked" }

By default, the script will let you know if you have any duplicates. However, if you want to know what all instance IDs are in use, they are stored in the $myReport variable. You can type “$myReport” (without the quotes) in the console window after this script completes.

Posted in Scripting, Virtualization | 2 Comments

Powershell title bar and profile

This is a very simple post, but it shows how to make the Powershell title bar contain useful information. By default the Powershell title contains the path to the powershell.exe file — here is an example:

To make this more useful, I’ve added a line to my powershell profile that looks like this:

$host.ui.rawui.WindowTitle="PowerShell $($psversiontable.psversion) as $($env:username)"

*Note: all this text should appear on the same line in your profile.

This change adds the Powershell version number and running user name to the title bar. This is useful in my environment because I often have the need to run Powershell as a different user. Here is an example of the update:

I placed this in the all users profile located here:

%windir%\system32\WindowsPowerShell\v1.0\profile.ps1 

This profile is machine specific and executes anytime you open a powershell console for any user. While you have the profile open, I have one more time saving suggestion. If you use the Send-MailMessage cmdlet often, add this line:

$PSEmailServer = "smtp-relay.mydomain.local"

With this variable specified, you no longer need the “-SmtpServer” attribute to send a message — this global variable will automatically be used.

Hope this helps!

Posted in Scripting | Leave a comment

Simple examples of Powershell PSCustomObject

In most of my Powershell scripts I make use of the PSCustomObject to store results. The example I first learned (and use all the time) looks just like this:


$item = "" | Select Name, RAM, CPU
$item.Name = "blah"
$item.Ram = 4096
$item.Cpu = 1
$item

In the above example, you create a blank PSCustomObject on line 1 which has Name, RAM and CPU placehoders. Then on lines 2 through 4 you assign values to each attribute. Finally on line 5 you do something with the variable $item. In the above example, the contents of the $item variable are displayed onscreen. Normally you’d see something like $myreport += $item which stores the new item in a collection called $myreport.

The problem is adding an additional attribute to your object requires two steps — first, you must declare the attribute on line 1 and then assign something to the attribute after it is declared. For example, if I wanted to add PowerState to my report, I would have to add “, PowerState” on the first line. If you forget, which happens to me all the time, you get this error:

$item.PowerState = "PoweredOff"
Property 'PowerState' cannot be found on this object; make sure it exists and is settable.
At line:1 char:7
+ $item. <<<< PowerState = "PoweredOff"
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyAssignmentException

I recently found a new example that I like a lot better. Here is an example:


$item2 = new-object -type PSObject -Property @{
	Name = "blah"
	RAM = 4096
	CPU = 1
}
$item2

In the above example, attributes are created as needed, removing the need to pre-define them on the first line of the script. This method removes the need to specify "$item." for each attribute, making the code easier to read/maintain/support.

This is a very simple example, but I hope others find it useful.

Posted in Scripting | Leave a comment

Working with the lastLogon attribute in PowerShell

I have been spending a lot of time working on Powershell scripts. Specifically, I have been re-writing many VB scripts and processes into more efficient powershell versions. In my last post I mentioned that I planed to share how I made a task that took 8 hours to execute run in only 28 minutes. There are two parts to this efficiency — Start-Job and Group-Object. In a future post I’ll write more about the Start-Job functionality, but the greatest benefit was from Group-Object — and thats what I’ll focus on in this post.

The task I re-wrote looked at about 50,000 user accounts and collected many details about the accounts for auditing purposes. Due to some constraints, I needed to use the lastLogon attribute instead of lastLogonTimeStamp. You can read more about the constraints here: http://www.rlmueller.net/Last%20Logon.htm, but this line pretty much sums it up: Because the lastLogon attribute is not replicated in Active Directory, a different value can be stored in the copy of Active Directory on each Domain Controller. In VB script, I was using an LDAP bind to each domain controller for each user account and then evaluated the lastLogon attribute, which was very inefficient.

Here is the powershell version of this code, which is much more efficient and flexible (as you can get the last login time from each/all domain controllers very easy).


$lastLogons = @()
$domainControllers | %{ # I used an LDAP query for computers with primaryGroupID=516 to get a list of domain controllers distinguished names
	$objDC = New-Object DirectoryServices.DirectoryEntry "LDAP://$_"
	$dcName = $objDC.dnsHostName.ToString()
	$de = New-Object System.DirectoryServices.DirectoryEntry ("LDAP://$dcName")
	$Rech = New-Object System.DirectoryServices.DirectorySearcher($de)
	$Rech.filter = "(&(objectCategory=User)(!objectClass=Computer)(lastLogon>=1))"
	$Rech.SearchScope = "subtree"
	$Rech.sizelimit = "90000"
	$Rech.pagesize = "90000"
	$Rech.PropertiesToLoad.Add("distinguishedName");
	$Rech.PropertiesToLoad.Add("lastLogon");
	$liste = $Rech.FindAll()
	$lastLogons += ($liste | select @{n='DN';e={$_.properties.distinguishedname}},@{n='LastLogon';e={$_.properties.lastlogon}}, @{n='DC';e={$dcName}})
}
 $groupedLastLogin = $lastLogons | Group-Object -Property DN -AsHashTable -AsString
 
# To get an individuals last login information, just select it from the hash table
$trueLastLogin = $groupedLastLogin.Item($objUser.distinguishedName.ToString()) | sort LastLogon -Descending | select -First 1
$lastDC = $trueLastLogin.DC
$lastLogonTrueDate = [datetime]::FromFileTimeUTC($trueLastLogin.lastLogon)

After creating this code, I attempted to select user information from the $lastLogons variable. This was very slow — even slower than the previous VB script that did excessive LDAP binds. The efficiency in this script was gained by grouping the objects into a hash table ($groupedLastLogin) by distinguished name, and then accessing the specific key value as needed.

I know several of my posts have strayed from the normal VMware/vSphere/PowerCLI topics recently, but I have some plans to get back on track early next year. Please stay tuned!

Posted in Messaging, Scripting | 2 Comments

T-SQL to show how long a task took to execute

I have been working on various scripts that populate information into a SQL table. The other day I was attempting to see how long some of these tables took to populate. I could have updated the PowerShell script to include some Measure-Command information, but then I’d have to re-execute my tasks and see how long they took to run. Since I already had all of the information populated into a table, and each row had a time stamp of when the data was entered, I could just use a T-SQL select statement to get the run time data I wanted.

SELECT CAST( (MAX(dataCollected) - MIN(dataCollected)) as time) as TotalRunTime, COUNT(*) as RecCount FROM tblTestInserts WHERE collectionID = MAX(collectionID)

The above example looks at two columns in my table. The first column (dataCollected) is of the datetime type and has a default binding of GetDate() — so it is automatically populated with the SQL Servers date and time every time a record is inserted. The second column (collectionID) is an integer that is calculated each time I execute the script — inside of powershell I select the maximum value of this column and then add 1. This provides a way know how many times the task has been executed and which data is the most current.

This gave me exactly the information I was looking for without needing to modify my PowerShell script and re-run the collection. It also allows me to compare current runs to previous runs (by changing the value of the collectionID in the WHERE clause). I can also be more specific…I can add an ‘AND’ to the where clause and see how long a specific part of the collection took to run.

In a future post I plan to share how I was able to take a vbscript that took 8 hours to complete condense it into a 28 minute execution time powershell script. (Here is a preview of the magic sauce — Group-Object -Property DN -AsHashTable -AsString)

Posted in Scripting | Leave a comment