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
PS> "Test" | Set-Content ttt.txt
PS> cat ttt.txt
Test
PS> "Insert" | Insert-Content ttt.txt
PS> cat ttt.txt
Insert
Test
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...
Just write your insert text to a file, then append your existing file
to that new file, finally rename and or delete old files.
# 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.
## 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
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
"Joel Bennett" <Jay...@HuddledMasses.org> wrote in message
news:eBhZN92k...@TK2MSFTNGP04.phx.gbl...
Nice! It's too bad that you can't use relative paths with it, though.
[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
Okay, as much as I think that's a nice addition, I have to wonder what
the hell they were thinking with that implementation.
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}
>> >> "@
...
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
Fair enough. Thanks for indulging me while it settles in.
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
Just how Provider agnostic is the underlying PowerShell notation?
- Larry
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
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.