Nigel Boulton's Blog
28Feb/113

Converting a PowerShell Array into a .Net Framework ArrayList

I was writing a PowerShell script earlier today and needed to take some data I had in an array and put it into a .Net Framework ArrayList. It took me some searching online to find out how to do this so I thought I’d blog it here…

ArrayLists are a powerful way of managing data – one of their biggest advantages is that it is easy to manipulate data by adding or removing elements, as shown below. With default PowerShell arrays there is no simple way to remove elements.

To demonstrate how ArrayLists work, try this code:

$ArrayList = New-Object System.Collections.ArrayList
$ArrayList.Add("New Element 1")
$ArrayList.Add("New Element 2")
$ArrayList.Count
$ArrayList.Remove("New Element 2")
$ArrayList.Count

Note that the return value from the Add method is the element number that was added. You can always cast this to void or pipe it to Out-Null if you don’t need it.

You can also specify where to add or remove elements:

$ArrayList.Add(0,"New Element 3") 	# Adds an element at the beginning of the array list
$ArrayList.RemoveAt(0) 				# Removes the first element

Anyway, back to the point... I had an array containing a list of files (which came from Get-ChildItem), and I wanted to create an ArrayList and populate this with that data, because I wanted to be able to remove each file from the list later on in the script. There are two approaches that can be used for this:

From an existing array:

$arrFiles = Get-ChildItem
$colFiles = New-Object System.Collections.ArrayList
$colfiles.AddRange($arrFiles)

Or more simply, populate the ArrayList directly:

$colFiles = New-Object System.Collections.ArrayList(,(Get-ChildItem))

Note the comma within the parameters – the comma is the array construction operator in PowerShell.

Forgive my artistic license in choosing a title for this post – we’re not really converting an array as such, but I thought it would be the most likely thing somebody seeking this information would search for.

Filed under: PowerShell 3 Comments
7Feb/110

Checking whether a Hotfix is installed on Multiple Machines using PowerShell Remoting

In my last post, I said that I would post a way of verifying whether a particular hotfix had been installed on a number of machines, so here it is...

This approach uses good old PowerShell remoting again - as I have said before, this is an incredibly powerful way of executing PowerShell code on a number of machines, and well worth investing the time to set it up in your environment.

...So, I'd deployed the hotfix to all the servers in the farm, and I needed a quick way of verifying that it had been successfully installed on each of them. This was a variation on an approach I'd taken in the past (an enhancement kindly provided by Jeffrey Snover) - with one important difference: this time I was making good use of the PowerShell custom objects that the script returns. The script code is shown below:

$Servers = $(1..176 | foreach {"SERVER$_"})

Invoke-Command -ComputerName $Servers -ScriptBlock {
	$Result = Get-Hotfix | where {$_.hotfixid -eq 'KB2464876'}
	if ($Result) {
        New-Object PSObject -Property @{Host = hostname; Value = $true}
    } else {
		New-Object PSObject -Property @{Host = hostname; Value = $false}
    }
}

Running this script as shown below allowed me to get a quick indication of any servers that did not have the hotfix installed. This was achieved by querying for returned custom objects whose "Value" property was not equal to True:

./Check-Hotfix.ps1 | Where-Object {$_.Value -ne $True} | Select-Object Host

...and the result was:

Host
----

As I got no servers returned in the result (which of course is good), I wanted a confidence check, so I ran it this way to prove that the code was in fact running as expected:

./Check-Hotfix.ps1 | Where-Object {$_.Value -ne $False} | Select-Object Host

Host
----
SERVER1
SERVER2
SERVER3
SERVER4
.

As I mentioned in my last post, there are a number of ways you can build the list of servers. I used a numbered range, but by simply substituting the line which sets the $Servers variable, you can easily read a list of machine names from a text file (or a CSV file of course):

$Servers = Get-Content '\\Fileserver\Hotfixes\ServerList.txt'

Variations on the above approach can potentially allow you to do almost anything that you can do with PowerShell locally, across your entire server estate. For example, recently I used the same method to check which servers had a specific unwanted value in one of the Terminal Server "shadow" keys. This rogue value was being written into user profiles when users were directed to the servers in question and causing unexpected behaviour in subsequent sessions.

One of the best things about this is that, in most cases, you can develop and test the functional part of the code locally and then simply drop it into the scriptblock. Nice!

Filed under: PowerShell No Comments