PowerShell: removing elements of an immutable “fixed size” array

By default, PowerShell’s Array is an object class; hence, its length a “fixed size” as an object. Therefore, any pop, splice, or push methods will not work with Array elements in this language as compared to a other languages such as JavaScript and Python. Here are two workarounds to this issue:

  1. Cast the Array object as a  [System.Collections.ArrayList]$ArrayObject; which will effectively convert the $ArrayObject to a “ArrayList” class. Hence, $ArrayObject.GetType().Namewill return “ArrayList“, instead of “Object[]“. This will make it “mutable” or changeable, whereby methods such as .Add() and .Remove() are available. The only downside to this conversion is that ArrayList cannot be multi-dimensional. Hence, the third item on this list is the catch-all technique in dealing with $ArrayObject ‘s.
  2. Convert $ArrayObject to a $Collection type: $Collection = {$ArrayObject}.Invoke() will also create a mutable Collection data type that will expose similar available methods as ArrayList.
  3. Manually filter the Array’s elements against a certain values, then reassign that result to itself. Here are some examples.
# Better Illustration of workaround #3
function validateData{
    param($inputData=$sourcesAndDestinations)
    $objectLength=$inputData.from.length 
    for ($i=0;$i -lt $objectLength; $i++){        
        $from=$inputData.from[$i]
        $to=$inputData.to[$i]
        #"Checking $from and $to ..."
        #if(!(test-path $from) -OR !(test-path $to) ){
        if(!(test-path $to)){
            write-host "$to is not reachable."    
            # Remove row if any path doesn't resolve. Overcome limitations of Powershell's immutable array "fixed size" using this workaround
            $castedArrayList=[System.Collections.ArrayList]$inputData;
            $castedArrayList.RemoveAt($i);
            $inputData=[Array]$castedArrayList; #reversed the casting
            #$inputData.from = $inputData.from|?{$_ -ne $from}
            #$inputData.to = $inputData.to|?{$_ -ne $to}
            $objectLength--;
            $i--;
            } #else{write-host "$to is reachable."}
    }
    return $inputData
}

$sourcesAndDestinations=validateData -inputData $sourcesAndDestinations
# Illustration of workaround #3
$arr=@{}
$arr["from"] = @{}; $arr["to"] = @{}    
#$arr["from"] = @("C:\Temp\Tech_Documentation"); $arr["to"]=@("\\FILESERVER01\Docs")
$arr["from"] += "C:\Temp\Test"; $arr["to"]+="\\FILESERVER01\Test"
$arr["from"] += "C:\InvalidDirectory"; $arr["to"]+="\\FILESERVER01\Void"

function sanitizeObject{
    param($GLOBAL:object=$arr)
    $objectLength=$object.from.count

    for ($i=0;$i -lt $objectLength; $i++){
        $from=$object.from[$i]
        $to=$object.to[$i]
        #"Checking $from and $to ..."
        if(!(test-path $from) -OR !(test-path $to) ){         
            # Remove row if any path doesn't resolve. Overcome limitation of Powershell's immutable array "fixed size"
            #"Removing $($object.from[$i]) and $($object.to[$i]) ..."
            $object.from = $object.from|?{$_ -ne $from}
            $object.to = $object.to|?{$_ -ne $to}

# Decrement object length pointer value to reflect new length and readjust index number
            $objectLength--;
            $i--;
            }
    }
    return $object
}

$arr=sanitizeObject -object $arr

Leave a Reply

Your email address will not be published. Required fields are marked *