This question is more about my understanding Powershell's objects rather than solving this practical example. I know there are other ways of separating out a page number from a string.
In my example I want to do this by accessing the object-match-value of the piped pattern match.
# data
$headerString = 'BARTLETT-BEDGGOOD__PAGE_5 BEECH-BEST__PAGE_6'
# require the number of page only
$regexPageNum = '([0-9]$)'
# split the header string into two separate strings to access page numbers
[string[]]$pages = $null
$pages = $headerString -split ' '
# access page numbers using regex pattern
$pages[0] | Select-String -AllMatches -Pattern $regexPageNum | Select-Object {$_.Matches.Value}
The output is:
$_.Matches.Value
----------------
5
Okay. So far so good. I see the page number of array member pages[0]
But how do I take this value from the object? The following does not work.
$x = $pages[0] | Select-String -AllMatches -Pattern $regexPageNum | Select-Object {$_.Matches.Value}
Write-Host "Here it is:"$x
Output:
Here it is: @{$_.Matches.Value=5}
Instead of assigning the value 5
to the variable $x
Powershell assigns, what looks to me: a hash table with an object description as its only member?
But if I try to access my variable using "Brackets for Access" Reference: hashtables Powershell indicates that variable $x is in fact an array.
x = $pages[0] | Select-String -AllMatches -Pattern $regexPageNum | Select-Object {$_.Matches.Value}
Write-Host "Here it is:"$x
$y = $x[$_.Matches.Value]
Write-Host "What about now:"$y
Output:
Here it is: @{$_.Matches.Value=5}
InvalidOperation:
Line |
33 | $y = $x[$_.Matches.Value]
| ~~~~~~~~~~~~~~~~~~~~~~~~~
| Index operation failed; the array index evaluated to null.
What about now:
Okay. At this stage I know I'm being silly. But the point I'm trying to make is: How can I retrieve the value I want when I'm done with the Powershell object?
CodePudding user response:
You can use $x.{ $_.Matches.Value }
to access the value.
$x = $pages[0] | Select-String -AllMatches -Pattern $regexPageNum | Select-Object { $_.Matches.Value }
$x.{ $_.Matches.Value } # This will print 5
ie, You would have to wrap the property name inside {}
since the property name contains "."
Instead of this way, I would suggest you to create a calculated property using Select-Object
which makes the code more readable.
$x = $pages[0] | Select-String -AllMatches -Pattern $regexPageNum | Select-Object @{Name = 'PageNumber'; Expression = {$_.Matches.Value}}
$x.PageNumber
CodePudding user response:
#Access matches in case of single match
$x = "red blue yellow green" | select-string -Pattern 'blue'
$x.matches.value
#Output
blue
#Access matches in case of multi match
$x = "red blue yellow green blue" | select-string -Pattern 'blue' -AllMatches
$x.matches.value
#Output
blue
blue
CodePudding user response:
When you use a scriptblock as a parameter to Select-Object
the return value will contain a property whose name matches the source code of the script block...
PS> @{ "aaa" = "bbb" } | select-object { $_.aaa; <# xxx #> }
$_.aaa; <# xxx #>
-------------------
bbb
In this pathological case, if I want to access the property I can't use the name in the default "dotted" notation because it contains reserved characters, but you can access it if you quote the property name:
PS> $x = @{ "aaa" = "bbb" } | select-object { $_.aaa; <# xxx #> }
# note the leading and trailing spaces in the string because the
# the original scriptblock source contains spaces between the "{" and "}"
PS> $x.' $_.aaa; <# xxx #> '
bbb
In your case you'd do this:
PS> $x = $pages[0] | Select-String -AllMatches -Pattern $regexPageNum | Select-Object {$_.Matches.Value}
PS C:\Users\Mike> $x.'$_.Matches.Value'
Other options work too:
$x = $pages[0] `
| Select-String -AllMatches -Pattern $regexPageNum `
| Select-Object {$_.Matches.Value}
# get the property whose name is contained in the $name variable
PS> $name = '$_.Matches.Value'
PS> $x.$name
5
# the scriptblock gets converted into a string, and then that string
# is used as a property name
PS> $x.{$_.Matches.Value}
5
# note the whitespace in both scriptblocks has to match *exactly* otherwise the property name won't be found
PS> $x.{ $_.Matches.Value }
ParentContainsErrorRecordException: The property ' $_.Matches.Value ' cannot be found on this object. Verify that the property exists.
but...
There's an easier way - if you pass a hashtable to Select-Object
instead of a scriptblock you can specify the name of the property - e.g.
PS> $x = $pages[0] `
| Select-String -AllMatches -Pattern $regexPageNum `
| Select-Object @{ "l"="Count"; "e"={$_.Matches.Value} }
PS> $x
Count
-----
5
PS> $x.Count
5
References: