Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Wednesday, July 14, 2010 1:52 PM | 1 vote
I am a very new PS user and I seem to be having an issue with array counts. Here's a code example.
$a = @( "dog" ; "dog"; "cat" ; "mouse" )
$b = @()
$b = $a | select-string -pattern "cat"
The value of $b.count = NULL
$b = $a | select-string -pattern "dog"
The value of $b.count = 2 as expected.
So my guess is that there are extra characters returned with the select-strings cmdlet and that somehow messes up the array because
$b = @ ( "dog" )
$b.count = 1
How can this be addresses? Is there a way to cleanup the return data form the select-string cmdlet? Is this a bug?
Thanks
All replies (8)
Wednesday, July 14, 2010 2:18 PM ✅Answered | 2 votes
You're getting bitten by Powershell's automatic typecasting. If an expression only retuns a single object, the reult will be cast as a scalar (single object). If it returns multiple objects, the result will be cast as an array. The array will have a count property, but the scalar will not, so the .count will evaluate to null.
To fix it, you can force the result to always be an array, just like you did with $b = @ ( "dog" ).
$b = @($a | select-string -pattern "cat")
In your example, you initialize $b as an array, but then replace it with the scalar value from the select-string expression. You can maintain the array type if you use array concatenation on $b instead of replacing it:
$b = @()
$b += $a | select-string -pattern "cat"
[string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "
Wednesday, July 14, 2010 2:53 PM ✅Answered | 1 vote
The object returned by Select-String is a "Microsoft.PowerShell.Commands.MatchInfo"
So, the $b = $a | select-string -pattern "cat" basically kills your original array $b, and creates a new $b variable, of type "Microsoft.PowerShell.Commands.MatchInfo"
$b = $a | select-string -pattern "dog" returns an array of "Microsoft.PowerShell.Commands.MatchInfo" objects.
To work around this, you need to convert the output to an array:
[ARRAY]$b = $a | select-string -pattern "cat" WILL create an array, $b.count will return 1, and if you look, you will see that #b consists of:
cat
(That's 1 blank line, 1 "cat", and a final blank line.)
Of course, IF you do $a | select-string -pattern "dog" you will get 2 "dog" and 2 blank lines.
$b[0].Matches will show:
Groups : {cat}
Success : True
Captures : {cat}
Index : 0
Length : 3
Value : cat
If you do the $b = $a | select-string -pattern "dog", you have an array of "Microsoft.PowerShell.Commands.MatchInfo" objects, so $b[1].Matches will return:
Groups : {dog}
Success : True
Captures : {dog}
Index : 0
Length : 3
Value : dog
Karl
http://unlockpowershell.wordpress.com
-join("6B61726C6D69747363686B65406D742E6E6574"-split"(?<=\G.{2})",19|%{[char][int]"0x$_"})
Wednesday, July 14, 2010 8:00 PM ✅Answered | 2 votes
Interesting. I would use the -match operator instead. That way you get back an array that has a count property:
$a = @( "dog" ; "dog"; "cat" ; "mouse" )
$b = $a -match 'cat'
$b.count
1
Shay Levy [MVP]
http://blogs.microsoft.co.il/blogs/ScriptFanatic
PowerShell Toolbar
Wednesday, July 14, 2010 3:13 PM
Thank you very much. That fixed an issue I was having with one of my scripts.
Wednesday, July 14, 2010 4:50 PM
Thanks Karl for the addition info. Why are there blank lines? Is that due to the return type of select-string? Is there a way to filter these out? It doesn't seems like they impact the results in this case, but I'm wondering if they would in other cases.
Wednesday, July 14, 2010 10:39 PM
Well ... That was easy ;-) Thanks Shay. I'm still wondering about the new lines though. select-string vs -match
Wednesday, July 14, 2010 11:29 PM
Select-string produces a matchinfo object. It has both a pre and post context property. If you don't specify it, it's null, but it's still there and included in the default display.
[PS] C:\$a = "dog","cat","pig"
[PS] C:\$a | select-string "cat" | fl *
IgnoreCase : True
LineNumber : 2
Line : cat
Filename : InputStream
Path : InputStream
Pattern : cat
Context :
Matches : {cat}
[PS] C:\$a | select-string "cat"
cat
You sepcify how many lines before and after (pre-context and post-context) with the -context switch:
[PS] C:\$a | select-string "cat" -context (1,1)
dog
> cat
pig
The actual content of the matched line is in the .line property. To get just that without the context information:
[PS] C:\$a | select-string "cat" |% {$_.line}
cat
[string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "
Wednesday, July 14, 2010 11:45 PM
On 7/14/2010 5:39 PM, jvtechnet wrote:
> ... I'm still wondering about the new lines though.
> select-string vs -match
>
After
$a = @( "dog" ; "dog"; "cat" ; "mouse" )
$b = @()
$b = $a | select-string -pattern "cat"
Try
$b.GetType()
to see that the type of $b is actually MatchInfo.
- Larry