Get-Beer Powershell function

Earlier in the week I had the privilege of presenting an introduction to Powershell/PowerCLI webex to a group of VMware customers. To help explain the Where-Object, Select-Object, and Sort-Object cmdlets, I thought it would be helpful to create a Get-Beer function. This function was a success, so I thought I would share it here. The function is very basic — it uses Import-CSV to read information from a file and returns the results ordered by name. The results can then be piped to other functions for demo purposes.

You can download a sample beer.csv file here.

Here is the function:
[cc lang=”powershell”]
<# .SYNOPSIS List Miller Coors beer .DESCRIPTION This function returns a list of beer bottled by MillerCoors. The object also includes nutrition and alcohol information. .EXAMPLE PS C:\> Get-Beer
.NOTES
This function was created for demo purposes only.
VMware PowerCLI rocks!
#>
Function Get-Beer {
$myResults = @()
Import-Csv C:\tmp\beer.csv | Sort-Object Name | %{
[decimal]$thisAlcoholPercent = $_.”Alcohol%”
[decimal]$thisCaloriesPer12oz = $_.CaloriesPer12oz
$myResults += new-object -type PSObject -Property @{
Name = $_.Name
AlcoholPercent = $thisAlcoholPercent
CaloriesPer12oz = $thisCaloriesPer12oz
Category = $_.Category
} #End New-Object
} #End for each object

# Return a custom PS object containing each beer
return ($myResults | Select-Object Name, AlcoholPercent, CaloriesPer12oz, Category)
} #End Function
[/cc]

The function type casts the numeric values as decimal so that they properly sort. To run this, place a beer.csv file in the C:\tmp path (or adjust the filename/path in the function), paste the function into a powershell window and you are ready to go.

Here are a few examples of what you can do with this function:

Get-Beer

(Get-Beer).count

Get-Beer | Sort-Object AlcoholPercent -Descending | Select-Object Name, AlcoholPercent -First 5

Get-Beer | Where-Object {$_.CaloriesPer12oz -lt 200 -AND $_.Category -eq "Craft"} | Sort-Object AlcoholPercent -Descending | Select-Object -First 5
Posted in Scripting | Leave a comment

vSphere vCenter 5.0 SSL certificates

It seems every release of the VMware vSphere vCenter server service has more dependency on SSL.  I always replace the default self signed SSL certificates with ones created from an internal/trusted certificate authority.  There is a good four part guide to creating the properly formatted certificates available here: http://www.virtualvcp.com/vsphere-4-technical-guides/136-replace-ssl-certificates-prepare-openssl-and-microsoft-cs

As of last count, you need to place the custom SSL certificate in 4 places to make sure you don’t see any pesky SSL warnings. Here is a listing of those paths and instructions required to make the certificate work:

vCenter Server Service (VPXD)
SSL location: C:\ProgramData\VMware\VMware VirtualCenter\SSL
Run the command: “D:\Program Files\VMware\Infrastructure\VirtualCenter Server\vpxd.exe –p” to reset the vpxd password.
*Note: This will cause all of the hosts to become disconnected and require each to be reconnected to vCenter

vSphere Web Client Server
SSL location: D:\Program Files\VMware\Infrastructure\vSphere Web Client\DMServer\config\ssl
Restart the “vSphere Web Client” Service.

VMware vCenter Update Manager
SSL location: D:\Program Files\VMware\Infrastructure\Update Manager\SSL
Find/Replace the existing server name in the D:\Program Files (x86)\VMware\Infrastructure\Update Manager\extension.xml file and replace it with your servers alias/SSL certificates common name.
Run the command: “D:\Program Files (x86)\VMware\Infrastructure\Update Manager\vciInstallUtils.exe –vc myvcenter.mydomain.com –port 80 -U myusername -P mypassword -S extension.xml -C . -L . -O extupdate”
Where myvcenter.mydomain.com is the common name/friendly name of your SSL certificate and 80 is the http port of your vCenter.

vCenter Inventory Service:
SSL location: D:\Program Files\VMware\Infrastructure\Inventory Service\ssl
Stop thevCenter Inventory Service (Note: This will also stop the dependent service VMware vSphere Profile-Driven Storage Service)
Run the command: D:\Program Files\VMware\Infrastructure\Inventory Service\scripts\register.bat myvcenter.mydomain.com 443
Where myvcenter.mydomain.com is the common name/friendly name of your SSL certificate and 443 is the https port of your vCenter.
Start the vCenter Inventory Service
Start the VMware vSphere Profile-Driven Storage Service

Posted in Virtualization | 2 Comments

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.

[cc lang=”Powershell”]
# 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” }
[/cc]

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:

[cc lang=”Powershell”]
$item = “” | Select Name, RAM, CPU
$item.Name = “blah”
$item.Ram = 4096
$item.Cpu = 1
$item
[/cc]

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:

[cc lang="Powershell"]
$item2 = new-object -type PSObject -Property @{
Name = "blah"
RAM = 4096
CPU = 1
}
$item2
[/cc]

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