2

Good evening. Stack Overflow and Powershell and RegEx novice here.

The below Powershell code is returning some but not enough parts of the string to make a visual verification. It might be returning the wrong fields.

For example, it is capturing variables in a JSON file for a variable called "CallingApplication". However I need more parts of the string.

Expected results: When I select Item1 checkbox, the below text should appear underneath the check icon and Item 1 text box. (the example CSV file shows enough characters and the results I want) enter image description here

Actual Results: When I select Item1 checkbox, the below texts appears, which is incorrect or lacking enter image description here

Below is the code I have so far. Any help would be appreciated. Please keep answers simple and with examples as I am a newbie. Thank you!

set-location C:\Users\B187515\Downloads\
$file = Get-ChildItem -Path C:\Users\B187515\Downloads\ -filter 
*.json | Sort-Object LastAccessTime -Descending | Select-Object - 
First 1

#Build the GUI
[xml]$xaml = @"
<Window 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window" Title="Initial Window" WindowStartupLocation = 
"CenterScreen"
SizeToContent = "WidthAndHeight" ShowInTaskbar = "True" Background = 
"lightgray"> 
<StackPanel >

<CheckBox x:Name="Item2" Content = 'AgencyGroup DNE' />
<CheckBox x:Name="Item1" Content = 'CallingApplication' />
<CheckBox x:Name="Item16" Content = 'PPVCount' />     
          
<TextBox x:Name='Item1_txt' />      
<TextBox x:Name='Item2_txt' />      
    
           
</StackPanel>
</Window>
"@

$reader=(New-Object System.Xml.XmlNodeReader $xaml)

#Connect to Controls
$Window=[Windows.Markup.XamlReader]::Load( $reader )


# define 1 textbox beneath the variables only
$Item1_txt = $Window.FindName('Item1_txt')
$Item2_txt = $Window.FindName('Item2_txt')



$Item1 = $Window.FindName('Item1')
$Item2 = $Window.FindName('Item2')
$Item16 = $Window.FindName('Item16')
#Events
## Item1
$Item1.Add_Checked({

If ($Item1.IsChecked) { $CA = “CallingApplication" 
Get-Content $file | Select-String -Pattern $CA -Context 2| ForEach- 
Object {
$_.LineNumber
$_.Line
$_.Pattern
$_.Context.PreContext
$_.Context.PostContext

$Item1_txt.Text = $_.LineNumber, $_.Line, $_.Context.PostContext
}
}
else {$CA ="!$!"}
})
$Item1.Add_UnChecked({
$Item1_txt.Text = ""
})

$Item2.Add_Checked({

If ($Item2.IsChecked) { $AG = “'AgencyGroup" 
Get-Content $file | Select-String -Pattern $AG -Context 2| ForEach- 
Object {
$_.LineNumber
$_.Line
$_.Pattern
$_.Context.PreContext
$_.Context.PostContext


$Item1_txt.Text = $_.LineNumber, $_.Line, $_.Context.PostContext
}
}
else {$AG ="!$!"}

})
$Item2.Add_UnChecked({
$Item1_txt.Text = ""
})

$Item16.Add_Checked({

If ($Item16.IsChecked) { $PPVCount = “PPVCount" 
Get-Content $file | Select-String -Pattern $PPVCount -Context 1| 
ForEach-Object {
$_.LineNumber
$_.Line
$_.Pattern
$_.Context.PreContext
$_.Context.PostContext
  

$Item1_txt.Text = $_.LineNumber, 
$_.Line, $_.Context.PreContext, $_.Context.PostContext
    
}
}
else {$PPVCount ="!$!"}

}) 
$Item16.Add_UnChecked({
$Item1_txt.Text = ""
$Item2_txt.Text = ""
})
$Window.Showdialog() | Out-Null

PPVCount in the program only shows lines 1332/1333 Actual results, line 1332/1333 is only showing

PPVCount actually appears on lines 859/860 and 1332/1333 in JSON file. I'd like both lines to appear when I select the checkbox Expected Results: lines 859/860 and lines 1332/1333 appear

0

2 Answers 2

2

In your code, your trying to output what is essentially an array of strings, rather than a single string. This is causing the System.String[] output you see. Its very possible your input is returning multiple strings, creating the array, rather than a single, joined string.

Simple solution is to set the $_.Context.PostContext to a variable, lets call it $postContext, and then on the same line, add a | Join-String -Separator ' '

$postContext = $_.Context.PostContext | Join-String -Separator ' '

Then, use that variable in your output: $Item1_txt.Text = $.LineNumber, $.Line,$postContext, $CA

Sign up to request clarification or add additional context in comments.

4 Comments

Good point re the array. Note that you can simply use string interpolation to get this kind of formatting: $Item1_txt.Text = $.LineNumber, $.Line, "$($_.Context.PostContext)", $CA
Good evening stackoverflow.com/users/13400133/voltaicgrid and stackoverflow.com/users/45375/mklement0 The String Interpolation that VolaICGrid provided worked. Thank you both for your help Now I am getting a different challend. PPVCount is a variable in the .JSON file which appears on different line numbers. When I select the checkbox, the PPVCount string appears only on the furtherest of the restuls.
@mklement0 I updated my original question with the new code (see above). The code now contains PPVCount for Item #16. I tried my best to shorten the code so you can understand. Sorry for any miscommunication. I appreciate your help. Here is the PPVCount output right now on line 1332 but notice it appears on both line 859 and 1332?
Correction, I used the string interpolation that @mklement0 provided,
2

VoltaicGRID's helpful answer gave the crucial pointer with respect to the undesired System.String[] part of your result text: you must explicitly stringify the $_.Context.PostContext array to yield a meaningful text representation, which in your case is most easily achieved with:[1]
$Item1_txt.Text = $_.LineNumber, $_.Line, "$($_.Context.PostContext)"

Additionally, you seemingly want to reflect all matches found by your Select-String calls in the GUI text box.

To that end, you most move the $Item1_txt.Text = assignment outside of the ForEach-Object script block, and use the entire pipeline as an expression, which allows you to collect all matches as single-line strings and join them with a newline (this assumes that your text box can display multiple lines - add TextWrapping="Wrap" to its XAML element):

# Apply this analogously to all similar blocks in your original code.
$Item1_txt.Text = 
  (
    Select-String -LiteralPath $file -Pattern $CA -Context 2 | 
    ForEach-Object {
      [string] $_.LineNumber + ' ' +  $_.Line + ' ' + $_.Context.PostContext
    }
  ) -join [Environment]::NewLine

Note:

  • Each line representing a match is constructed with string concatenation (+):

    • It is sufficient for the first operand to be coerced to [string], in which case all others are implicitly coerced too, if they aren't already strings.
    • In this case, PowerShell implicitly stringifies arrays as it does in string interpolation (inside "..."): that is, the (stringified) elements are space-concatenated.
  • The path of the file whose content to search, $file, is passed directly to Select-String, via its -LiteralPath parameter, which is much faster than piping the file's individual lines to it using Get-Content.


[1] Inside "...", i.e in an expandable (interpolating) string PowerShell stringifies arrays by joining the (stringified) elements with spaces; e.g., "$(@(1, 2, 3))" yields '1 2 3'.
While $_.LineNumber, $_.Line, "$($_.Context.PostContext)" is also an array, the assignment to the [string] typed $Item1_txt.Text property causes the same kind of stringification, but it isn't replied recursively - hence the need to explicitly stringify the nested array.

7 Comments

The issue has been resolved. If I come across more challenges I will create a new post. @mklement
Thank you all for your help. The issue has been resolved. If I come across more challenges I will create a new post. @mklement0 I see you like coffee :)
Glad to hear it, @BigSmooth82. Re coffee: 😁 I do like it, but there's definitely no expectation that others support my habit - if and when they do, it's always appreciated, however.
Hi @mklement0 I hope you are well. You helped me with the above project. I am looking to get your guidance on the same project with a few improvements. It would involve REGEX and Powershell knowledge. I am a novice in both. Would you be willing to help?
I hope you are well. I posted the new question here
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.