159

I'd like to use PowerShell to store the entire contents of a text file (including the trailing blank line that may or may not exist) in a variable. I'd also like to know the total number of lines in the text file. What's the most efficient way to do this?

Greg Sansom
  • 20,442
  • 6
  • 58
  • 76
Nick
  • 8,049
  • 18
  • 63
  • 107

6 Answers6

254

On a side note, in PowerShell 3.0 you can use the Get-Content cmdlet with the new Raw switch:

$text = Get-Content .\file.txt -Raw 
Shay Levy
  • 121,444
  • 32
  • 184
  • 206
  • 5
    This is should be the accepted answer. By the way, I'm pretty sure Get-Content worked even in earlier versions. – MatteoSp May 08 '15 at 12:17
  • 10
    @MatteoSp `Get-Content` did, but it wasn't until 3.0 that it got `-Raw`. Without that, it gets stored as a array of lines. – jpmc26 Jan 30 '16 at 03:53
  • This should absolutely be the accepted answer. It doesn't help that the [documentation](https://technet.microsoft.com/en-us/library/hh849787.aspx) says that the `-Raw` parameter isn't implemented by anything native. – Richard Szalay Aug 03 '16 at 22:24
  • This does not fully answer the original question (needs to add how to calculate line numbers). It is a useful piece of information though. – Trisped Jun 02 '22 at 19:39
149

To get the entire contents of a file:

$content = [IO.File]::ReadAllText(".\test.txt")

Number of lines:

([IO.File]::ReadAllLines(".\test.txt")).length

or

(gc .\test.ps1).length

Sort of hackish to include trailing empty line:

[io.file]::ReadAllText(".\desktop\git-python\test.ps1").split("`n").count
manojlds
  • 290,304
  • 63
  • 469
  • 417
  • 1
    Thanks! `$content = [IO.File]::ReadAllText(".\test.txt")` appears to do the same thing as `$content = (gc ".\test.txt" | out-string)`. Since the second of the two is shorter, that's what I prefer. Unfortunately, neither of the methods you provided for calculating the total number of lines takes trailing blank lines into consideration. Any other ideas? – Nick Nov 02 '11 at 07:20
  • @Nick In .Net (and windows), any line with `\r\n` will be counted. – manojlds Nov 02 '11 at 07:35
  • I was doing some experimenting and came up with the same thing as your updated answer, but I wouldn't have gotten there without your help, so thank you so much! – Nick Nov 02 '11 at 07:53
  • Is there a way to transparently combine this with `Invoke-WebRequest`? – Kareem Mar 09 '17 at 09:00
31

Powershell 2.0:

(see detailed explanation here)

$text = Get-Content $filePath | Out-String

The IO.File.ReadAllText didn't work for me with a relative path, it looks for the file in %USERPROFILE%\$filePath instead of the current directory (when running from Powershell ISE at least):

$text = [IO.File]::ReadAllText($filePath)

Powershell 3+:

$text = Get-Content $filePath -Raw
Kapé
  • 4,411
  • 3
  • 37
  • 54
  • 1
    To use relatives paths, resolve it first eg: `[IO.File]::ReadAllText((Resolve-Path $filePath))` – mvanle Aug 22 '15 at 02:35
17

One more approach to reading a file that I happen to like is referred to variously as variable notation or variable syntax and involves simply enclosing a filespec within curly braces preceded by a dollar sign, to wit:

$content = ${C:file.txt}

This notation may be used as either an L-value or an R-value; thus, you could just as easily write to a file with something like this:

 ${D:\path\to\file.txt} = $content

Another handy use is that you can modify a file in place without a temporary file and without sub-expressions, for example:

${C:file.txt} = ${C:file.txt} | select -skip 1

I became fascinated by this notation initially because it was very difficult to find out anything about it! Even the PowerShell 2.0 specification mentions it only once showing just one line using it--but with no explanation or details of use at all. I have subsequently found this blog entry on PowerShell variables that gives some good insights.

One final note on using this: you must use a drive designation, i.e. ${drive:filespec} as I have done in all the examples above. Without the drive (e.g. ${file.txt}) it does not work. No restrictions on the filespec on that drive: it may be absolute or relative.

Michael Sorens
  • 35,361
  • 26
  • 116
  • 172
  • I have never got this to work unless I put a backslash after the drive name. – Charles Anderson May 09 '13 at 09:42
  • @CharlesAnderson: It is not clear which of the three examples you are referring to, or perhaps all of them... nonetheless, I just confirmed that all 3 work with a relative path (i.e. no backslash) in PowerShell V3. Further, at the time of my answer I was using V2, so perhaps there is something else causing an issue in your environment. – Michael Sorens May 09 '13 at 14:35
  • I meant examples like ${C:file.txt}, which I have to write as ${C:\file.txt}. Yes, I presume it is something about my environment, but I have no idea what. – Charles Anderson May 10 '13 at 17:25
  • When using as L-value, it uses the system's default encoding. I tried to set $OutputEncoding with no effect. When using as R-value, it produces a string[] array. – robert4 Jul 19 '13 at 16:54
  • It seems you can only use a literal pathname; you can't use a variable or something like a Join-Path expression inside this. Which is annoying, because when piped through ConvertTo-Json, there is a world of difference compared with Get-Content (and the ${...} result is what I was hoping for. I'm not sure if this is the same as Get-Content | Out-String though – Cameron Kerr Nov 13 '16 at 09:57
  • @CameronKerr Yes that seems to be the case. I might just edit this answer to note that. – Justin Dearing Jun 02 '17 at 17:43
  • How do I get this to work on a filesystem that doesn't have drives, like on UNIX systems? I'm using Powershell 7.2.5 on Linux. Thank you. – Teddy C Jul 24 '22 at 14:21
3

Get-Content grabs data and dumps it into an array, line by line. Assuming there aren't other special requirements than you listed, you could just save your content into a variable?

$file = Get-Content c:\file\whatever.txt

Running just $file will return the full contents. Then you can just do $file.Count (because arrays already have a count method built in) to get the total # of lines.

Hope this helps! I'm not a scripting wiz, but this seemed easier to me than a lot of the stuff above.

Jerry T.
  • 31
  • 1
0

Read binary file:

This is not exactly what was asked, but some might find this useful for their use case anyway. Get-Content -Raw yields a string, so if you want byte[]:

Get-Content c:\file.bin -Encoding Byte -ReadCount 0

-Read-Count tells how many lines go through the pipeline at a time (default is 1), and 0 does everything in one operation which boosts performance.

The credits shall go to Shay Levy who has published this solution: (see Shay's post here)

Ingmar
  • 2,361
  • 3
  • 19
  • 33