How to Find a VM by MAC address with VMware PowerCLI

logo-powershellFinding a VM by its MAC address can be a non-trivial task, especially if you have a vCenter with tons of complicated virtual appliances and several network cards on each one of them. Fortunately, VMware has PowerShell CLI that can help here.

First, you will need to install PowerCLI on a Windows box. Check for PowerCLI version you want to use on its PowerShell Gallery page. PowerCLI versions are backward-compatible (PowerCLI v6.5 worked for me on vCenter 5.5), so just pick the latest stable version. On the way, PowerShell may ask you to update NuGet and/or trust installations from PowerShell Gallery.

PS C:\> Install-Module -Name VMware.PowerCLI -RequiredVersion 6.5.4.7155375

NuGet provider is required to continue
PowerShellGet requires NuGet provider version '2.8.5.201' or newer to interact with NuGet-based repositories. The NuGet
 provider must be available in 'C:\Program Files\PackageManagement\ProviderAssemblies' or
'C:\Users\ankhitre\AppData\Local\PackageManagement\ProviderAssemblies'. You can also install the NuGet provider by
running 'Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force'. Do you want PowerShellGet to install
and import the NuGet provider now?
[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"): Y

Untrusted repository
You are installing the modules from an untrusted repository. If you trust this repository, change its
InstallationPolicy value by running the Set-PSRepository cmdlet. Are you sure you want to install the modules from
'PSGallery'?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "N"): Y
PS C:\> 

Next step is to import core CLI module. You may need to adjust execution policy to do that – do it on your own risk, and make sure you know what you are doing first! Also, PowerCLI will prompt you to join their data collection program, but you can safely ignore that “warning” for now.

PS C:\> Import-Module VMware.VimAutomation.Core
WARNING: .....
PS C:\> 

Now you can connect to your vCenter:

PS C:\> Connect-VIServer -Server <IP/FQDN> -Protocol https -User <username> -Password <password>

Name                           Port  User
----                           ----  ----
<IP/FQDN>                      443   <user>

PS C:\> 

Note that if you don’t have valid SSL certificate on your vCenter, you will have to configure PowerCLI to deal with that – either prompt you to accept certificate on connection ("Set-PowerCLIConfiguration -InvalidCertificateAction Prompt") or just ignore those warnings altogether ("Set-PowerCLIConfiguration -InvalidCertificateAction Ignore").

Once CLI is connected to vCenter, finding for your VM by MAC address is one step away:

PS C:\> Get-VM | Get-NetworkAdapter | Where {$_.MacAddress -eq “00:50:56:12:34:56”} | Select-Object Parent,Name,MacAddress

Parent              Name                MacAddress
------              ----                  ----------
ubuntu-dev-012      Network adapter 1     00:50:56:12:34:56


PS C:\>

Alternatively, you can “pipe” the result through Format-List instead of Select-Object and get all available properties of this network adapter.

Good luck!

How to check MSI version in PowerShell

logo-powershellIt appears that checking MSI version in PowerShell is much less trivial than checking DLL version. Yet, the following script can do it for you. Most of the credits for the script go to this StackOverflow question.

###############################################################
# Name:         GetMsiVersion.ps1
# Description:  Prints out MSI installer version
# Usage:        GetMsiVersion.ps1 <path to MSI>
# Credits:      http://stackoverflow.com/q/8743122/383673
###############################################################
param (
    [IO.FileInfo] $MSI
)

if (!(Test-Path $MSI.FullName)) {
    throw "File '{0}' does not exist" -f $MSI.FullName
}

try {
    $windowsInstaller = New-Object -com WindowsInstaller.Installer
    $database = $windowsInstaller.GetType().InvokeMember(
        "OpenDatabase", "InvokeMethod", $Null,
        $windowsInstaller, @($MSI.FullName, 0)
    )

    $q = "SELECT Value FROM Property WHERE Property = 'ProductVersion'"
    $View = $database.GetType().InvokeMember(
        "OpenView", "InvokeMethod", $Null, $database, ($q)
    )

    $View.GetType().InvokeMember("Execute", "InvokeMethod", $Null, $View, $Null)
    $record = $View.GetType().InvokeMember( "Fetch", "InvokeMethod", $Null, $View, $Null )
    $version = $record.GetType().InvokeMember( "StringData", "GetProperty", $Null, $record, 1 )

    return $version
} catch {
    throw "Failed to get MSI file version: {0}." -f $_
}

Here is the execution sample:

C:\>powershell -ExecutionPolicy bypass -File GetMsiVersion.ps1 "C:\Program Files (x86)\Google\Update\1.3.21.79\GoogleUpdateHelper.msi"
1.3.21.79

C:\>

Enjoy!

How to check DLL version in PowerShell

logo-powershellChecking DLL version in PowerShell is extremely easy.

Here is the script that does it for you. Note that the real code fits in a single line (lines 17-18, I just split it out for readability). Other 20+ lines are dedicated to script header, input validation and exception handling.

###############################################################
# Name:         GetDllVersion.ps1
# Description:  Prints out DLL version
# Usage:        GetDllVersion.ps1 <path to DLL>
# Author:       Anton Khitrenovich, Jan 2014
###############################################################
param(
    [string]$DLL
)

if (!(Test-Path $DLL)) {
    throw "File '{0}' does not exist" -f $DLL
}

try {
    $version =
        Get-ChildItem $DLL | Select-Object -ExpandProperty VersionInfo |
            Select-Object FileVersion | Select-Object -ExpandProperty FileVersion

    return $version
} catch {
    throw "Failed to get DLL file version: {0}." -f $_
}

Here is the execution sample:

C:\>powershell -ExecutionPolicy bypass -File C:\GetDllVersion.ps1 "C:\Program Files\Java\jre7\bin\java.dll"
7.0.250.17

C:\>

Enjoy!

How to run PowerShell script from Ant

logo-powershellYesterday I was looking for a good recipe of how to run PowerShell script from Ant build file. Unfortunately, it seems that most of the people are looking for an advise on exactly the opposite – how to run Ant from PowerShell. So, I did some trial and error on my own, and here are the results.

The following Ant snippet executes PowerShell script MyScript.ps1 in the current directory and verifies that it did not fail. The result of the script execution is stored in myscript.out property.

<exec dir="." executable="powershell" timeout="5000" failonerror="true"
        outputproperty="myscript.out" errorproperty="myscript.error">
    <arg line="-ExecutionPolicy bypass" />
    <arg line="-File MyScript.ps1" />
</exec>
<if>
    <not>
        <equals arg1="${myscript.error}" arg2="" trim="true" />
    </not>
    <then>
        <fail message="${myscript.error}" />
    </then>
</if>

The main caveat here is the error checking. Despite the failonerror flag, the exec task will not fail in case of many errors – like compilation issues, missing parameters and other runtime errors. This happens because the task verifies invocation of PowerShell itself and not the script execution, which is handled inside PowerShell. The solution is to capture error stream into dedicated property and verify that nothing was actually written there.

Pay attention that if tag (lines 6-13) requires ant-contrib tasks library available. The same condition may be rewritten in less readable form with pure Ant:

<fail message="${myscript.error}">
    <condition>
        <not>
            <equals arg1="${myscript.error}" arg2="" trim="true" />
        </not>
    </condition>
</fail>

Another note is the bypass of default execution policy on line 3. This is not specific to Ant, but rather to PowerShell in general. There are a lot of discussions on the net about the topic, so I won’t cover it here.