Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Append text to top of text file?

6,324 views
Skip to first unread message

Get-James

unread,
Feb 19, 2009, 5:46:55 PM2/19/09
to
Hi,

Anyone know how to append some text, to the top of a text file?

I already know how to put it to the bottom using 'add-conent'

add-content 'C:\test.txt' "`nHello"

Is there away using .net, I have tried the following but it overwrites the
first line:

$TextFilePath = "C:\text.txt"
$logstream =
[system.io.file]::open($TextFilePath,"open","write","ReadWrite")
$logWriter = New-Object system.io.streamwriter $Logstream
$logWriter.WriteLine("Hello New Line")
$logWriter.close()
$logstream.close()


Any help would be great.
Cheers
James

PaulChavez

unread,
Feb 19, 2009, 6:32:09 PM2/19/09
to
function Insert-Content ($file) {
BEGIN {
$content = Get-Content $file
}
PROCESS {
$_ | Set-Content $file
}
END {
$content | Add-Content $file

PaulChavez

unread,
Feb 19, 2009, 6:38:04 PM2/19/09
to
Forgot to include a usage example:

PS> "Test" | Set-Content ttt.txt
PS> cat ttt.txt
Test
PS> "Insert" | Insert-Content ttt.txt
PS> cat ttt.txt
Insert
Test

Josh Einstein

unread,
Feb 19, 2009, 6:39:29 PM2/19/09
to
What you want to do isn't possible without re-writing the entire file. It's
not a limitation of PowerShell, but just filesystems in general.

If the file isn't too large, you can reasonably do this:

function Insert-Content {
param ( [String]$Path )
process {
$( ,$_; Get-Content $Path -ea SilentlyContinue) | Out-File $Path
}
}

'hello newman' | Insert-Content seinfeld.txt
'hello jerry' | Insert-Content seinfeld.txt

Hope this helps.

Josh

"Get-James" <1...@1.com> wrote in message
news:yjlnl.7668$ot7....@newsfe15.ams2...

Null_Hypothesis

unread,
Feb 19, 2009, 8:15:12 PM2/19/09
to
> > James- Hide quoted text -
>
> - Show quoted text -

Just write your insert text to a file, then append your existing file
to that new file, finally rename and or delete old files.

Kiron

unread,
Feb 20, 2009, 1:39:59 AM2/20/09
to
# interactively
# write test file
sc file.txt 4,5,6
# new content
[array]$nc = 1,2,3
# original content
$oc = gc file.txt
# prepend
$nc, $oc | sc file.txt
# verify
gc file.txt
# get rid of test file
ri file.txt

# for big flies
function Prepend-Content (
[String]$Path,
[Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding]
$Encoding = 'UTF8'
) {
$Path = $(if (Test-Path $Path -PathType Leaf) {
(rvpa $Path).path
} else {
throw "`"$Path`" does not exist"
})
sc $Path ($input + [IO.File]::ReadAllLines($Path)) -en $Encoding
[GC]::Collect()
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# setup large content
$oc = New-Object String[] 1mb
for ($i = 0; $i -lt 1mb; $i++) {
$oc[$i] = "line $i"
}
cls
# write large content to file
sc big.txt $oc -en 5
'-< before >-'
# get first 11 lines
gc big.txt -t 11
# prepend 3 new lines
1,2,3 | Prepend-Content big.txt
'-< after >-'
gc big.txt -t 11
# delete big.txt
ri big.txt

--
Kiron

tojo2000

unread,
Feb 20, 2009, 3:02:51 AM2/20/09
to
(gc file.txt) | %{do something} > file.txt

# sort file
(gc file.txt) | sort > file.txt

# prepend data
$data + (gc file.txt) > file.txt

# set to all uppercase
(gc file.txt) | %{$_.ToUpper()} > file.txt

# convert to UTF-8
(gc file.txt) | Out-File -Encoding utf8 file.txt

The key is putting the parentheses around 'gc file.txt'. That makes
PowerShell read in the entire file to evaluate the parentheses before
passing anything down the pipeline, so you don't ever end up throwing
exceptions for writing to a file you're reading from.

Joel Bennett

unread,
Feb 20, 2009, 10:24:02 AM2/20/09
to

You know, this brings up the fact that you can use ${} notation to work
with file contents ...

## Append
${C:\YourFile.txt} += "`nA Line at the bottom"

## Prepend
${C:\YourFile.txt} = "A Line at the top`n" + ${C:\YourFile.txt}


You can even put the ${} inside the string:

${C:\YourFile.txt} = @"
A line at the top
Another line at the top
${C:\YourFile.txt}
A line at the bottom
"@

--
Joel

Flowering Weeds

unread,
Feb 20, 2009, 10:22:00 AM2/20/09
to

>
> Anyone know how to append some text, to the top of a text file?
>

FYI

Mmm since powershell.exe is the Windows admin's automation tool
and the year 2009 is the data parsing and charting automation year,
then perhaps for any file (large or small, local or remote):

function Add-TopLine
{
param ($theInFile,$line,$theOutFile)

$theOldFile = $theInFile
$theNewFile = $theOutFile
$thetempFile = "$pwd\theTempFile.txt"

$lp = (Get-Command LogParser.exe).FileVersionInfo.FileName

$line | & $lp "SELECT text
INTO $theTempFile
FROM STDIN " -i textline -stats off `
-o nat -headers off

& $lp "SELECT text
INTO $theTempFile
FROM $theOldFile " -i textline -stats off `
-o nat -headers off -filemode 0

& $lp "SELECT text
INTO $theNewFile
FROM $theTempFile " -i textline -stats off `
-o nat -headers off

remove-item $theTempFile

}

$myFile = "$pwd\theFile.txt"
$myNewFile = "$pwd\myNewFile.txt"

Add-TopLine $myFile "L line of text" $myNewFile

$lp = (Get-Command LogParser.exe).FileVersionInfo.FileName

" "
& $lp "SELECT EXTRACT_FILENAME(LogFileName) As FileName,
index, text FROM $myFile " -i textline -stats off

" "
& $lp "SELECT EXTRACT_FILENAME(LogFileName) As FileName,
index, text FROM $myNewFile " -i textline -stats off

Add-TopLine $myNewFile "K line of text" $myNewFile
Add-TopLine $myNewFile "J line of text" $myNewFile

" "
& $lp "SELECT EXTRACT_FILENAME(LogFileName) As FileName,
index, text FROM $myNewFile " -i textline -stats off

" "
"Mmm now chart the difference."

$title = "File Line Counts"

& $lp "SELECT EXTRACT_FILENAME(LogFileName) As FileName,
COUNT(index) As Totals
INTO testChart.png
FROM $myFile,$myNewFile
GROUP BY FileName " -i textline -stats off -o chart `
-charttype "ColumnClustered" -values on `
-chartTitle "$title"

invoke-item testChart.png

" "
"Done!"
" "
Exit

The above automation of Log Parser returns:

FileName Index Text
----------- ----- ---------------
theFile.txt 1 A line of text.
theFile.txt 2 B line of text.
theFile.txt 3 C line of text.

FileName Index Text
------------- ----- ---------------
myNewFile.txt 1 L line of text
myNewFile.txt 2 A line of text.
myNewFile.txt 3 B line of text.
myNewFile.txt 4 C line of text.

FileName Index Text
------------- ----- ---------------
myNewFile.txt 1 J line of text
myNewFile.txt 2 K line of text
myNewFile.txt 3 L line of text
myNewFile.txt 4 A line of text.
myNewFile.txt 5 B line of text.
myNewFile.txt 6 C line of text.

Mmm now chart the difference.

Done!

Have fun automating Log Parser within powershell.exe!


Josh Einstein

unread,
Feb 20, 2009, 11:40:08 AM2/20/09
to
Ahh that's the syntax I was thinking of. I read it in PowerShell in Action
but I loaned my book to a coworker and couldn't remember it. Thanks!

Josh

"Joel Bennett" <Jay...@HuddledMasses.org> wrote in message
news:eBhZN92k...@TK2MSFTNGP04.phx.gbl...

tojo2000

unread,
Feb 20, 2009, 12:50:42 PM2/20/09
to

Nice! It's too bad that you can't use relative paths with it, though.

Joel Bennett

unread,
Feb 20, 2009, 1:11:03 PM2/20/09
to
Sure you can! Just leave the \ off the front of the path ...


[113]: ls .\output.txt

Directory: C:\Users\Joel\Documents\WindowsPowershell\temp

Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2/20/2009 1:06 PM 16 output.txt


[114]: cat .\output.txt
some test text
[115]: ${C:output.txt} = @"
>> text at the top
>> ${C:output.txt}
>> text at the bottom
>> "@
>>
[116]: cat .\output.txt
text at the top
some test text
text at the bottom
[117]: ls .\output.txt

Directory: C:\Users\Joel\Documents\WindowsPowershell\temp

Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2/20/2009 1:06 PM 51 output.txt

[118]: cd ..
[119]: pwd

Path
----
C:\Users\Joel\Documents\WindowsPowershell

[120]: ${C:temp\output.txt} = @"
>> more text at the top
>> ${C:temp\output.txt}
>> "@
>>
[121]: cat .\temp\output.txt
more text at the top
text at the top
some test text
text at the bottom

tojo2000

unread,
Feb 20, 2009, 2:19:08 PM2/20/09
to

Okay, as much as I think that's a nice addition, I have to wonder what
the hell they were thinking with that implementation.

Joel Bennett

unread,
Feb 20, 2009, 3:39:23 PM2/20/09
to
Well, the key thing about the ${} notation is that it's not a
file-system trick. It works with any PS Provider that supports has
CONTENT (ie: that supports IContentCmdletProvider), and it works without
$(wrapping) inside strings, so you can do:

Write-Host "You are ${env:USERNAME}"

or even:

${function:prompt} = iex "{
write-host `${env:USERNAME} -Fore Cyan -NoNewLine
write-host '@' -NoNewLine
write-host `${env:COMPUTERNAME} -Fore Green -NoNewLine
${function:prompt}
}"

It takes some getting used to, but it saves a lot of typing, and you can
even use operators like ++ and += ...

--
Joel

tojo2000 wrote:
> On Feb 20, 10:11 am, Joel Bennett<Jay...@HuddledMasses.org> wrote:
>> Sure you can! Just leave the \ off the front of the path ...
>>

...


>>
>> [120]: ${C:temp\output.txt} = @"
>> >> more text at the top
>> >> ${C:temp\output.txt}
>> >> "@

...

tojo2000

unread,
Feb 20, 2009, 5:02:16 PM2/20/09
to

It just seems weird that c:temp is treated as "the item named temp
under CurrentLocation in the PSDrive C:", but c:\temp is treated as
"the item named temp at the root of PSDrive C:", while c:.\temp is
also treated as "the item named temp under CurrentLocation in the
PSDrive C:".

Joel Bennett

unread,
Feb 20, 2009, 8:09:03 PM2/20/09
to
tojo2000 wrote:
> It just seems weird that c:temp is treated as "the item named temp
> under CurrentLocation in the PSDrive C:", but c:\temp is treated as
> "the item named temp at the root of PSDrive C:", while c:.\temp is
> also treated as "the item named temp under CurrentLocation in the
> PSDrive C:".

Well, this is the exact same syntax we've been using in DOS since the
dark ages ... ie: in DOS:

C:\Users\Joel\Documents\WindowsPowershell\temp>type output.txt


more text at the top

some test text

C:\Users\Joel\Documents\WindowsPowershell\temp>A:

A:\>type C:output.txt


more text at the top

some test text

A:\>C:

C:\Users\Joel\Documents\WindowsPowershell\temp>cd ..

C:\Users\Joel\Documents\WindowsPowershell>A:

A:\>type C:.\temp\output.txt


more text at the top

some test text

The thing that bothers me about it is when you just leave off the drive
it doesn't use the "current psdrive" --it defaults to the variable:
drive-- so unless you just want a variable, you have to put the drive
name on, even for purely relative paths.

--
Joel

tojo2000

unread,
Feb 20, 2009, 10:33:34 PM2/20/09
to

Fair enough. Thanks for indulging me while it settles in.

Al Dunbar

unread,
Feb 22, 2009, 10:04:31 AM2/22/09
to

"Joel Bennett" <Jay...@HuddledMasses.org> wrote in message
news:%23TVpOE8...@TK2MSFTNGP03.phx.gbl...

But, as you said earlier about ${}" it's not a file-system trick". It might
seem intuitive for a purely relative reference to a file to be resolved that
way - if it exists. But what if it does not exist? or if the indicated
folder does not exist?

Conversely, if you want it to refer to a variable, how annoying would it be
to find that it referred to a file when such a file happened to exist? And
if a relative file path were the default, how annoying would it be to have
to type "variable:" all the time...

imho, it is the drive-letter prefix that flags the rest of it as a reference
to a file. In the ambiguous case, I would think that assuming a variable
would be more intuitively logical than looking on the current drive to see
if such a file exists - or in the registry to see if such a registry entry
exist - and etc.

Perhaps it would have been nice to allow a truly relative file reference
with a file system specific prefix such as ${FILE:test.txt}, or even
${::test.txt}or ${:test.txt}. ".\" is not available, as it appears that
${.\file.txt} refers to a variable named ".\file.txt".


/Al


Larry__Weiss

unread,
Feb 22, 2009, 2:44:06 PM2/22/09
to
Al Dunbar wrote:
> But, as you said earlier about ${}" it's not a file-system trick". It might
> seem intuitive for a purely relative reference to a file to be resolved that
> way - if it exists. But what if it does not exist? or if the indicated
> folder does not exist?
>
> Conversely, if you want it to refer to a variable, how annoying would it be
> to find that it referred to a file when such a file happened to exist? And
> if a relative file path were the default, how annoying would it be to have
> to type "variable:" all the time...
>
> imho, it is the drive-letter prefix that flags the rest of it as a reference
> to a file. In the ambiguous case, I would think that assuming a variable
> would be more intuitively logical than looking on the current drive to see
> if such a file exists - or in the registry to see if such a registry entry
> exist - and etc.
>
> Perhaps it would have been nice to allow a truly relative file reference
> with a file system specific prefix such as ${FILE:test.txt}, or even
> ${::test.txt}or ${:test.txt}. ".\" is not available, as it appears that
> ${.\file.txt} refers to a variable named ".\file.txt".
>


Just how Provider agnostic is the underlying PowerShell notation?


- Larry

Joel Bennett

unread,
Feb 23, 2009, 1:03:19 AM2/23/09
to
Larry__Weiss wrote:
> Just how Provider agnostic is the underlying PowerShell notation?

Totally. As far as I can tell, it just lets you use variable notation to
wrap a call to get-content/set-content (which are obviously provider
agnostic), assuming of course that the PSProvider in question implements
the interface:

PS> ${hklm:}
The provider 'Registry' cannot be used to get or set data using the
variable syntax. Cannot use interface. The IContentCmdletProvider
interface is not implemented by this provider.

PS> Get-Content hklm:
Get-Content : Cannot use interface. The IContentCmdletProvider interface
is not implemented by this provider.


--
Joel

tojo2000

unread,
Feb 23, 2009, 3:20:44 AM2/23/09
to

One last point about the ${drive:path} notation: In case anyone was
wondering, it does read the entire file before it starts to pass the
results down the pipeline, so it is the equivalent of

(gc file.txt)

and not

gc file.txt

which makes a huge difference if you try to redirect to the same file,
because if you do this:

gc file.txt | %{$_.replace('one', 'two')} > file.txt

You will clobber file.txt and end up with an empty file.

0 new messages