Back to Basics: A Casting Quandary
I could hear the screams of frustration from miles away!
Not too long after my Skype for Business chimed in... it all became clear... a colleague has been struggling with some seemingly simple PowerShell.
PoshChap to the Rescue
We have a list of Active Directory computer accounts.
$hosts = Get-ADComputer -Filter * -Properties ServicePrincipalName
We need to enumerate a multi-value attribute, ServicePrinicpalName, and check for a specific string. Initially, we need to report on the computer objects where the string is present. Simple, no?
Here's what my colleague sent me...
$hosts | Where-Object {$_.serviceprincipalname -match "MSServer*"} | Format-Table DnsHostName
Which generates the below output containing the desired results.
Now, the source of the screams was the fact that when they reversed the logic, i.e. used the -notmatch operator, the above list would be included in the output!
$hosts | Where-Object {$_.serviceprincipalname -notmatch "MSServer*"} | Format-Table DnsHostName
On initial inspection, this makes little sense and could well be the source of many a scream. However, if you consider that the ServicePrincipalName attribute is multi-valued and that -notmatch will check each of the values in the multi-valued attribute, and that true is returned if just one of those entries isn't matched, then it starts to make more sense.
A Casting Fix
The answer? Cast the returned ServicePrinicpalName attribute as a string, i.e. turn it from a multi-valued array to single-valued string. Look at the [string] prefix below - this performs the cast.
This time -notmatch only searches for the pattern in a single string.
$hosts | ? {[string]$_.serviceprincipalname -notmatch "MSServer*"} | ft DnsHostName
The desired result. The screams fall silent.
Comments
- Anonymous
May 15, 2016
cool stuffthanks