0

As part of a bigger script I need to verify a file contents before continuing. However, it's not working when I use | Out-String.

Note this needs to work under powershell v2 unfortunately. The file I am looking at contains the data:

{"somedata":5,"hello":[]}

If I remove | Out-String from the command then it tells me the file matches.

But if I add data to the file, then it still tells me the file matches when it doesn't. If I add | Out-String then it tells me the file doesn't match when it does...

$filecheck = Get-Content ("C:\temp\hello.txt") | Out-String
Write-Host $filecheck
if ($filecheck -eq '{"somedata":5,"hello":[]}') {
    Write-Host "file matches"
} else {
    Write-Host "doesn't match"
}
3
  • Why do you pipe it into Out-String? Your code works if you remove that. Commented Apr 4, 2018 at 10:05
  • because if there are any additional lines in the file then it still evaluates to true when it's not. Commented Apr 4, 2018 at 10:45
  • OK, I see. I only tried with one line in the file. Commented Apr 4, 2018 at 10:50

2 Answers 2

6

As how to fix the issue, see @tukan's answer. Anyway, for learning purposes, let's explore the root cause, namely using the Out-String cmdlet. It actually adds a newline to the string. Like so,

PS C:\temp> $filecheck = Get-Content ("C:\temp\hello.txt") | Out-String
PS C:\temp> write-host $filecheck
{"somedata":5,"hello":[]}

PS C:\temp>

As the data contains a newline, it isn't equal to the string literal used in the if statement. Thus the comparison fails. Remove the Out-String and it works:

PS C:\temp>$filecheck = Get-Content ("C:\temp\hello.txt")
PS C:\temp> $filecheck
{"somedata":5,"hello":[]}
PS C:\temp> $filecheck -eq '{"somedata":5,"hello":[]}'
True
PS C:\temp>

Earlier you noted that Out-String was needed as otherwise adding data would still make the comparison to fail. Why is that? Let's say the data in file is

{"somedata":5,"hello":[]}
{"moredata":1,"foo":bar}

What now happens is that Get-Content will give you an array of strings. The 2nd line consists of {"moredata":1,"foo":bar} plus a newline. Passing such a construct to the comparison will evaluate just the first element, thus a match.

When you pass an array to Out-String, the result is actually a string with data, newline, data and extra newline:

PS C:\temp> $filecheck|out-string
{"somedata":5,"hello":[]}
{"moredata":1,"foo":bar}

PS C:\temp>

This obviously isn't equal to the string literal used in the if statement.

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

2 Comments

Good problem analysis. I'm not sure Tukan's answer is a proper solution to the problem, though, since the OP seems to want to check the entire content of a JSON file. $filecheck = (Get-Content "C:\temp\hello.txt" | Out-String).Trim() is probably a better approach.
yes perfect thank you! the trim will work as I wasn't aware it was adding a new line when using out-string
1

Edit - the script will exit on first match.
Edit2 - you don't need the Else branch if nothing is found print 'failed' at the end suffice.

What about piping into Foreach-Object like this:

 (Get-Content 'C:\<our_path>\test.txt') |
        Foreach-Object { If ($_ -eq '{"somedata":5,"hello":[]}') {write-host 'matches'; exit}} 
 write-host 'failed'

I have kept your format of -eq, even thou, I would recommend regex for string/text search.

4 Comments

This gives a line-by-line comparison of the file, not sure if this is what the OP wants?
@JamesC you are right. Hard to say from the question.
hi, see what you mean yes this would work but it I only want it to match on the complete file with the first string.
@Ian you mean exit on first occurrence? If yes, see my edit.

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.