Delete elements from an array

I was working on all workstations in a domain and simply building an array with computer names like this

$computersar = @()            
Get-ADComputer -ResultPageSize 10000 -SearchScope Subtree -SearchBase (Get-ADDomain).DistinguishedName -Filter {            
    (OperatingSystem -Like "Windows*7*") -or (OperatingSystem -Like "Windows*XP*")} | ForEach-Object -Process {             
        $computersar += $_.Name            
}

Then I wanted to remove some computers from this array. I’ve tried using the ‘Remove’ method but it failed.
Exception calling “Remove” with “1” argument(s): “Collection was of a fixed size.”

The error message is quite explicit, but this doesn’t explain why there’s a ‘remove’ method.
To discover why, here’s what I did:

# Initialize an empty array            
$array = @()            
# Build a messy array (unsorted with my computername in the middle)            
0..5 | % { $array += 'Test{0:000}' -f ([int]$_) }            
10..15 | % { $array += 'Test{0:000}' -f ([int]$_) }            
$array += $env:computername            
6..9 | % { $array += 'Test{0:000}' -f ([int]$_) }            
16..19 | % { $array += 'Test{0:000}' -f ([int]$_) }            
            
# Display the content            
$array            
            
# Make sure that we have 21 records in the array            
$array.Count             
            
# Use the new -in operator to check that my computername is found in the array            
"$env:computername" -in $array            
            
# Get its index position in the array (12 actually)            
$array.IndexOf("$env:computername")            
            
# Check what type of object we have            
$array.GetType()            
            
# It seems that there's a method named 'remove', let's see how to use it            
$array | gm -MemberType Method | ? Name -eq 'Remove' | Select -ExpandProperty Definition            
            
# Use the 'remove' method to exfiltrate my computername from the array            
try {            
    $array.Remove($array.IndexOf("$env:computername"))            
} catch {            
    $_.Exception.Message            
}            
# Exception calling "Remove" with "1" argument(s): "Collection was of a fixed size."            
            
# As you see the remove method doesn't work            
            
# Let's examine the base array object            
[system.array]| gm -Static            
            
# Check the difference with $array            
$array | gm -Static            
            
# this statement will return true            
$array -is [system.array]            
$array -is [system.object]            
# because it's referenced as type            
$array.psobject.TypeNames            
            
# The array has also a property that indicates that it has a fixed size            
$array.IsFixedSize            
            
# It has a 'Clear' method, that would help that doesn't exist on the $array object            
[system.array]| gm -static | ? Name -eq 'Clear' | Select -ExpandProperty Definition            
            
# Let's try it:            
[system.array]::Clear($array,$array.IndexOf("$env:computername"),1)            
            
# Now this statement will return false             
"$env:computername" -in $array            
            
# Really make sure that the value at index 12 is cleared            
0..($array.Count-1) | % { '{0} -> --{1}--' -f $_,$array[$_]}            
            
# The array size is fixed and hasn't changed            
$array.Count            
            
# If we iterate through the array, we may encounter the empty value we left at index 12            
            
# Wait, we can do better than this            
            
# Step 1: sort the array, so that empty values are located starting at index 0            
[system.array]::Sort($array)            
0..($array.Count-1) | % { '{0} -> --{1}--' -f $_,$array[$_]}            
            
# Step2: reverse the order so that empty values are located at the end of the array            
[system.array]::Reverse($array)            
0..($array.Count-1) | % { '{0} -> --{1}--' -f $_,$array[$_]}            
            
# Step3: resize the array to strip empty values at the end of the array            
[system.array]::Resize([ref]$array,($array.Count-1))            
            
# Make sure the array count is 20            
$array.Count            
            
# Get the content of the array            
0..($array.Count-1) | % { '{0} -> --{1}--' -f $_,$array[$_]}            
            
# We have finally been able to remove a string in the middle of the array            
            
# There's another type of arrays            
$arlist = New-Object System.Collections.ArrayList            
            
# Let's fill the array with the sames values            
0..5 | % { $arlist.Add('Test{0:000}' -f ([int]$_)) | Out-Null}            
10..15 | % { $arlist.Add('Test{0:000}' -f ([int]$_)) | Out-Null}            
$arlist.Add($env:computername) | Out-Null            
6..9 | % { $arlist.Add('Test{0:000}' -f ([int]$_)) | Out-Null}            
16..19 | % { $arlist.Add('Test{0:000}' -f ([int]$_)) | Out-Null}            
            
# Display its content            
$arlist            
            
# Make sure that we have 21 records in the array            
$arlist.Count             
            
# Use the new -in operator to check that my computername is found in the array            
"$env:computername" -in $arlist            
            
# Get its index position in the array (12 actually)            
$arlist.IndexOf("$env:computername")            
            
# Check what type of object we have            
$arlist.GetType()            
$arlist -is [system.array]            
$arlist -is [system.object]            
$arlist.psobject.TypeNames            
            
# Does it have a fixed size ?            
$arlist.IsFixedSize            
            
# See again what's in the array before            
0..($arlist.Count-1) | % { '{0} -> --{1}--' -f $_,$arlist[$_]}            
            
# Remove my computer from the array (using the Remove method)            
$arlist.Remove($env:computername)            
            
# See again what's in the array afterward            
0..($arlist.Count-1) | % { '{0} -> --{1}--' -f $_,$arlist[$_]}            
            
# Get the count            
$arlist.Count

I came across this forum post that also sheds some lights on why the ‘remove’ method exists and failed.

http://social.technet.microsoft.com/Forums/en-US/winserverpowershell/thread/c13ea9bd-dac4-44be-99f7-272a8eb0c55d/

Bonus: I could have used the Select-String cmdlet and simply do:

$array |            
 select-String -Pattern "$env:computername" -NotMatch|            
  % { '--{0}--' -f $_}

We end up with a new array and its count is 20

$newar = $array | select-String -Pattern "$env:computername" -NotMatch            
$newar.Count
Advertisements

One thought on “Delete elements from an array

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s