Hashtables: Introduction

I was recently working on a script for a co-worker who is trying to learn more powershell. In the script I had used a couple of hashtables to store information…which caused a couple of questions as he was reviewing the code. This post is an introduction to powershell hashtables.

A hashtable stores indexed key-value pairs in memory and is similar to the vbscript dictionary object. To help describe these concepts, I have listed a few examples based on a CSV file containing HTML color codes.

The examples below will:
1.) Import the CSV into a powershell array object,
2.) Show how to use the array object to return a specific code given a color name
3.) Convert the object from step 1 into a hashtable
4.) Show how to use the hashtable to return a specific code given a color name

[cc lang=”Powershell”]
# Example 1:
$colorCodes = Import-Csv ColorCodes.csv

# Example 2:
# Using just the array object created from Import-CSV
# we can select the color code for Red with just one line
($colorCodes | Where-Object {$_.ColorName -eq ‘Red’}).Code

# Example 3:
# We could also create a hash table and store each item
# from the array using a couple lines of code
$colorCodeHT = @{}
$colorCodes | %{ $colorCodeHT.Add($_.ColorName, $_.Code) }

# Example 4
# And then we can retreive the code for red using either of the
# examples below. Note: you only need one as they return the same
# value. The first sample is my preferred method, but either works.
$colorCodeHT[‘Red’]
$colorCodeHT.Item(‘Red’)
[/cc]

Posted in Scripting | Leave a comment

Using ADSI to clear an attribute

I have many scripts that write information into Active Directory. Sometimes I need to do the opposite — remove or blank out an attribute.

All of the following examples will require a distinguishedName value in AD, so I will set a common variable here. You will need a valid distinguishedName defined in a varible like this if you want to follow along.

$distinguishedName = "CN=Brian Wuchner,OU=Test Users,DC=bwuch,DC=local"

The first test we will do is to update the displayName of the user. This is easy…we don’t care what the existing value is, we are just going to set it to whatever string value we want. We will do this by creating an object representing the Directory Entry of my user, updating the displayName attribute of that object and finally updating/committing that change back to the directory as follows.
[cc lang=”powershell”]
$objUser = New-Object DirectoryServices.DirectoryEntry “LDAP://$distinguishedName”
$objUser.displayName=”Wuchner, Brian”
$objUser.SetInfo()
[/cc]

That is a rather straight forward process. However, it becomes slightly more complex if we want to clear the attribute and make it null. One would think you could simply think you could set the displayName equal to $null using something like this:
[cc lang=”powershell”]
$objUser = New-Object DirectoryServices.DirectoryEntry “LDAP://$distinguishedName”
$objUser.displayName=$null
[/cc]

However, if you try that you will most likely get a chance to see the following error message:

Exception setting "displayName": "Value cannot be null.

As a follow up, you might think “I’ll just set the attribute to an empty string” like this:
[cc lang=”powershell”]
$objUser = New-Object DirectoryServices.DirectoryEntry “LDAP://$distinguishedName”
$objUser.displayName=””
$objUser.SetInfo()
[/cc]

The only problem with that…setinfo will fail with the following error.

setinfo : Exception calling "setinfo" with "0" argument(s): "The attribute syntax specified to the directory service is invalid.

Does that mean its time to give up? Are we just going to have to live with bad data in AD? Never!

There are at least two ways to clean this up. The first way is my favorite (I’ve been using it since vbscript). You simply need to refer to the Microsoft article HOW TO: Use ADSI to Set LDAP Directory Attributes and you’ll realize this can be accomplished with PutEx.
[cc lang=”powershell”]
$objUser = New-Object DirectoryServices.DirectoryEntry “LDAP://$distinguishedName”
$objUser.PutEx(1, ‘displayName’, 0)
$objUser.SetInfo()
[/cc]

In the above example, we use the constant ADS_PROPERTY_CLEAR by placing a ‘1’ as the first argument in our method, then specifying the displayName as the attribute we want to clear, and finishing up by providing the desired value. Since we want the value to be clear, and we’ve already specified the ‘1’ to clear, we just need to specify something so the method has enough parameters. I use 0 just for fun.

Another option is to call the Remove method and specify the value we want to remove. The downside is the attribute MUST have a value or you get an error when trying to clear it. We can overcome that with a simple if statement like this:
[cc lang=”powershell”]
$objUser = New-Object DirectoryServices.DirectoryEntry “LDAP://$distinguishedName”
if ($objUser.displayName) {
$objUser.displayName.Remove(“$($objUser.displayName)”)
$objUser.SetInfo()
}
[/cc]

It doesn’t matter which of the options I use, the end result is the same — a clear attribute. I hope this post helps if you ever need to clear out an attribute.

Posted in Messaging, Scripting | 2 Comments

Remove vCenter Scheduled Tasks with PowerCLI (Part 3)

In my most recent series on vCenter Scheduled Tasks with PowerCLI, I have provided three functions…Get-VIScheduledTasks, Get-VMScheduledSnapshots, and New-VMScheduledSnapshot. To complete the series, I have a final function Remove-VIScheduledTask. I don’t really see the need for this one, as you can easily bulk select scheduled tasks in the vCenter UI and delete them with a single click. However, in the interest of completeness, here is a rough function that will delete a vSphere scheduled task. [A more robust/efficient/complete function could be written that would accept input from the pipeline. If there is a good use case for this please leave a comment below.]

NOTE: This function requires an additional function: Get-VIScheduledTasks to find the task by name. In addition the usage example below requires Get-VMScheduledSnapshots. Both functions are available here: New vCenter Scheduled Tasks with PowerCLI (Part 1).

[cc lang=”Powershell”]
Function Remove-VIScheduledTask {
PARAM ([string]$taskName)
(Get-View -Id ((Get-VIScheduledTasks -Full | ?{$_.Name -eq $taskName}).ScheduledTask)).RemoveScheduledTask()
}
[/cc]

Usage example:

# This example will find all VM Scheduled Snapshots which 
# are not scheduled to run again, then remove each one by name.
Get-VMScheduledSnapshots | 
?{$_.NextRunTime -eq $null} | %{ Remove-VIScheduledTask $_.Name }
Posted in Scripting, Virtualization | 2 Comments

New vCenter Scheduled Tasks with PowerCLI (Part 2)

In a recent post New vCenter Scheduled Tasks with PowerCLI (Part 1), I provided two functions that return information related to vCenter Scheduled Tasks. This was my first step towards creating a PowerShell function that I could run to create scheduled snapshot tasks. This post will cover the create scheduled snapshot function.

NOTE: This function requires two additional functions, Get-VMScheduledSnapshots and Get-VIScheduledTasks, available here: New vCenter Scheduled Tasks with PowerCLI (Part 1).

[cc lang=”powershell”]
Function New-VMScheduledSnapshot {
PARAM (
[string]$vmName,
[string]$runTime,
[string]$notifyEmail=$null,
[string]$taskName=”$vmName Scheduled Snapshot”
)

# Verify we found a single VM
$vm = (get-view -viewtype virtualmachine -property Name -Filter @{“Name”=”^$($vmName)$”}).MoRef
if (($vm | Measure-Object).Count -ne 1 ) { “Unable to locate a specific VM $vmName”; break }

# Validate datetime value and convert to UTC
try { $castRunTime = ([datetime]$runTime).ToUniversalTime() } catch { “Unable to convert runtime parameter to date time value”; break }
if ( [datetime]$runTime -lt (Get-Date) ) { “Single run tasks can not be scheduled to run in the past. Please adjust start time and try again.”; break }

# Verify the scheduled task name is not already in use
if ( (Get-VIScheduledTasks | ?{$_.Name -eq $taskName } | Measure-Object).Count -eq 1 ) { “Task Name `”$taskName`” already exists. Please try again and specify the taskname parameter”; break }

$spec = New-Object VMware.Vim.ScheduledTaskSpec
$spec.name = $taskName
$spec.description = “Snapshot of $vmName scheduled for $runTime”
$spec.enabled = $true
if ( $notifyEmail ) {$spec.notification = $notifyEmail}
($spec.scheduler = New-Object VMware.Vim.OnceTaskScheduler).runAt = $castRunTime
($spec.action = New-Object VMware.Vim.MethodAction).Name = “CreateSnapshot_Task”
$spec.action.argument = New-Object VMware.Vim.MethodActionArgument[] (4)
($spec.action.argument[0] = New-Object VMware.Vim.MethodActionArgument).Value = “$vmName scheduled snapshot”
($spec.action.argument[1] = New-Object VMware.Vim.MethodActionArgument).Value = “Snapshot created using $taskName”
($spec.action.argument[2] = New-Object VMware.Vim.MethodActionArgument).Value = $false # Snapshot memory
($spec.action.argument[3] = New-Object VMware.Vim.MethodActionArgument).Value = $false # quiesce guest file system (requires VMware Tools)

[Void](Get-View -Id ‘ScheduledTaskManager-ScheduledTaskManager’).CreateScheduledTask($vm, $spec)
Get-VMScheduledSnapshots | ?{$_.Name -eq $taskName }
}
[/cc]

# Create a snapshot of the VM test002 at 9:40AM on 3/2/13
New-VMScheduledSnapshot test002 "3/2/13 9:40AM"

# Create a snapshot and send an email notification
New-VMScheduledSnapshot test002 "3/2/13 9:40AM" myemail@mydomain.com

# Use all of the options and name the parameters
New-VMScheduledSnapshot -vmname 'test001' -runtime '3/2/13 9:40am' -notifyemail 'myemail@mydomain.com' -taskname 'My scheduled task of test001'

I hope someone finds this function useful.

Posted in Scripting, Virtualization | 11 Comments

Get vCenter Scheduled Tasks with PowerCLI (Part 1)

I work with a lot of scheduled tasks. Typically, these tasks run powershell scripts from the Windows Task Scheduler. However, when working with simple VMware tasks (like creating snapshots right before a maintenance window) I like to use the Scheduled Tasks feature from right inside vCenter. The other day I thought it would be interesting if I had a PowerShell function that I could run to create these snapshot tasks. The first step in this process is to figure out what tasks we already have…and understand where some of these properties are located using PowerCLI.

The following two functions can be used to get information on Scheduled Tasks inside vCenter. The first function Get-VIScheduledTasks will simply return a list of all scheduled tasks that exist in a vCenter environment. I picked out a handful of properties that I figured would be needed and return those by default, casting the date/time values into local time. If you need all of the properties (the native .Net view of the Scheduled Task Info objects) you can include the parameter -Full and all of the properties will be returned.

[cc lang=”powershell”]
Function Get-VIScheduledTasks {
PARAM ( [switch]$Full )
if ($Full) {
# Note: When returning the full View of each Scheduled Task, all date times are in UTC
(Get-View ScheduledTaskManager).ScheduledTask | %{ (Get-View $_).Info }
} else {
# By default, lets only return common headers and convert all date/times to local values
(Get-View ScheduledTaskManager).ScheduledTask | %{ (Get-View $_ -Property Info).Info } |
Select-Object Name, Description, Enabled, Notification, LastModifiedUser, State, Entity,
@{N=”EntityName”;E={ (Get-View $_.Entity -Property Name).Name }},
@{N=”LastModifiedTime”;E={$_.LastModifiedTime.ToLocalTime()}},
@{N=”NextRunTime”;E={$_.NextRunTime.ToLocalTime()}},
@{N=”PrevRunTime”;E={$_.LastModifiedTime.ToLocalTime()}},
@{N=”ActionName”;E={$_.Action.Name}}
}
}
[/cc]

This next function calls above function, but only returns the tasks whose action is “CreateSnapshot_Task”
[cc lang = “Powershell”]
Function Get-VMScheduledSnapshots {
Get-VIScheduledTasks | ?{$_.ActionName -eq ‘CreateSnapshot_Task’} |
Select-Object @{N=”VMName”;E={$_.EntityName}}, Name, NextRunTime, Notification
}
[/cc]

Sample usage would be:

# To find all tasks that failed to execute last run
Get-VIScheduledTasks | ?{$_.State -ne 'success'}

# To find all snapshots that are not scheduled to run again:
Get-VMScheduledSnapshots | ?{$_.NextRunTime -eq $null}

I hope you find these functions useful. Be sure to check out the next post – on creating scheduled snapshots with PowerCLI!

Posted in Scripting, Virtualization | 10 Comments