Skip to content
PowerShell FAQs
PowerShell FAQs
  • Home
  • PowerShell Commands
  • Start Here
    • Variables
    • Data Types
    • Array
    • Files
    • String
    • Datetime
  • Download
  • Blogs

How to Read a File Line by Line in PowerShell

Last Modified Date: October 4, 2026 by Bijay Kumar

To read a file line by line in PowerShell, loop over Get-Content. It returns one string per line, so a foreach loop handles each line in turn:

foreach ($line in Get-Content -Path C:\psfaqs\servers.txt) {
    "Checking $line"
}

Output:

Checking WEB01
Checking WEB02
Checking SQL01
Checking FILE01

Below I cover line numbers, reading into an array, the first and last lines, skipping a header, and one encoding problem in Windows PowerShell 5.1. I ran every example in PowerShell 7.6 and 5.1.

This Tutorial Covers:

Toggle
  • Show line numbers
  • Read a file into an array
    • The one-line file trap
  • Read the first or last line
  • Skip the first line
  • Why do special characters look wrong in Windows PowerShell 5.1?
  • Reading very large files
  • Frequently Asked Questions
    • How do I read a file line by line in PowerShell?
    • How do I read only the first line of a file?
    • How do I skip the first line of a file in PowerShell?
    • Why does $lines[0] return only one letter?
    • How do I get the line number while reading a file?

Show line numbers

Every line that Get-Content returns carries its line number in a ReadCount property, so you don’t need your own counter:

Get-Content -Path C:\psfaqs\servers.txt | ForEach-Object {
    "Line $($_.ReadCount): $_"
}

Output:

Line 1: WEB01
Line 2: WEB02
Line 3: SQL01
Line 4: FILE01
PowerShell read a file line by line with line numbers from ReadCount
Each line knows its own line number (PowerShell 7)

If you only need the total, see counting lines in a file.

Read a file into an array

Assign Get-Content to a variable and you have an array of lines. Index it like any other array, and use -1 for the last line:

$lines = Get-Content -Path C:\psfaqs\servers.txt

"Lines:  $($lines.Count)"
"First:  $($lines[0])"
"Last:   $($lines[-1])"
"Second and third: $($lines[1..2] -join ', ')"

Output:

Lines:  4
First:  WEB01
Last:   FILE01
Second and third: WEB02, SQL01

The one-line file trap

If the file has only one line, Get-Content returns a single string instead of an array. Indexing a string gives you letters:

$lines = Get-Content -Path C:\psfaqs\one-line.txt
"Without @(): first = [$($lines[0])], rest = [$($lines[1..($lines.Count - 1)] -join ', ')]"

$lines = @(Get-Content -Path C:\psfaqs\one-line.txt)
"With @():    first = [$($lines[0])], rest = [$(($lines | Select-Object -Skip 1) -join ', ')]"

Output:

Without @(): first = [A], rest = [u, A]
With @():    first = [Austin], rest = []
PowerShell one-line file returns a string so [0] gives the first letter
A one-line file breaks array indexing until you add @() (Windows PowerShell 5.1)

$lines[0] returned the letter A, and the range 1..0 counted backwards through the letters. Wrapping Get-Content in @() keeps it an array, and Select-Object -Skip is safer than a range.

Read the first or last line

-TotalCount reads only the first lines and stops, and -Tail reads from the end of the file:

"First line: $(Get-Content -Path C:\psfaqs\servers.txt -TotalCount 1)"
"Last line:  $(Get-Content -Path C:\psfaqs\servers.txt -Tail 1)"
"Last two:   $((Get-Content -Path C:\psfaqs\servers.txt -Tail 2) -join ', ')"

Output:

First line: WEB01
Last line:  FILE01
Last two:   SQL01, FILE01

Both are faster than reading the whole file on big logs. The Get-Content documentation lists their aliases, -First and -Last.

Skip the first line

To skip a header row, pipe the lines to Select-Object -Skip 1:

Get-Content -Path C:\psfaqs\states.csv | Select-Object -Skip 1

Output:

California,39538223
Texas,29145505
Florida,21538187
Ohio,11799448

For CSV files, you usually don’t need to skip the header yourself. Import-Csv uses it to name the columns:

$rows = Import-Csv -Path C:\psfaqs\states.csv

"First row: $(($rows | Select-Object -First 1).State)"
"Last row:  $(($rows | Select-Object -Last 1).State)"

Output:

First row: California
Last row:  Ohio

Looping through CSV rows covers Import-Csv in more detail.

Why do special characters look wrong in Windows PowerShell 5.1?

cafe.txt is saved as UTF-8 without a byte order mark, which is how most editors and Linux tools save text today. Here’s how each version reads it:

"Default:        $(Get-Content -Path C:\psfaqs\cafe.txt)"
"-Encoding UTF8: $(Get-Content -Path C:\psfaqs\cafe.txt -Encoding UTF8)"

Output in PowerShell 7:

Default:        Café in San José
-Encoding UTF8: Café in San José

Output in Windows PowerShell 5.1:

Default:        Café in San José
-Encoding UTF8: Café in San José
PowerShell 5.1 Get-Content misreads UTF-8 without -Encoding UTF8
The accented letters break unless you add -Encoding UTF8 (Windows PowerShell 5.1)

Windows PowerShell 5.1 assumes the older Windows code page when there’s no byte order mark, so é turns into two wrong characters. Add -Encoding UTF8 in 5.1. PowerShell 7 reads UTF-8 by default.

Reading very large files

Get-Content is fine for most files, but it’s slow on files with hundreds of thousands of lines. [System.IO.File]::ReadLines() reads one line at a time and is much faster:

foreach ($line in [System.IO.File]::ReadLines('C:\Logs\big.log')) {
    if ($line -like '*ERROR*') { $line }
}

Give ReadLines a full path. Counting lines in a file has timing results for these methods on a 300,000-line log.

Frequently Asked Questions

How do I read a file line by line in PowerShell?

Use foreach ($line in Get-Content -Path file.txt) { ... }. Get-Content returns each line as a separate string.

How do I read only the first line of a file?

Use Get-Content -Path file.txt -TotalCount 1. It stops reading after the first line. Use -Tail 1 for the last line.

How do I skip the first line of a file in PowerShell?