PowerCLI: Getting vmhost uptime

I love a powershell challenge, and last week a colleague of mine asked me for assistance in getting the uptime of vmware hosts. My initial response did the trick:

Get-View  -ViewType hostsystem -Property name,runtime.boottime | Select-Object Name, @{N="UptimeDays"; E={((((get-date) - ($_.runtime).BootTime).TotalDays).Tostring()).Substring(0,5)}}

However, I wasn’t completely satisfied by the the output or the ease of use.
So today I went back and rewrote the code and made a function of it.
Instead of using the ToString and Substring methods I went for the built-in class Math, which has a method called Round. You can learn more about the Math class here: http://www.madwithpowershell.com/2013/10/math-in-powershell.html

Anyways, here’s the function I came up with:

function Get-VMHostUptime
    {
        [CmdletBinding()] 
            Param (
                [Parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)][Alias('Name')][string]$VMHosts,
                [string]$Cluster
                  )
    Process{
         If ($VMHosts) {
            foreach ($VMHost in $VMHosts) {Get-View  -ViewType hostsystem -Property name,runtime.boottime -Filter @{"name" = "$VMHost"} | Select-Object Name, @{N="UptimeDays"; E={[math]::round((((Get-Date) - ($_.Runtime.BootTime)).TotalDays),1)}}, @{N="UptimeHours"; E={[math]::round((((Get-Date) - ($_.Runtime.BootTime)).TotalHours),1)}}, @{N="UptimeMinutes"; E={[math]::round((((Get-Date) - ($_.Runtime.BootTime)).TotalMinutes),1)}}}
            }
     
         elseif ($Cluster) {
            foreach ($VMHost in (Get-VMHost -Location $Cluster)) {Get-View  -ViewType hostsystem -Property name,runtime.boottime -Filter @{"name" = "$VMHost"} | Select-Object Name, @{N="UptimeDays"; E={[math]::round((((Get-Date) - ($_.Runtime.BootTime)).TotalDays),1)}}, @{N="UptimeHours"; E={[math]::round((((Get-Date) - ($_.Runtime.BootTime)).TotalHours),1)}}, @{N="UptimeMinutes"; E={[math]::round((((Get-Date) - ($_.Runtime.BootTime)).TotalMinutes),1)}}}
            }

         else {
            Get-View  -ViewType hostsystem -Property name,runtime.boottime | Select-Object Name, @{N="UptimeDays"; E={[math]::round((((Get-Date) - ($_.Runtime.BootTime)).TotalDays),1)}}, @{N="UptimeHours"; E={[math]::round((((Get-Date) - ($_.Runtime.BootTime)).TotalHours),1)}}, @{N="UptimeMinutes"; E={[math]::round((((Get-Date) - ($_.Runtime.BootTime)).TotalMinutes),1)}}
            }
        }
<#
 .Synopsis
  Shows the uptime of VMHosts
 .Description
  Calculates the uptime of VMHosts provided, or VMHosts in the cluster provided
 .Parameter VMHosts
  The VMHosts you want to get the uptime of. Can be a single host or multiple hosts provided by the pipeline
 .Example
  Get-VMHostUptime
  Shows the uptime of all VMHosts in your vCenter
 .Example
  Get-VMHostUptime vmhost1
  Shows the uptime of vmhost1
 .Example
  Get-VMHostUptime -cluster cluster1
  Shows the uptime of all vmhosts in cluster1
 .Example
  Get-VMHost -location folder1 | Get-VMHostUptime
  Shows the uptime of VMHosts in folder1
 .Link
  http://cloud.kemta.net
 #>
}

You can use it in a couple of different ways, as documented in its help section (get-help get-vmhostuptime -expamples). But if you provide no input to it, it will generate an output like this:

get-vmhostuptime

Hopefully, you don’t have an uptime as long as some of these hosts Smilie: :)

Posted in PowerCLI, Powershell, VMware Tagged , , , , , ,

PowerCLI: Getting the status of vmware tools on all VMs

I’m sure I don’t need to explain to you guys why VMware tools is a good idea to have installed on your VMs, and probably not why it’s a good idea to keep VMware tools updated.
However, I haven’t found a good way to get a neat list of which VMs need to have their VMware tools upgraded. While working on my vCenter health check script I found that I had to make my own little script to get that list. And, in addition, I wanted the list to include the VM version.

I ended up with creating a function to provide me with that list:

function Get-VMToolsStatus
    {
        [CmdletBinding()] 
        Param (
            [ValidateSet('NeedUpgrade','NotInstalled','Unsupported')][string]$Filter
            )
            
    $VMs = Get-View -ViewType VirtualMachine -Property name,guest,config.version,runtime.PowerState
    $report = @()
    $progress = 1
    foreach ($VM in $VMs) {
        Write-Progress -Activity "Checking vmware tools status" -Status "Working on $($VM.Name)" -PercentComplete ($progress/$VMs.count*100) -ErrorAction SilentlyContinue
        $object = New-Object PSObject
        Add-Member -InputObject $object NoteProperty VM $VM.Name
        if ($VM.runtime.powerstate -eq "PoweredOff") {Add-Member -InputObject $object NoteProperty ToolsStatus "$($VM.guest.ToolsStatus) (PoweredOff)"}
        else {Add-Member -InputObject $object NoteProperty ToolsStatus $VM.guest.ToolsStatus}
        Add-Member -InputObject $object NoteProperty ToolsVersionStatus ($VM.Guest.ToolsVersionStatus).Substring(10)
        Add-Member -InputObject $object NoteProperty SupportState ($VM.Guest.ToolsVersionStatus2).Substring(10)
        if ($object.ToolsStatus -eq "NotInstalled") {Add-Member -InputObject $object NoteProperty Version ""}
        else {Add-Member -InputObject $object NoteProperty Version $VM.Guest.ToolsVersion}
        Add-Member -InputObject $object NoteProperty "HW Version" $VM.config.version
        $report += $object
        $progress++
        }
    Write-Progress -Activity "Checking vmware tools" -Status "All done" -Completed -ErrorAction SilentlyContinue

    if ($Filter -eq 'NeedUpgrade') {
        $report | Sort-Object vm | Where-Object {$_.ToolsVersionStatus -eq "NeedUpgrade"}
        }
    elseif ($Filter -eq 'NotInstalled') {
        $report | Sort-Object vm | Where-Object {$_.ToolsVersionStatus -eq "NotInstalled"}
        }
    elseif ($Filter -eq 'Unsupported') {
        $report | Sort-Object vm | Where-Object {($_.SupportState -eq "Blacklisted") -or ($_.SupportState -eq "TooNew") -or ($_.SupportState -eq "TooOld") -or ($_.SupportState -eq "Unmanaged")}
        }
    else {$report | Sort-Object vm}

<#
 .Synopsis
  List vm tools status for all VMs
 .Description
  Lists the status and version for all VMs, also tells whether the version is supported and also the vm version
 .Parameter Filter
  Filters the list based on if the VMware tools "NeedUpgrade", is "NotInstalled" or if they are "Unsupported"
 .Example
  Get-VMToolsStatus
  List vm tools status for all VMs
 .Example
  Get-VMToolsStatus -Filter NeedUpgrade
  Show only VMs needing update of vm tools
 .Link
  http://cloud.kemta.net
 #>
}

The function will create an output that look kinda like this:

get-vmtoolsstatues

You can also use a basic filter on the function by specifying -Filter <filtername>. The different filters is documented in the help section.
For example, if you only want a list of VMs who need an upgrade of their VMware tools version:

get-vmtoolsstatus-needupgrade

In case you don’t want to use this as a function, here’s the script version:

    $VMs = Get-View -ViewType VirtualMachine -Property name,guest,config.version,runtime.PowerState
    $report = @()
    $progress = 1
    foreach ($VM in $VMs) {
        Write-Progress -Activity "Checking vmware tools status" -Status "Working on $($VM.Name)" -PercentComplete ($progress/$VMs.count*100) -ErrorAction SilentlyContinue
        $object = New-Object PSObject
        Add-Member -InputObject $object NoteProperty VM $VM.Name
        if ($VM.runtime.powerstate -eq "PoweredOff") {Add-Member -InputObject $object NoteProperty ToolsStatus "$($VM.guest.ToolsStatus) (PoweredOff)"}
        else {Add-Member -InputObject $object NoteProperty ToolsStatus $VM.guest.ToolsStatus}
        Add-Member -InputObject $object NoteProperty ToolsVersionStatus ($VM.Guest.ToolsVersionStatus).Substring(10)
        Add-Member -InputObject $object NoteProperty SupportState ($VM.Guest.ToolsVersionStatus2).Substring(10)
        if ($object.ToolsStatus -eq "NotInstalled") {Add-Member -InputObject $object NoteProperty Version ""}
        else {Add-Member -InputObject $object NoteProperty Version $VM.Guest.ToolsVersion}
        Add-Member -InputObject $object NoteProperty "HW Version" $VM.config.version
        $report += $object
        $progress++
        }
    Write-Progress -Activity "Checking vmware tools" -Status "All done" -Completed -ErrorAction SilentlyContinue

    $report

Depending on the number of VMs in your environment, the list might now even fit on the screen. So you should probably pipe it to where-object to filter it down further, like this:

get-vmtoolsstatus-script

Posted in PowerCLI, Powershell, VMware Tagged , , , , ,

PowerCLI: Getting datastore alarms

Next in the series on getting alarms is getting datastore alarms.
Again, the code is pretty similar:

$Datastores = Get-View -ViewType Datastore -Property Name,OverallStatus,TriggeredAlarmstate
$FaultyDatastores = $Datastores | Where-Object {$_.TriggeredAlarmState -ne "{}"}

$progress = 1
$report = @()
if ($FaultyDatastores -ne $null) {
    foreach ($FaultyDatastore in $FaultyDatastores) {
        foreach ($TriggeredAlarm in $FaultyDatastore.TriggeredAlarmstate) {
            Write-Progress -Activity "Gathering alarms" -Status "Working on $($FaultyDatastore.Name)" -PercentComplete ($progress/$FaultyDatastores.count*100) -Id 1 -ErrorAction SilentlyContinue
            $entity = $TriggeredAlarm.Entity.ToString()
            $alarmID = $TriggeredAlarm.Alarm.ToString()
            $object = New-Object PSObject
            Add-Member -InputObject $object NoteProperty Datastore $FaultyDatastore.Name
            Add-Member -InputObject $object NoteProperty TriggeredAlarms ("$(Get-AlarmDefinition -Id $alarmID)")
            $report += $object
            }
        $progress++
        }
    }
Write-Progress -Activity "Gathering alarms" -Status "All done" -Completed -Id 1 -ErrorAction SilentlyContinue

$report | Where-Object {$_.TriggeredAlarms -ne ""}

And the output is pretty similar:

get-datastorealarms

The function code is this:

function Get-DatastoreAlarms
{
$Datastores = Get-View -ViewType Datastore -Property Name,OverallStatus,TriggeredAlarmstate
$FaultyDatastores = $Datastores | Where-Object {$_.TriggeredAlarmState -ne "{}"}

$progress = 1
$report = @()
if ($FaultyDatastores -ne $null) {
    foreach ($FaultyDatastore in $FaultyDatastores) {
        foreach ($TriggeredAlarm in $FaultyDatastore.TriggeredAlarmstate) {
            Write-Progress -Activity "Gathering alarms" -Status "Working on $($FaultyDatastore.Name)" -PercentComplete ($progress/$FaultyDatastores.count*100) -Id 1 -ErrorAction SilentlyContinue
            $entity = $TriggeredAlarm.Entity.ToString()
            $alarmID = $TriggeredAlarm.Alarm.ToString()
            $object = New-Object PSObject
            Add-Member -InputObject $object NoteProperty Datastore $FaultyDatastore.Name
            Add-Member -InputObject $object NoteProperty TriggeredAlarms ("$(Get-AlarmDefinition -Id $alarmID)")
            $report += $object
            }
        $progress++
        }
    }
Write-Progress -Activity "Gathering alarms" -Status "All done" -Completed -Id 1 -ErrorAction SilentlyContinue

$report | Where-Object {$_.TriggeredAlarms -ne ""}
        
<#
 .Synopsis
  Lists all triggered Cluster alarms that haven't been acknowledged
 .Description
  Outputs a list of Cluster and the unacknowledged alarms they have triggered
 .Example
  Get-VMHostAlarms
  Outputs a list of Cluster and the unacknowledged alarms they have triggered
 .Link
  http://cloud.kemta.net
 #>
}

 

Posted in PowerCLI, Powershell, VMware Tagged , , , , ,

PowerCLI: Getting cluster alarms

The next step in my short series on getting vCenter alarms using PowerCLI is to get cluster alarms.

Here’s the code:

$Clusters = Get-View -ViewType ComputeResource -Property Name,OverallStatus,TriggeredAlarmstate
$FaultyClusters = $Clusters | Where-Object {$_.TriggeredAlarmState -ne "{}"}
$report = @()
$progress = 1
if ($FaultyClusters -ne $NULL) {
    foreach ($FaultyCluster in $FaultyClusters) {
        foreach ($TriggeredAlarm in $FaultyCluster.TriggeredAlarmstate) {
            Write-Progress -Activity "Gathering alarms" -Status "Working on $($FaultyCluster.Name)" -PercentComplete ($progress/$FaultyClusters.count*100) -Id 1 -ErrorAction SilentlyContinue
            $entity = $TriggeredAlarm.Entity.ToString()
            $alarmID = $TriggeredAlarm.Alarm.ToString()
            if ($entity -like "ClusterComputeResource-*") {
                $entityName = $FaultyCluster.Name
                $type = "Cluster"
                }
            elseif ($entity -like "HostSystem-host*") {
                $entityName = (Get-View -ViewType HostSystem -Property Name | Where-Object {$_.MoRef -eq $entity}).Name
                $type = "VMHost"
                }
            elseif ($entity -like "VirtualMachine-vm*") {
                $entityName = (Get-View -ViewType VirtualMachine -Property Name | Where-Object {$_.MoRef -eq $entity}).Name
                $type = "VM"
                }
            $object = New-Object PSObject
            Add-Member -InputObject $object NoteProperty Cluster $FaultyCluster.Name
            Add-Member -InputObject $object NoteProperty Entity $entityName
            Add-Member -InputObject $object NoteProperty Type $type
            Add-Member -InputObject $object NoteProperty TriggeredAlarms ("$(Get-AlarmDefinition -Id $alarmID)")
            $report += $object
            }
        $progress++
        }
    }
Write-Progress -Activity "Gathering alarms" -Status "All done" -Completed -Id 1 -ErrorAction SilentlyContinue
$report | Where-Object {$_.TriggeredAlarms -ne ""}

And the output will look something like this:

get-clusteralarms

As you can see, this will also list vm alarms and host alarms. So you could argue that you only need this and not separate scripts/functions for getting vm alarms and host alarms.

Anyways, here’s the function code:

function Get-ClusterAlarms
{
$Clusters = Get-View -ViewType ComputeResource -Property Name,OverallStatus,TriggeredAlarmstate
$FaultyClusters = $Clusters | Where-Object {$_.TriggeredAlarmState -ne "{}"}
$report = @()
$progress = 1
if ($FaultyClusters -ne $NULL) {
    foreach ($FaultyCluster in $FaultyClusters) {
        foreach ($TriggeredAlarm in $FaultyCluster.TriggeredAlarmstate) {
            Write-Progress -Activity "Gathering alarms" -Status "Working on $($FaultyCluster.Name)" -PercentComplete ($progress/$FaultyClusters.count*100) -Id 1 -ErrorAction SilentlyContinue
            $entity = $TriggeredAlarm.Entity.ToString()
            $alarmID = $TriggeredAlarm.Alarm.ToString()
            if ($entity -like "ClusterComputeResource-*") {
                $entityName = $FaultyCluster.Name
                $type = "Cluster"
                }
            elseif ($entity -like "HostSystem-host*") {
                $entityName = (Get-View -ViewType HostSystem -Property Name | Where-Object {$_.MoRef -eq $entity}).Name
                $type = "VMHost"
                }
            elseif ($entity -like "VirtualMachine-vm*") {
                $entityName = (Get-View -ViewType VirtualMachine -Property Name | Where-Object {$_.MoRef -eq $entity}).Name
                $type = "VM"
                }
            $object = New-Object PSObject
            Add-Member -InputObject $object NoteProperty Cluster $FaultyCluster.Name
            Add-Member -InputObject $object NoteProperty Entity $entityName
            Add-Member -InputObject $object NoteProperty Type $type
            Add-Member -InputObject $object NoteProperty TriggeredAlarms ("$(Get-AlarmDefinition -Id $alarmID)")
            $report += $object
            }
        $progress++
        }
    }
Write-Progress -Activity "Gathering alarms" -Status "All done" -Completed -Id 1 -ErrorAction SilentlyContinue
$report | Where-Object {$_.TriggeredAlarms -ne ""}
        
<#
 .Synopsis
  Lists all triggered Cluster alarms that haven't been acknowledged
 .Description
  Outputs a list of Cluster and the unacknowledged alarms they have triggered
 .Example
  Get-VMHostAlarms
  Outputs a list of Cluster and the unacknowledged alarms they have triggered
 .Link
  http://cloud.kemta.net
 #>
}

The output will be the same, but since it’s a function you can manipulate the data further. For example if you only want alarms related to the clusters themselves:

get-clusteralarms-filter

Posted in PowerCLI, Powershell, VMware Tagged , , , , ,

PowerCLI: Getting host alarms

Yesterday I wrote a post about getting vm alarms through PowerCLI. Today it’s time for getting host alarms Smilie: :)
The code is very similar to the one for getting vm alarms, since they both use get-view to grab all info:

$VMHosts = Get-View -ViewType HostSystem -Property Name,OverallStatus,TriggeredAlarmstate
$FaultyVMHosts = $VMHosts | Where-Object {$_.TriggeredAlarmState -ne "{}"}

$progress = 1
$report = @()
if ($FaultyVMHosts -ne $null) {
    foreach ($FaultyVMHost in $FaultyVMHosts) {
        foreach ($TriggeredAlarm in $FaultyVMHost.TriggeredAlarmstate) {
            Write-Progress -Activity "Gathering alarms" -Status "Working on $($FaultyVMHost.Name)" -PercentComplete ($progress/$FaultyVMHosts.count*100) -Id 1 -ErrorAction SilentlyContinue
            $alarmID = $TriggeredAlarm.Alarm.ToString()
            $object = New-Object PSObject
            Add-Member -InputObject $object NoteProperty VMHost $FaultyVMHost.Name
            Add-Member -InputObject $object NoteProperty TriggeredAlarms ("$(Get-AlarmDefinition -Id $alarmID)")
            $report += $object
            }
        $progress++
        }
    }
Write-Progress -Activity "Gathering alarms" -Status "All done" -Completed -Id 1 -ErrorAction SilentlyContinue

$report | Where-Object {$_.TriggeredAlarms -ne ""}

The output will look something like this:

get-vmhostalarms

And here’s the function code:

function Get-VMHostAlarms
{
$VMHosts = Get-View -ViewType HostSystem -Property Name,OverallStatus,TriggeredAlarmstate
$FaultyVMHosts = $VMHosts | Where-Object {$_.TriggeredAlarmState -ne "{}"}

$progress = 1
$report = @()
if ($FaultyVMHosts -ne $null) {
    foreach ($FaultyVMHost in $FaultyVMHosts) {
        foreach ($TriggeredAlarm in $FaultyVMHost.TriggeredAlarmstate) {
            Write-Progress -Activity "Gathering alarms" -Status "Working on $($FaultyVMHost.Name)" -PercentComplete ($progress/$FaultyVMHosts.count*100) -Id 1 -ErrorAction SilentlyContinue
            $alarmID = $TriggeredAlarm.Alarm.ToString()
            $object = New-Object PSObject
            Add-Member -InputObject $object NoteProperty VMHost $FaultyVMHost.Name
            Add-Member -InputObject $object NoteProperty TriggeredAlarms ("$(Get-AlarmDefinition -Id $alarmID)")
            $report += $object
            }
        $progress++
        }
    }
Write-Progress -Activity "Gathering alarms" -Status "All done" -Completed -Id 1 -ErrorAction SilentlyContinue

$report | Where-Object {$_.TriggeredAlarms -ne ""}
        
<#
 .Synopsis
  Lists all triggered VMHost alarms that haven't been acknowledged
 .Description
  Outputs a list of VMHosts and the unacknowledged alarms they have triggered
 .Example
  Get-VMHostAlarms
  Outputs a list of VMHosts and the unacknowledged alarms they have triggered
 .Link
  http://cloud.kemta.net
 #>
}

 

Posted in PowerCLI, Powershell, VMware Tagged , , , , ,

PowerCLI: Getting vm alarms

A few weeks ago I started to put together a health check script for our vmware environments and the first thing I wanted to have in that report is a list of triggered alarms. To my surprise there was no native cmdlet to retrieve alarms using PowerCLI, instead I had to write a short script to retrieve alarms.

So here’s the the script for retrieving vm alarms:

$VMs = Get-View -ViewType VirtualMachine -Property Name,OverallStatus,TriggeredAlarmstate
$FaultyVMs = $VMs | Where-Object {$_.OverallStatus -ne "Green"}

$progress = 1
$report = @()
if ($FaultyVMs -ne $null) {
    foreach ($FaultyVM in $FaultyVMs) {
            foreach ($TriggeredAlarm in $FaultyVM.TriggeredAlarmstate) {
                Write-Progress -Activity "Gathering alarms" -Status "Working on $($FaultyVM.Name)" -PercentComplete ($progress/$FaultyVMs.count*100) -Id 1 -ErrorAction SilentlyContinue
                $alarmID = $TriggeredAlarm.Alarm.ToString()
                $object = New-Object PSObject
                Add-Member -InputObject $object NoteProperty VM $FaultyVM.Name
                Add-Member -InputObject $object NoteProperty TriggeredAlarms ("$(Get-AlarmDefinition -Id $alarmID)")
                $report += $object
            }
        $progress++
        }
    }
Write-Progress -Activity "Gathering VM alarms" -Status "All done" -Completed -Id 1 -ErrorAction SilentlyContinue

$report | Where-Object {$_.TriggeredAlarms -ne ""}

This will provide an output like this:

get-vmalarms

But, as always, to make it easier for my colleagues to use I make a function out of it:

function Get-VMAlarms
{
$VMs = Get-View -ViewType VirtualMachine -Property Name,OverallStatus,TriggeredAlarmstate
$FaultyVMs = $VMs | Where-Object {$_.OverallStatus -ne "Green"}

$progress = 1
$report = @()
if ($FaultyVMs -ne $null) {
    foreach ($FaultyVM in $FaultyVMs) {
            foreach ($TriggeredAlarm in $FaultyVM.TriggeredAlarmstate) {
                Write-Progress -Activity "Gathering alarms" -Status "Working on $($FaultyVM.Name)" -PercentComplete ($progress/$FaultyVMs.count*100) -Id 1 -ErrorAction SilentlyContinue
                $alarmID = $TriggeredAlarm.Alarm.ToString()
                $object = New-Object PSObject
                Add-Member -InputObject $object NoteProperty VM $FaultyVM.Name
                Add-Member -InputObject $object NoteProperty TriggeredAlarms ("$(Get-AlarmDefinition -Id $alarmID)")
                $report += $object
            }
        $progress++
        }
    }
Write-Progress -Activity "Gathering VM alarms" -Status "All done" -Completed -Id 1 -ErrorAction SilentlyContinue

$report | Where-Object {$_.TriggeredAlarms -ne ""}
        
<#
 .Synopsis
  Lists all triggered VM alarms that haven't been acknowledged
 .Description
  Outputs a list of VMs and the unacknowledged alarms they have triggered
 .Example
  Get-VMAlarms
  Outputs a list of VMs and the unacknowledged alarms they have triggered
 .Link
  http://cloud.kemta.net
 #>
}

Beside the fact that a function is easier to use, it also makes it easier to manipulate the data further. For example if you only want alarms for vm whose name start with “smart”:

get-vmalarms_filter

Posted in PowerCLI, Powershell, VMware Tagged , , , , ,

PowerCLI: Mount NFS stores on multiple hosts

Ever had a bunch of vmware hosts that you want to add a NFS datastore on? It can be quite time consuming to say the least.
In our environment we have a couple of NFS stores that should be available on all vmware hosts and I really don’t want to browse around all 50 or so hosts and check if they have them and then mount them if they’re not available.

So, of course, I wrote a small powercli script to check if the NFS stores are mounted and then mount them if they’re not mounted:

$vmhosts = Get-View -ViewType HostSystem -Filter @{"Runtime.ConnectionState" = "connected"} -Property name

$progress = 1
$mounts = 1
foreach ($vmhost in $vmhosts) {
    Write-Progress -Activity "Checking $($vmhost.Name)" -PercentComplete ($progress/$vmhosts.count*100)
    if ((Get-Datastore -VMHost $vmhost.name | Where-Object {$_.name -eq "MGMT-ISO"}) -eq $NULL){
        New-Datastore -vmhost $vmhost.name -Name MGMT-ISO -Nfs -NfsHost <nfsHost> -Path /MGMT-ISO
        $mounts++
        }
    if ((Get-Datastore -VMHost $vmhost.name | Where-Object {$_.name -eq "USER-ISO"}) -eq $NULL){
        New-Datastore -vmhost $vmhost.name -Name USER-ISO -Nfs -NfsHost  -Path /USER-ISO
        $mounts++
        }
    $progress++
    }
if ($mounts = "1") {
    Write-Host "All hosts have the NFS stores already mounted" -ForegroundColor green
    }

While I am pretty comfortable with writing and executing scripts like this on the fly, other people who are not as familiar with powershell might be a bit intimidated by it.
That’s why I like to create functions of them and put them in the powershell profile for all users on our jumpstation (C:WindowsSystem32WindowsPowerShellv1.0profile.ps1).

If I were to create a function out of this script, it would look something like this (very basic):

function Mount-NFSstores {    
    $vmhosts = Get-View -ViewType HostSystem -Filter @{"Runtime.ConnectionState" = "connected"} -Property name

    $progress = 1
    $mounts = 1
    foreach ($vmhost in $vmhosts) {
        Write-Progress -Activity "Checking $($vmhost.Name)" -PercentComplete ($progress/$vmhosts.count*100)
        if ((Get-Datastore -VMHost $vmhost.name | Where-Object {$_.name -eq "MGMT-ISO"}) -eq $NULL){
            New-Datastore -vmhost $vmhost.name -Name MGMT-ISO -Nfs -NfsHost 10.64.0.8 -Path /MGMT-ISO
            $mounts++
            }
        if ((Get-Datastore -VMHost $vmhost.name | Where-Object {$_.name -eq "USER-ISO"}) -eq $NULL){
            New-Datastore -vmhost $vmhost.name -Name USER-ISO -Nfs -NfsHost 10.64.0.8 -Path /USER-ISO
            $mounts++
            }
        $progress++
        }
    if ($mounts = "1") {
        Write-Host "All hosts have the NFS stores already mounted" -ForegroundColor green
        }
<#
 .Synopsis
  Mounts MGMT-ISO and USER-ISO on vmhosts
 .Description
  Checks every vmhost for NFS stores, if MGMT-ISO or USER-ISO isn't mounted, the function will mount it
 .Example
  Mount-NFSstores
  Mounts MGMT-ISO and USER-ISO on vmhosts
 .Link
  http://cloud.kemta.net
 #>
    }

Posted in PowerCLI, Powershell, VMware Tagged , , ,

Powershell: Listing activated clients on KMS server

If you are using a KMS server for activating servers and clients in your environment, you may have noticed that there’s really no obvious way to get a list of all the clients that have been activated by the KMS server.

One way to get that overview is by using VAMT (http://technet.microsoft.com/en-us/library/hh824953.aspx), but since that tool is based on pulling info from clients and not from the KMS server it is not suitable for everyone.

Thankfully, there’s PowerShell Smilie: :)
Getting a list of all activated KMS clients through PowerShell is actually a simple one-liner:

$(foreach ($entry in (Get-EventLog -Logname "Key Management Service")) {$entry.ReplacementStrings[3]}) | sort-object -Unique

What this does is look through the Key Management Service eventlog, grab only the client name and then remove all duplicates (since a client activates itself at regular intervals, there will be duplicates).

Posted in Microsoft, Powershell Tagged , ,

Powershell: Measuring latency on DNS queries

A little while ago we have some issues with one of our Exchange environments. The symptoms was that basically everything was slow, opening address books, owa, sending mails and so on.
After some digging it occurred to me that this may be DNS related, so I used a one-liner in powershell to see how fast our DNS servers responded:

Measure-Command {Resolve-DnsName google.com -DnsOnly -Type A -NoHostsFile -server x.x.x.x}

And sure enough, we were seeing response times in the range of 5-7 seconds. Way more than enough to cause our problems. After rebooting the DNS servers ours problems disappeared.

But, as always, I had to play around with created a powershell function.

The function resolves a few records from locally defined DNS servers and some publicly available DNS servers (or a custom list if you want) and measures the average latency (in milliseconds). The results are put in a list and sorted by latency.

Here’s the code:

function Measure-DNSLatency
{
    [CmdletBinding()] 
        Param (
            [string[]]$CustomDNSServer
            )

    try {
        Get-DnsClientServerAddress -ErrorAction Stop | Out-Null
        }
    catch [System.Management.Automation.CommandNotFoundException] {
        Throw "You need at least PowerShell v4.0, your version is: $(($PSVersionTable.psversion).Major)"
        }
    
    $report = @()
    
    if ($CustomDNSServer.count -eq "0") {    
        Write-Verbose "Grabbing a list of locally defined dns servers"
        $LocalDNSServers = (Get-DnsClientServerAddress).serveraddresses | Select-Object -Unique
        $LocalDNSServers = $LocalDNSServers | Where-Object {$_ -ne "fec0:0:0:ffff::1"}
        $LocalDNSServers = $LocalDNSServers | Where-Object {$_ -ne "fec0:0:0:ffff::2"}
        $LocalDNSServers = $LocalDNSServers | Where-Object {$_ -ne "fec0:0:0:ffff::3"}

        Write-Verbose "Measuring locally defined dns servers"
        $progress = 1
        foreach ($DNSServer in $LocalDNSServers) {
            Write-Progress -ErrorAction SilentlyContinue -Activity "Measuring Latency on locally defined servers" -Status "Measuring $((Resolve-DnsName $DNSServer -Server $DNSServer).NameHost)" -PercentComplete ($progress/$LocalDNSServers.count*100) -Id 1
            $results = @()
            $results += (Measure-Command {Resolve-DnsName cloud.kemta.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
            $results += (Measure-Command {Resolve-DnsName google.com -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
            $results += (Measure-Command {Resolve-DnsName a.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
            $results += (Measure-Command {Resolve-DnsName b.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
            $results += (Measure-Command {Resolve-DnsName c.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
            $object = New-Object PSObject
            Add-Member -InputObject $object NoteProperty DNSServerName (Resolve-DnsName $DNSServer -Server $DNSServer).NameHost
            Add-Member -InputObject $object NoteProperty DNSServerIP $DNSServer
            Add-Member -InputObject $object NoteProperty LatencyInMS ($results | Measure-Object -Average).Average
            $report += $object
            $progress++
            }
        Write-Progress -ErrorAction SilentlyContinue -Activity "Measuring Latency on locally defined servers" -Status "Done" -Id 1 -Completed


        Write-Verbose "Measuring well known and publicly open dns servers"
        $PublicDNSServers = New-Object System.Collections.ArrayList
        $PublicDNSServers.Add("8.8.8.8") | Out-Null
        $PublicDNSServers.Add("8.8.4.4") | Out-Null
        $PublicDNSServers.Add("208.67.220.123") | Out-Null
        $PublicDNSServers.Add("208.67.220.220") | Out-Null
        $PublicDNSServers.Add("208.67.220.222") | Out-Null
        $PublicDNSServers.Add("208.67.222.222") | Out-Null
        $PublicDNSServers.Add("4.2.2.1") | Out-Null
        $PublicDNSServers.Add("4.2.2.2") | Out-Null
        $PublicDNSServers.Add("4.2.2.3") | Out-Null
        $PublicDNSServers.Add("4.2.2.4") | Out-Null
        $PublicDNSServers.Add("4.2.2.5") | Out-Null
        $PublicDNSServers.Add("4.2.2.6") | Out-Null
        $PublicDNSServers.Add("68.4.16.30") | Out-Null
        $PublicDNSServers.Add("68.4.16.25") | Out-Null
        $PublicDNSServers.Add("8.26.56.26") | Out-Null
        $PublicDNSServers.Add("8.20.247.20") | Out-Null
        $PublicDNSServers.Add("156.154.70.1") | Out-Null
        $PublicDNSServers.Add("156.154.71.1") | Out-Null

        $progress = 1
        foreach ($DNSServer in $PublicDNSServers) {
            Write-Progress -ErrorAction SilentlyContinue -Activity "Measuring Latency on publicly available servers" -Status "Measuring $((Resolve-DnsName $DNSServer -Server $DNSServer).NameHost)" -PercentComplete ($progress/$PublicDNSServers.count*100) -Id 1
            $results = @()
            $results += (Measure-Command {Resolve-DnsName cloud.kemta.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
            $results += (Measure-Command {Resolve-DnsName google.com -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
            $results += (Measure-Command {Resolve-DnsName a.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
            $results += (Measure-Command {Resolve-DnsName b.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
            $results += (Measure-Command {Resolve-DnsName c.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
            $object = New-Object PSObject
            Add-Member -InputObject $object NoteProperty DNSServerName (Resolve-DnsName $DNSServer -Server $DNSServer).NameHost
            Add-Member -InputObject $object NoteProperty DNSServerIP $DNSServer
            Add-Member -InputObject $object NoteProperty LatencyInMS ($results | Measure-Object -Average).Average
            $report += $object
            $progress++
            }
        Write-Progress -ErrorAction SilentlyContinue -Activity "Measuring Latency on publicly available servers" -Status "Done" -Id 1 -Completed
        }
    
    else {
        Write-Verbose "Measuring custom dns servers"
        $progress = 1
        foreach ($DNSServer in $CustomDNSServer) {
            Write-Progress -ErrorAction SilentlyContinue -Activity "Measuring Latency on custom servers" -Status "Measuring $((Resolve-DnsName $DNSServer -Server $DNSServer).NameHost)" -PercentComplete ($progress/$CustomDNSServer.count*100) -Id 1
            $results = @()
            $results += (Measure-Command {Resolve-DnsName cloud.kemta.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
            $results += (Measure-Command {Resolve-DnsName google.com -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
            $results += (Measure-Command {Resolve-DnsName a.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
            $results += (Measure-Command {Resolve-DnsName b.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
            $results += (Measure-Command {Resolve-DnsName c.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
            $object = New-Object PSObject
            Add-Member -InputObject $object NoteProperty DNSServerName (Resolve-DnsName $DNSServer -Server $DNSServer).NameHost
            Add-Member -InputObject $object NoteProperty DNSServerIP $DNSServer
            Add-Member -InputObject $object NoteProperty LatencyInMS ($results | Measure-Object -Average).Average
            $report += $object
            $progress++
            }
    }
    
    $report | Sort-Object LatencyInMS
        
<#
 .Synopsis
  Measures DNS Latency
 .Description
  Grabs locally defined dns servers and some publicly available dns servers and measures the Latency (in milliseconds) on DNS queries from your computer to them
 .Parameter CustomDNSServer
  Specifies a custom list of DNS servers to measure, or it could be a single server
 .Example
  Measure-DNSLatency
  Measures DNS latency on locally defined DNS servers og some public available DNS servers
 .Example
  Measure-DNSLatency 8.8.8.8
  Measures the DNS latency only on the DNS server 8.8.8.8
 .Example
  Measure-DNSLatency 8.8.8.8,8.8.4.4
  Measures the DNS latency only on the DNS servers 8.8.8.8 and 8.8.4.4
 .Link
  http://cloud.kemta.net
 #>
}

The different outputs will look something like this:

2014-08-15_10-25-49

 

Posted in Microsoft, Powershell Tagged , , , ,

Activate Server 2012 (R2) by telephone

The option for activating Server 2012 by phone is kinda hidden, so I have to write this down before I forget it:

Win+R – SLUI 4

https://dl.dropboxusercontent.com/u/33041052/bloggting/img/server2012_activa_by_phone.PNG

Posted in Microsoft Tagged , ,