Scripting

PowerShell: DataOnTAP and SID Convertions

This morning while standing up a new vScan A/V server I wanted to look up our McAfee service account.  I knew the account would be a domain account, and I knew it would be a member of the backup operators group on the filer.  With that in mind I ran the following.

[0:4]> Get-NaDomainUser -Group "Backup Operators"

SID
---
S-1-5-21-XXXXXXXX-XXXXXXXXX-XXXXXXXXX-112477
S-1-5-21-XXXXXXXX-XXXXXXXXX-XXXXXXXXX-111419
S-1-5-21-XXXXXXXX-XXXXXXXXX-XXXXXXXXX-146727

Well that’s rather useless… Unfortunately, the OnTAP API doesn’t provide a means to convert a SID to a NTAccount.  This is normally accomplished via the “cifs lookup” command on the Ontap CLI, but that doesn’t help us much from the toolkit.  Fortunately .Net provides a native means to perform this conversion.  This isn’t new to anyone who has been following PowerShell for a while (/\/\o\/\/ first posted these function way back in the Monad days), but that doesn’t make them any less useful!

Function ConvertTo-NTAccount
{
    Param(
        [Parameter(Mandatory=$true,
            HelpMessage="Enter the Sid to translate",
            ValueFromPipeLine=$true,
            ValueFromPipelineByPropertyName=$true
        )]
        [string]
        $SID
    )
    Process {
        $SIDObject = New-Object system.security.principal.securityidentifier($SID)
        write-output $SIDObject.translate([system.security.principal.ntaccount])
    }
}
Function ConvertTo-SID
{
    Param(
        [Parameter(Mandatory=$true,
            HelpMessage="Enter the NTAccount to translate in the form of domain\account",
            ValueFromPipeLine=$true,
            ValueFromPipelineByPropertyName=$true
        )]
        [string]
        $NTAccount
    )
    Process {
        $NTAccountObject = New-Object system.security.principal.NtAccount($NTaccount)
        write-output $NTAccountObject.translate([system.security.principal.securityidentifier])
    }
}

Armed with my trusty functions Let's try this again!
[0:15]> Get-NaDomainUser -Group "Backup Operators" | ConvertTo-NTAccount

Value
-----
GetAdmin\svcAV
GetAdmin\svcBackup
GetAdmin\svcMNV

Now that’s more like it!  This is what I Love about powershell.  In the past I would have had to push back on my sales rep, who would have inturn pushed back on the development team.  fast forward a year, and maybe I would have a workaround.  Or I would have had to try and glue a couple third party exe together (yuck). With PowerShell if I don’t like something I simply extend it in script.  No development, nothing complicated, just a couple line of PowerShell.  Best of all I can then provide this to the vendor as a concreate example of what I want in the next release (hint hint NetApp cifs lookup needs to be in the SDK!)

It really is just great stuff.
~Glenn

NetApp
Powershell

Comments (1)

Permalink

Cacti: Monitor protocol statistics for NetApp volumes

I have made no secret that I use two applications daily to monitor my infrastructure: Nagios and Cacti. I have created a fair number of scripts (and hopefully publishing more soon) to help Nagios monitor the different parts of the infrastructure, however I haven’t published many of my Cacti scripts previously.

One of the most useful is the config that I use to monitor the different protocol stats for volumes. I created an indexed query so that the single script, and accompanying XML file, are capable of monitoring all the volumes, and I can select which graphs to create for each volume. The polling script is loosely based off of the multi-protocol realtime volume statistics script that I created some time ago.

Download the template and script(s) here.

Some examples…

Total Operations, Latency
Cacti Volume Total Operations  Cacti Volume Total Latency
CIFS Operations, Latency
Cacti Volume CIFS Operations  Cacti Volume CIFS Latency
NFS Operations, Latency
Cacti Volume NFS Operations  Cacti Volume NFS Latency
iSCSI Operations, Latency
Cacti Volume iSCSI Operations  Cacti Volume iSCSI Latency

NetApp
Perl

Comments (7)

Permalink

Nagios: Checking for abnormally large NetApp snapshots

My philosophy with Nagios checks, especially with the NetApp, is that unless there are extenuating circumstances then I want all volumes (or whatever may be being checked) to be checked equally and at the same time. This means I don’t want to have to constantly add and remove checks from Nagios as volumes are added, deleted and modified. I would much rather have one check that checks all of the volumes and reports on them en masse. This means I don’t have to think about the check itself, but rather, only what it’s checking.

One of the many things that I regularly monitor on our multitude of NetApp systems is snapshots. We have had issues, especially with LUNs, where the snapshots have gotten out of control.

In order to prevent this, or at least hope that someone is watching the screen…, I wrote a quick script that checks to see if the total size of snapshots on a volume exceed the snap reserve. Since not all of our volumes have a snap reserve, I also put in the ability to check the size of the snaps against the percentage of free space left in the volume.

This last measure is a little strange, but I think it works fairly well. Take, for example, a 100GB volume. If it is 50% full (50GB), there is no snap reserve and the alert percentage is left at the default of 40% free space, then the alert will happen when snapshots exceed about 15GB. “But that’s not 40% of the free space”, I hear you saying. Ahhh, but it is…you see as the snapshot(s) grow, there is less free space, which means that it takes a larger percentage as the free space shrinks. So at 15GB of snapshots, there would be 35GB of free space, and 40% of 35GB is 14GB.

This causes the alerts to happen earlier than you may expect at first. You can adjust this number to be a percentage of the total space in the volume if you like…however, why not just set a snap reserve at that point? I chose to make the script this way in order to attempt to keep a little more free space in the volume, while not making a snap reserve mandatory.

One last word…please keep in mind this script does not check for a volume being filled, you should have other checks for that. This merely checks to see if snapshots have exceeded a threshold of space in the volume to prevent them from taking up too much space.

Bring on the Perl…

Continue Reading »

NetApp
Perl

Comments (2)

Permalink

PowerShell: DataOnTap Realtime Multiprotocol Volume Latency

I had some free time yesterday morning as I couldn’t sleep after the long weekend. I used the time to dig into into the DataOnTap PowerShell Toolkit.  I started with an easy port of one of Andrews performance monitoring scripts.  I won’t go into as it’s very straight forward, but I will say so far I am very pleased with the DataOnTAP toolkit. 

<#
.SYNOPSIS
    Get the different protocol latencies for a specified volume.
.DESCRIPTION
    Get the different protocol latencies for a specified volume.
.PARAMETER Volume
    Volume to retrieve the latency.
.PARAMETER Protocol
    Protocol to collect latency for valid values are 'all','nfs','cifs','san','fcp','iscsi'
.PARAMETER Interval
    The interval between iterations in seconds, default is 15 seconds
.PARAMETER Count
    the number of iterations to execute, default is infinant
.PARAMETER Controller
    NetApp Controller to query.
.EXAMPLE
    .Get-NaVolumeLatency.ps1 -Volume vol0 

    Get the average latency for all protocols on vol0
.EXAMPLE
    Get-NaVol | .Get-NaVolumeLatency.ps1 -Interval 5 -count 5 | ft

    Get the average latency for all protocols, all volumes, 5 samples, 5 seconds apart.
.EXAMPLE
    .Get-NaVolumeLatency.ps1 -Volume vol0 -protocol nfs

    Get the NFS latency for vol0
#>
[cmdletBinding()]
Param(
    [Parameter(Mandatory=$true,
        HelpMessage="Volume name to retrieve latency counters from.",
        ValueFromPipelineByPropertyName=$true,
        ValueFromPipeLine=$true
    )]
    [Alias("Name")]
    [string]
    $Volume
,
    [Parameter(Mandatory=$false)]
    [ValidateSet('all','nfs','cifs','san','fcp','iscsi')]
    [string]
    $Protocol='all'
,
    [Parameter(Mandatory=$false)]
    [int]
    $Interval=15
,
    [Parameter(Mandatory=$false)]
    [string]
    $count
,
    [Parameter(Mandatory=$false)]
    [NetApp.Ontapi.Filer.NaController]
    $Controller=($CurrentNaController)
)
Begin
{
    IF ($Protocol -eq 'all')
    {
       $Counters = @(
            @{
                Counter = 'read_latency'
                Base     = ''
                unit     = ''
            }
       ,
            @{
                Counter = 'write_latency'
                Base     = ''
                unit     = ''
            }
       ,
            @{
                Counter = 'other_latency'
                Base     = ''
                unit     = ''
            }
       ,
            @{
                Counter = 'avg_latency'
                Base     = ''
                unit     = ''
            }
        )
    }
    Else
    {
        $Counters = @(
            @{
                Counter  = "$($Protocol.ToLower())_read_latency"
                Base     = ''
                unit     = ''
            }
        ,
            @{
                Counter = "$($Protocol.ToLower())_write_latency"
                Base     = ''
                unit     = ''
            }
        ,
            @{
                Counter = "$($Protocol.ToLower())_other_latency"
                Base     = ''
                unit     = ''
            }
        )
    }
    foreach ($c in $Counters)
    {
        Get-NaPerfCounter -Name 'volume' -Controller $Controller |
            Where-Object {$_.name -eq $c.Counter} |
            ForEach-Object {
                $c.Base = $_.BaseCounter
                $c.unit = switch ($_.unit) {
                    "microsec"  {10000}
                    "millisec"  {1}
                }
            }
    }
}
Process
{            

    # Check if volume exists.
    if (-Not ((get-navol -Controller $Controller|select -ExpandProperty Name) -contains $Volume)) {
        Write-Warning "$volume doesn't exist!"
        break;
    }
    $iteration = 0
    $first = $null
    #loop untill we're done or Cntr ^c 
    while ((!$Count) -or ($iteration -le $count))
    {
        $second = New-Object Collections.HashTable
        Get-NaPerfData -Name volume `
            -Instances $Volume `
            -Controller $Controller `
            -Counters ($Counters|%{$_.base,$_.counter}) |
            Select-Object -ExpandProperty Counters |
            ForEach-Object {
                $second.add($_.Name,$_.value)
            }            

        if ($first -and $second)
        {
            $results = "" | Select-Object -Property ($Counters|%{$_.base,$_.counter})
            foreach ($v in $Counters)
            {
                IF ($second[$v.Base] -gt $first[$v.Base])
                {
                    #calculate the average over our interval
                    $avg = ($second[$v.Counter] - $first[$v.Counter])/($second[$v.Base] - $first[$v.Base])
                    #conver to ms
                    $results."$($v.Base)" = [math]::Round((($second[$v.Base] - $first[$v.Base])/$Interval))
                    $results."$($v.Counter)" = ("{0} ms" -f [math]::Round($avg/$v.unit))
                }
                Else
                {
                    $results."$($v.Base)" = 0
                    $results."$($v.Counter)" = "0 ms"
                }
            }
            Write-Output $results| Add-Member NoteProperty 'Volume' $Volume -PassThru
        }
        Start-Sleep -Seconds $Interval
        $first = $second.clone()
        $iteration++
    }
}

~Glenn

NetApp
Powershell

Comments (3)

Permalink

PowerCLI: Reconnect VMhosts after changing vCenter certificates

If you have ever changed the vCenter server certificates, you’ve experienced having all your hosts disconnected from vCenter.  I couldn’t imagine reconnecting them one at a time… You could do this all natively in PowerCLI, but that would require you to fully remove and then add the hosts.  That is very inconvenient, and almost as much trouble as doing it by hand… In this case it is both faster and easier to just use the native vSphere API.

# Get the hostsystem object for every host currently disconnected.
$VMhosts = Get-View -ViewType 'Hostsystem' `
                    -Property 'name' `
                    -Filter @{"Runtime.ConnectionState"="disconnected"}            

Foreach ($VMhost in $VMhosts)
{
    # Create a reconnect spec
    $HostConnectSpec = New-Object VMware.Vim.HostConnectSpec
    $HostConnectSpec.hostName = $VMhost.name
    $HostConnectSpec.userName = 'root'
    $HostConnectSpec.password = 'PassWord'            

    # Reconnect the host
    $taskMoRef = $VMhost.ReconnectHost_Task($HostConnectSpec)            

    # optional, but i like to return a task object, that way I can 
    # easily integrate this into a pipeline later if need be.
    Get-VIObjectByVIView -MORef $taskMoRef
}

~Glenn

HOW TO
PowerCLI
Powershell
Scripting
VMware
vCenter

Comments (2)

Permalink

Monitoring for orphaned snapshots left by SMVI

NetApp’s SnapManager for Virtual Infrastructure (SMVI) is a great product, but it’s messy. If it encounters the any error, it seemingly forgets to delete the virtual machine snapshots from the Virtual Infrastructure before dying.

To prevent many orphans (I’ve seen as many as 20 on a single virtual machine) from happening, I created a quick Nagios check that simply alerts when it sees them.

This script is very elementary. It very simply uses a regex to check for any snapshots that match the default SMVI naming convention. For each one it finds, a counter is incremented. If any are found, the script returns an error to Nagios, which causes an alert to be sent.

#!/usr/bin/perl -w
#
# check_vi_smvi_snapshots.pl - written by Andrew Sullivan, 2010-06-16
#
# Please report bugs and request improvements at http://get-admin.com/blog/?p=1059
#
# A simple script to look for snapshots that match the name pattern that smvi uses.
# We are merely pulling a list of all snapshots, searching for the string "smvi" in 
# the name, if it's found, we return a warning condition.  This could lead to a 
# "false" positive if it runs while a snapshot series is still ongoing, but since
# the smvi snaps should be very short lived the condidition will not last unless
# the snap is left.
#
# Example:
#   ./check_vi_smvi_snapshots.pl --server your.esx.host --username you --password secret
#
 
use strict;
use warnings;
 
use FindBin;
use lib "$FindBin::Bin/../";
 
use VMware::VIRuntime;
 
# substitute the location of your nagios perl library
use lib "/usr/lib64/nagios/plugins";
use utils qw(%ERRORS);
 
Opts::parse();
Opts::validate();
 
Util::connect();
 
main();
 
Util::disconnect();
 
sub main {
 
	# the number of smvi snapshots
	my $smviSnaps = 0;
 
	# for setting the type of exit we want
	my $exitCondition = "";
 
	# we need MORs for each of the VMs on the host
	my $VMs = Vim::find_entity_views( view_type => 'VirtualMachine' );
 
	foreach my $vm (@$VMs) {
		if ($vm->snapshot) {			
			foreach my $childSnapshot (@{$vm->snapshot->snapshotInfo->rootSnapshotList}) {
				$smviSnaps += getSnaps($childSnapshot);
			}
 
		} else {
			#print $vm->name . " has no snapshots\n";
		}
	}
 
	if ($smviSnaps > 0) {
		print "WARNING - " . $smviSnaps . " SMVI snapshots exist.\n";
		$exitCondition = "WARNING";
 
	} else {
		print "OK - No SMVI snapshots exist.\n";
		$exitCondition = "OK";
 
	}
 
	Util::disconnect();
	exit $ERRORS{ $exitCondition };
}
 
sub getSnaps {
	my ($snapshotTree) = @_;
	my $snapcount = 0;
 
	# uncomment for debugging
	#print "Found snap: " . $snapshotTree->{name} . "\n";
 
	if ( $snapshotTree->{name} =~ /smvi/ ) {
		$snapcount++;
	}
 
	if ($snapshotTree->childSnapshotList) {
		foreach my $childSnapshot (@{$snapshotTree->childSnapshotList}) {
			$snapcount += getSnaps($childSnapshot);
		}
	}
 
	return $snapcount;
}

I’ve set the check to execute once an hour in my environment, as I don’t feel that granularity finer than that is needed…an hour’s worth of change is ok for an SMVI snapshot for me.

Nagios
NetApp
Perl
Scripting
Virtulization

Comments (0)

Permalink

Scripting Games 2010: My Scripts


2010 Scripting Games--I was there!

This is more for my own records.  I know for sure I will be using these as a reference over the next few month.  All my 2010 Scripting Games solutions.

~Glenn

Powershell
Scripting

Comments (1)

Permalink

Scripting Games 2010: PostGame Roundup

2010 Scripting Games
I just submitted my last entry into this years games, and I wanted to capture a few things before I go and get busy. 

The Challenges

In years past the challenges where the equivalent of the scripting combine.  They would test ones ability to solve a logic problem in code. This created a developer friendly zone.  Whereby professional coders (aka developers) would inevitably produce a script that used some –xor feature or .net class I knew nothing about.  I would look back on my script feel incredibly inadequate and try harder.  This always lasted at most 5 days… until this year I never made it past 5 days.

This year the dread pirate Ed Wilson flipped the script. All of a sudden the event resembled a ticket at work.  As I read them I instantly knew how to do x or y, and would jump straight to the extra credit section.  This my friends is where it got interesting.  Every event this year could be solved by a PowerShell newbie, but to hit all the design criteria that would take some skill.

It was this combination that kept me in the games. Looking back it felt more like leveling in a MMO than work.  It wasn’t enough to solve the problem I wanted my stars.

PoshCode

There were a slew of issues with Poshcode V2 during the first couple days of the games.  They were fixed promptly, and the site has preformed admirably ever since.  This is the second year I’ve used PoshCode V2, and would just like to say…

JOEL… SHIP IT ALREADY…. ITS GOOD ENOUGH!!!!!1111

Seriously though, it is a massive upgrade, I’m excited to see what the poshcode.org upgrade may bring!

The Ratings

Judging criteria was put out here.  The short version is as follows.  If the script looks like it works you get two stars.  Every star beyond that is based on meeting the extra design criteria.  Now that is an incredibly open guideline…. and I am completely okay with it.

The same judges judge all the scripts so one liberal judge will give us all 5 stars.  The next judge might not like our approach and only give it three, but that stingy judge will be stingy to all the entries.  (I have some great scripts that got some whacked rankings.  Tell me how this only get’s three stars?)

That being said I would like to propose one change for next year.  We need feedback, why only four stars… did I miss something? Do you not like the formatting?  Did I go off the deep end for no reason and overcomplicated it?  All of these would be valid reasons to deduct points, but the deduction looses it’s real purpose if we can’t pass on the lesson it contains.

I’ll give you an example.  one of my close competitors this year kept creating the help by hand.  After day two or three I left a comment that said

hey great script, but you’re use of a here-string already locks you to V2.  Might as well go whole hog… check out help about_Comment_Based_Help

His very next script included comment based help.. heck he even gave me a shout out for the tip!  Awesome, this is what these games are about!

Except, that script didn’t rate too well… as of event 5 he was back to his old VBScript ways.  Somehow he associated that change with the bad rating… maybe it was part of it, he’s had all 5’s since.  Either way for on brief moment he was on track…

PowerShell Best practices

Which leads me to my final peeve about these games, and something we should fix for next year.  A script that is CLEARLY VBScript written in PowerShell should not get higher than a 3.  This isn’t about prizes or winning either.  These games are a learning event.  If we aren’t teaching best practices along the way what good are we doing anyone? You know simple stuff like don’t use the Scripting.FileSystemObject com object anymore…  I know this is a slippery slope, and I was truly blown away by the overall quality of the submissions. Nevertheless I think it’s a conversation worth having.

Motivation for the Games

As of this post I’m in first place… Looks like I might win this dang thing(what ever that means)!  Still way to early to call. Either way I didn’t participate this year for any monetary prize… I did it for the vanity of it all. I wanted to know where I stacked up.  I never thought I’d win anything… first place came out of left field.  All in all I got exactly what I wanted out of the games.  I do wish the judges had participated, they need only recuse themselves from the event they judge.  I would have liked to compete against a couple MVP’s.

New Tricks

These games forced me to step my game up.  I used EVERY trick I know, and I learned a few knew ones along the way.  Three specific tricks I will not soon forget.

Splatting:

I finally know what spatting is and why it’s a big deal.  Splatting helped me streamline half of my scripts removing 20-30 logic tree’s, by simply creating the parameter set’s upfront. I know we’ve all heard the definition before, but let me show you in code why it matters!

Before Spatting

Param(
    $Credential,
    $Computer = $ENV:COMPUTERNAME
)
End
{
    If ($credential)
    {
        Get-WmiObject win32_ComputerSystem -ComputerName $Computer -Credential $credential
    }
    Else
    {
        Get-WmiObject win32_ComputerSystem -ComputerName $Computer
    }
}

After Splatting

Param(
    $Credential,
    $Computer
)
Begin
{
    $extraparams=@{}
    If ($Computer)
    {
        $extraparams["ComputerName"] = $Computer
    }
    If ($credential)
    {
        $extraparams["Credential"] = $Credential
    }
}
End
{
    Get-WmiObject win32_ComputerSystem @extraparams
}

As you can see splatting allows you to offload all the logic that isn’t related to the task at hand to the the script/function initialization.  This cleans up your working area, and results in cleaner code!

Windows Forms:

Last week I created my very first windows form GUI ever, and I did it by hand.  Not because I’m hardcore, but because once I got started it was REALLY easy.  Like .net itself windows forms have full reflection, meaning it’s all self descriptive from within PowerShell.

Obviously using a tool like PrimalForms will save a ton of time, but don’t feel like you need a third party tool.  This stuff is easier than you’d think!

WPF/WPK:

This was the gut shot that hurt my brain!  WPF was a lot to bit off in one chunk.  After two weeks with it I feel like I still barel y know what I’m doing, but once I do… WPK will make it easy.  WPK’s strength, and weakness come from it’s meta-programming roots.

If you don’t already know, James wrote a script that wrote WPK.  It’s all machine generated code.

The good part, it is 100% complete it can do anything possible in WPF.

The bad part, there is NO abstraction layer between you and WPF.

There are some really cool helper functions that make it easy to use PowerShell code directly.  But if you want to make a listbox you’re going have to look at a c# example. I originally planned on doing event 10 with boots, and I wish I had time… I want to compare the two head to head, but I ran short and wanted to get my final submission in.

Final Thoughts

100% worth the time, These few weeks have sharpened my skill significantly.  To the point where I’ve actually caught up at work.  At this pace I’ll be ahead of schedule next week.  I think it was just the hard break the games carried… forced me out of my rut.

Take a look at my work let me know what you think. I have very thick skin and prefer the truth over candy coated fairy tales.

If you spent this year on the side line… save the excuses.  These games, like learning PowerShell will advance you professionally; ergo they’re good for work; ergo quit you’re bitchin and get to it!  Unless you were at EMC world ;P

In closing I want to personally thank the sponsors and judges who made the games possible this year:

Thank you, Tech·Ed 2010 North America
Thank you, PoshCode.org
Thank you, Microsoft TechNet
Thank you, SAPIEN Technologies
Thank you, Quest Software
Thank you, /n software
Thank you, Software FX
Thank you, 101FreeTechBooks.com
Thank you, ShellTools
Thank you, Idera
Thank you Judges

I had a blast a learned a ton, Good job all, See ya next year!

~Glenn

@extraparams

Powershell
Scripting

Comments (4)

Permalink

PowerCLI: Apply-VMHostProfile passing parameters via $AdditionalConfiguration

I’ve ran across this particular issue myself, and submitted a bug to the PowerCLI team, but shortly after Andrew posted his ESXi 4.0 autoinstall Tim asked about this very issue.  There is a documentation error in Example #5 from the Apply-VMHostProfile cmdlet help.  Which contains the following code example.

$profile = Get-VMHostProfile -Name testProfile            

$additionalConfiguration = Apply-VMHostProfile -ApplyOnly -Profile $profile -Entity 10.23.114.166
$additionalConfiguration['network.hostPortGroup["key-vim-profile-host-HostPortgroupProfile-VMkernel"].ipConfig.IpAddressPolicy.address'] = '10.0.0.128'
$additionalConfiguration['network.hostPortGroup["key-vim-profile-host-HostPortgroupProfile-VMkernel"].ipConfig.IpAddressPolicy.subnetmask'] = '255.255.255.0'            

Apply-VMHostProfile -ApplyOnly -Profile $profile -Entity 10.23.114.166 -Variable $additionalConfiguration

Sadly if you tried to execute the above you would get the following error.

PS > $additionalConfiguration['network.hostPortGroup["key-vim-profile-host-HostPortgroupProfile-VMkernel"].ipConfig.Ip
AddressPolicy.address'] =  "10.52.8.11"
Array assignment to [network.hostPortGrou ..] failed: Cannot convert   value "network.hostPortGroup["key-vim-profile-
host-HostPortgroupProfile-VMkernel"].ipConfig.IpAddressPolicy.address" to   type "System.Int32". Error: "Input string
was not in a correct format.".
At line:1 char:26 + $additionalConfiguration[ <<<< '"network.hostPortGroup["key-vim-profile-host-HostPortgroupProfile-VMkernel"].ipCo nfig.IpAddressPolicy.address'] ='10.52.8.11' + CategoryInfo          : InvalidOperation: (10.52.8.11:String) [], RuntimeException + FullyQualifiedErrorId : ArrayAssignmentFailed
 

At first this may appear a little cryptic, but it get’s a lot clearer once we inspect the object types in use.

PS > $additionalConfiguration.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Object  

PS > $additionalConfiguration[0]

Name                           Value
----                           -----
network.hostPortGroup["key-...

PS > $additionalConfiguration[0].GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     DictionaryEntry                          System.ValueType

The example from the help docs was apparently expecting a Hashtable to be returned from apply-VMhostProfile.  Instead we found an array of DictionaryEntry objects... hence the error.

There are two possible work around's we can employ until the PowerCLI team ships a fix.  The first one is complicated, but dynamic.

<pre class='PowerShellColorizedScript'><span style='color:#ff4500'>$profile</span> <span style='color:#a9a9a9'>=</span> <span style='color:#0000ff'>Get-VMHostProfile</span> <span style='color:#000080'>-Name</span> <span style='color:#8a2be2'>testProfile</span>

<span style='color:#ff4500'>$additionalConfiguration</span> <span style='color:#a9a9a9'>=</span> <span style='color:#0000ff'>Apply-VMHostProfile</span> <span style='color:#000080'>-ApplyOnly</span> <span style='color:#000080'>-Profile</span> <span style='color:#ff4500'>$profile</span> <span style='color:#000080'>-Entity</span> <span style='color:#8a2be2'>10.23.114.166</span>
<span style='color:#000000'>(</span><span style='color:#ff4500'>$additionalConfiguration</span> <span style='color:#a9a9a9'>|</span> <span style='color:#0000ff'>Where-Object</span> <span style='color:#000000'>{</span><span style='color:#ff4500'>$_</span><span style='color:#a9a9a9'>.</span><span style='color:#000000'>Name</span> <span style='color:#a9a9a9'>-eq</span> <span style='color:#8b0000'>'network.hostPortGroup["key-vim-profile-host-HostPortgroupProfile-VMkernel"].ipConfig.IpAddressPolicy.address'</span><span style='color:#000000'>}</span><span style='color:#000000'>)</span><span style='color:#a9a9a9'>.</span><span style='color:#000000'>Value</span> <span style='color:#a9a9a9'>=</span> <span style='color:#8b0000'>'10.0.0.128'</span>
<span style='color:#000000'>(</span><span style='color:#ff4500'>$additionalConfiguration</span> <span style='color:#a9a9a9'>|</span> <span style='color:#0000ff'>Where-Object</span> <span style='color:#000000'>{</span><span style='color:#ff4500'>$_</span><span style='color:#a9a9a9'>.</span><span style='color:#000000'>Name</span> <span style='color:#a9a9a9'>-eq</span> <span style='color:#8b0000'>'network.hostPortGroup["key-vim-profile-host-HostPortgroupProfile-VMkernel"].ipConfig.IpAddressPolicy.subnetmask'</span><span style='color:#000000'>}</span><span style='color:#000000'>)</span><span style='color:#a9a9a9'>.</span><span style='color:#000000'>Value</span> <span style='color:#a9a9a9'>=</span> <span style='color:#8b0000'>'255.255.255.0'</span>

<span style='color:#0000ff'>Apply-VMHostProfile</span> <span style='color:#000080'>-ApplyOnly</span> <span style='color:#000080'>-Profile</span> <span style='color:#ff4500'>$profile</span> <span style='color:#000080'>-Entity</span> <span style='color:#8a2be2'>10.23.114.166</span> <span style='color:#000080'>-Variable</span> <span style='color:#ff4500'>$additionalConfiguration</span></pre>

$VMHostProfile = Get-VMHostProfile -Name testProfile            

$additionalConfiguration = Apply-VMHostProfile -ApplyOnly -Profile $VMHostProfile -Entity 10.23.114.166
($additionalConfiguration | Where-Object {$_.Name -eq 'network.hostPortGroup["key-vim-profile-host-HostPortgroupProfile-VMkernel"].ipConfig.IpAddressPolicy.address'}).Value = '10.0.0.128'
($additionalConfiguration | Where-Object {$_.Name -eq 'network.hostPortGroup["key-vim-profile-host-HostPortgroupProfile-VMkernel"].ipConfig.IpAddressPolicy.subnetmask'}).Value = '255.255.255.0'            

Apply-VMHostProfile -ApplyOnly -Profile $VMHostProfile -Entity 10.23.114.166 -Variable $additionalConfiguration

I actually don't like this approach even though it's a modified version of the included example.  I prefer just a simple static Hashtable.

$VMHostProfile = Get-VMHostProfile -Name testProfile            

$additionalConfiguration = @{
    'network.hostPortGroup["key-vim-profile-host-HostPortgroupProfile-VMkernel"].ipConfig.IpAddressPolicy.address'    = '10.0.0.128'
    'network.hostPortGroup["key-vim-profile-host-HostPortgroupProfile-VMkernel"].ipConfig.IpAddressPolicy.subnetmask' = '255.255.255.0'
}
Apply-VMHostProfile -ApplyOnly -Profile $VMHostProfile -Entity 10.23.114.166 -Variable $additionalConfiguration

All in all, the HostProfile cmdlets are surprisingly complete, and I think the majority of the "issues" I've ran across are a result of the SDK itself.  The Host Profiles sections of the API just don't have the same fit and finish I've come to expect in a VMware API.

I'm sure carter and team will have this fixed in the next release, untill then...

~Glenn

PowerCLI
Powershell
Scripting
VMware

Comments (1)

Permalink

PowerShell: The Admin Development Model, Win32_NetworkLoginProfile, and DateTime objects

While scanning the PowerShell forums this evening I ran accross this question.  Cruisader03 had already answered the question. The solution.. just…. looked too complicated.  After three years of using PowerShell everyday as my primary means of administration… I offer this simple mantra.

 If it looks complex your doing it wrong!… And you’re the second person to read it. 

I just made that up, but I like it!  Seriously though, this is something I’ve started to notice in my own code.  I believe it is an interesting side effect of the Admin Development Model.  

We cut and paste, one line at a time. Until we get it to work.  By the time we finish a script we know that code not as a script, but as a series of lines. (Pay attention, I bet you still read it like a series of one liners).  In that context it looks fine, but wait 24hr’s and look again… not the same is it.   Now that you’re looking at a finished script.   You will start to find all sorts of inefficiencies and poor grammar usage.   So you polish it up a little… rinse and repeat 100 times, and post to PoshCode!  So goes the Admin Development Model.  With that in mind I offer this simple snip it, more a refactor of  Cruisader03 post than a solution.

$name = '.'            

Get-WmiObject Win32_NetworkLoginProfile -ComputerName $name|
    #Filter out any non valid DTG
    Where-Object {$_.LastLogon -match "(?<dtg>\d{14}\.\d{6}\S)(?<offset>\d+)$"}|
    #Foreach valid entry find the last logon dtg
    ForEach-Object {
        # Win32_NetworkLoginProfile formats the utc offset in seconds this
        # Breaks the DateTime parser.  We reformat the string converting
        # the offset back to hours
        $CorrectedDTG = "{0}{1:00}" -f $matches.dtg, ($matches.offset/60)            

        New-Object PSObject -Property @{
            Name=$_.Name
            LogonTime=[datetime]::ParseExact($CorrectedDTG, "yyyyMMddhhmmss.ffffffzz", $null)
        }
    } |
    Sort-Object -Descending LogonTime |
    Select-Object -First 1

~Glenn

Powershell
Scripting

Comments (3)

Permalink