Add Content to a specific line in powershell

I have seen this post: Add-Content - append to specific line

But I cannot add these lines because "Array index is out of range".

What my script is doing:

  1. Find the line
  2. Loop through the array that contains the data i want to add
  3. $file[$line]+=$data
  4. $line+=1
  5. Write to file

Should I create a new file content and then add each line of the original file to it? IF so, do you know how to do that and how to stop and add my data inbetween?

thank you!

--EDIT-- I cannot post the whole code because it is stored on a VM and i cannot copy contents into my actual computer. But here is the part where I try to add:

$f=Get-Content $path
$ct=$begin+1 #$begin is the line where i want to place content under
foreach($add in $add_to_yaml)
{
     $f[$ct]+=$add
     $ct+=1
}
$f | Out-File -FilePath $file

1 answer

  • answered 2022-05-04 10:45 Mathias R. Jessen

    Let's break down your script and try to analyze what's going on:

    $f = Get-Content $path
    

    Get-Content, by default, reads text files and spits out 1 string per individual line in the file. If the file found at $path has 10 lines, the resulting value stored in $f will be an array of 10 string values.

    Worth noting is that array indices in PowerShell (and .NET in general) are zero-based - to get the 10th line from the file, we'd reference index 9 in the array ($f[9]).

    That means that if you want to concatenate stuff to the end of (or "under") line 10, you need to specify index 9. For this reason, you'll want to change the following line:

    $ct = $begin + 1 #$begin is the line where i want to place content under
    

    to

    $ct = $begin 
    

    Now that we have the correct starting offset, let's look at the loop:

    foreach($add in $add_to_yaml)
    {
         $f[$ct] += $add
         $ct += 1
    }
    

    Assuming $add_to_yaml contains multiple strings, the loop body will execute more than once. Let's take a look at the first statement:

    $f[$ct] += $add
    

    We know that $f[$ct] resolves to a string - and strings have the += operator overloaded to mean "string concatenation". That means that the string value stored in $f[$ct] will be modified (eg. the string will become longer), but the array $f itself does not change its size - it still contains the same number of strings, just one of them is a little longer.

    Which brings us to the crux of your issue, this line right here:

    $ct += 1
    

    By incrementing the index counter, you effectively "skip" to the next string for every value in $add_to_yaml - so if the number of elements you want to add exceeds the number of lines after $begin, you naturally reach a point "beyond the bounds" of the array before you're finished.

    Instead of incrementing $ct, make sure you concatenate your new string values with a newline sequence:

    $f[$ct] = $f[$ct],$add -join [Environment]::Newline
    

    Putting it all back together, you end up with something like this (notice we can discard $ct completely, since its value is constant an equal to $begin anyway):

    $f = Get-Content $path
    
    foreach($add in $add_to_yaml)
    {
        $f[$begin] = $f[$begin],$add -join [Environment]::Newline
    }
    

    But wait a minute - all the strings in $add_to_yaml are simply going to be joined by newlines - we can do that in a single -join operation and get rid of the loop too!

    $f = Get-Content $path
    $f[$begin] = @($f[$begin];$add_to_yaml) -join [Environment]::Newline
    $f | Out-File -FilePath $file
    

    Much simpler :)

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum