One thing that I occasionally forget (and it can take me a while to remember the fix) is some apparently strange behaviour when processing an array. Sometimes array-based methods don’t work when there’s only one item (or no items!) to be processed.
It’s all down to PowerShell’s automatic type conversion and is pretty easy to fix.
The bugs for this come up when I write scripts to process a list of objects, normally from a CSV or the pipeline. I write the code to process the array after it’s been created and it’s all great! Then later on I get some bizarre behaviour when the list of items to process is empty or only has one entry.
So let’s say we had a CSV file like;
Name,EMail Herring,herring@herringsfishbait.com
If I then import that into a variable;
$Records=Import-CSV c:\names.csv
I can then see the following;
$Records.Count -eq 0 False $Records.Count -gt 0 False
So PowerShell returns the count of items in $Records is neither equal to 0 nor greater than 0. Any logic in my script that uses that comparison would see some odd results, to say the least.
I get a straight error if I tried to add a new record to the variable;
PS C:\Users\Neil> $Records+=New-Object -TypeName PSObject -Property @{Name="Newuser";Email="Newuser@herringsfishbait.com "} Method invocation failed because [System.Management.Automation.PSObject] does not contain a method named 'op_Addition'. At line:1 char:1 + $Records+=New-Object -TypeName PSObject -Property @{Name="Newuser";Em ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (op_Addition:String) [], RuntimeException + FullyQualifiedErrorId : MethodNotFound
Both of these problems come from the fact that $Records isn’t, in fact, an array. In the case where I’ve imported a CSV with only one record, PowerShell helpfully sets the type of $Records to an Object, rather than an array;
PS C:\Users\Neil> $Records.GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True False PSCustomObject System.Object PS C:\Users\Neil> @("1","2").GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True Object[] System.Array
So in order to stop this happening, you need to force PowerShell to set $Records to an array (cast it to an array) even if there’s only one element being imported into it. Then everything works as you expect.
PS C:\Users\Neil> [PSObject[]]$Records=Import-csv D:\temp\test.csv PS C:\Users\Neil> $Records.GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True PSObject[] System.Array PS C:\Users\Neil> $Records.Count 1
You could also do;
PS C:\Users\Neil> $Records2=@(Import-csv D:\temp\test.csv) PS C:\Users\Neil> $Records2.Count 1
THANK YOU! I was using an AD object searcher to store results then adding additional results to that same collection.
Example:
$colResults = @()
$colResults = $objSearcher.FindAll()
$objSearcher.SearchRoot = “another OU”
$colResults += $objSearcher.FindAll()
This worked on every datacenter except for one and was driving me nuts! Your article led me to:
$colResults = @($objSearcher.FindAll())
$colResults += $objSearcher.FindAll()
Thank you much!
That’s brilliant it helped! I still forget this sometimes, I’m hoping writing the post would help me remember 🙂
Thanks..