1

I check a file for lines where a char in a special position is missing. If the char is missing, I insert it in that exact location. Now I want to write that new line with that extra char over the old line into the file. For example I have the following in the file:

"C:\\path\test\test"
"C:\\path\test\test2\"
"C:\\path\test\test3\"

After I run my short script, I want it to look like:

"C:\path\test\test\"
"C:\path\test\test2\"
"C:\path\test\test3\"

I try to accomplish that using this little loop:

$content = Get-Content C:\path\to\file.txt
foreach ($line in $content)
{
    if($line[-25] -ne '\') {
        $test = $line -replace '(?<!\\)(?=.{24}$)', '\' | Set-Content C:\path\to\file.txt
    }
    else {
        continue
    }
}

That code does insert me the char at the correct position. But in the end only line one is in the file, instead of all three lines. I think I am close, but just started with powershell.

2 Answers 2

2

Set-Content replaces all the content in a file with the input values. You're calling it independently on each iteration of the loop, when what you really want is to call it with all the results of the loop.

There are many ways to change it, but I would consider replacing foreach with ForEach-Object, and piping the result into Set-Content:

Get-Content C:\path\to\file.txt |
ForEach-Object -Process {
    $line = $_
    if($line[-25] -ne '\') {
        $line -replace '(?<!\\)(?=.{24}$)', '\'
    } else {
        $line
    }
} | Set-Content C:\path\to\file.txt
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, works perfectly! For everyone else, who might have a similar problem, put the Get-Content C:\path\to\file.txt in brackets (Get-Content C:\path\to\file.txt). Otherwise the Set-Content can't access the file, as it is still used by Get-Content.
@BallerNacken good point; you could also write to a separate file, that would do it.
2

As @briantist points out, you need to move the Set-Content outside the for loop to set the entire file at once. Inside the for loop, there is no need for character counting, though. And I find it is better to use the system APIs to work with paths rather than try to write a regex.

Get-Content $inputFileName | Foreach-Object {
  # Strip quotes
  $line = $_ -replace '"',''

  # Add trailing backslash if needed
  $line += '\'

  # Call .NET GetFullPath to normalize. This removes double backslashes
  # and resolves relative paths if needed.
  $line = [System.IO.Path]::GetFullPath($line)

  # Add quotes back, and output string
  '"' + $line + '"'
} | Set-Content $outputFileName

Or, in much condensed form

gc $inputFile | % { [io.path]::GetFullPath((($_+'\') -replace '"','')) } | sc $outputFile

2 Comments

I accepted briantists answer, but will consider yours and test it. thx!
@BallerNacken you should definitely consider using path functions and cmdlets (Split-Path, Join-Path) rather than what you were doing before.

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.