Get-Content & Sub string combined - powershell

I'm trying to figure out if there is syntax I can use to get content out of a file and only pull back a sub string of it all in one line? Something like the following, except it doesn't work, so I'm looking for the missing piece.
$ConfigureEmail = Get-Content -Path "\\myFilePath\Location\MyFile.sql" -Raw | $_.SubString($_.IndexOf("*/"))
I'm trying to pull the main script out of the file, starting after the comment block.
Edit: I realized I could add Foreach-Object after the pipe but since I will only ever have one item is there something better to use?

$Content = Get-Content -Path "\\myFilePath\Location\MyFile.sql" -Raw
$ConfigureEmail = $Content.SubString($Content.IndexOf("*/"))
->
$ConfigureEmail = ($Content = Get-Content -Path "\\myFilePath\Location\MyFile.sql" -Raw).SubString($Content.IndexOf("*/"))
or
[regex]::Match((Get-Content .\test.txt -Raw), '\*/.*', 'singleline').Value

Related

How to prepend to a file in PowerShell?

I'm generating two files, userscript.meta.js and userscript.user.js. I need the output of userscript.meta.js to be placed at the very beginning of userscript.user.js.
Add-Content doesn't seem to accept a parameter to prepend and Get-Content | Set-Content will fail because userscript.user.js is being used by Get-Content.
I'd rather not create an intermediate file if it's physically possible to have a clean solution.
How to achieve this?
The Subexpression operator $( ) can evaluate both Get-Content statements which are then enumerated and passed through the pipeline to Set-Content:
$(
Get-Content userscript.meta.js -Raw
Get-Content userscript.user.js -Raw
) | Set-Content userscript.user.js
Consider using the Absolute Path of the files if your current directory is not where those files are.
An even more simplified approach than the above would be to put the paths in the desired order since both, the -Path and -LiteralPath parameters can take multiple values:
(Get-Content userscript.meta.js, userscript.user.js -Raw) |
Set-Content userscript.user.js
And in case you want to get rid of excess leading or trailing white-space, you can include the String.Trim Method:
(Get-Content userscript.meta.js, userscript.user.js -Raw).Trim() |
Set-Content userscript.user.js
Note that in above examples the grouping operator ( ) is mandatory as we need to consume all output from Get-Content before being passed through the pipeline to Set-Content. See Piping grouped expressions for more details.
For future folks, here's a snippet if you need to prepend the same thing to multiple files:
example: prepending an #include directive to a bunch of auto-generated C++ files so it works with my Windows environment.
Get-ChildItem -Path . -Filter *.cpp | ForEach-Object {
$file = $_.FullName
# the -Raw param was important for me as it didn't read the entire
# file properly without it. I even tried [System.IO.File]::ReadAllText
# and got the same thing, so there must have been some characater that
# caused the file read to return prematurely
$content = Get-Content $file -Raw
$prepend = '#include "stdafx.h"' + "`r`n"
#this could also be from a file: aka
# $prepend = Get-Content 'path_to_my_file_used_for_prepending'
$content = $prepend + $content
Set-Content $file $content
}

Trouble reading last line of CSV

I am getting CSV files (with no header) from another system. The last line ends the file, (there is not a newline after the last line of data). When I try Import-CSV, it will not read the last line of the file.
I do not have the ability to have the input file changed to include the newline.
I have noticed that the Get-Content doesn't have a problem reading the entire file, but then it isn't a CSV and I'm unable to reference the fields in the file.
Currently I'm doing:
$w = Import-CSV -path c:\temp\input.txt -header 'head1', 'head2', 'head3'
This will not read the last line of the file
This reads the entire file:
$w = Get-Content -path c:\temp\input.txt
But the data doesn't have the ability to reference the fields like: $w.head1
Is there a way to get Import-CSV to read the file including the last line?
OR Is there a way to read in the data using Get-Content, adding a header to it and then converting it back to a CSV?
I've tried use ConvertTo-CSV but have not had success:
$w = Get-Content -path c:\temp\input.txt
$csvdata = $w | ConvertTo-CSV # No header option for this function
I'd rather not create an intermediate file unless absolutely necessary.
You're very close! What you're after is not ConvertTo-Csv, you already have the file contents in CSV-format after all. So change that to ConvertFrom-Csv instead, which incidentally does support the -Headers parameter. So something like this:
$w = Get-Content -path c:\temp\input.txt
$csvdata = $w | ConvertFrom-Csv -Header 'head1', 'head2', 'head3'
If I understand correctly, you know the number of columns in the file and all it is missing is a header line. Since in your code you do not specify a -Delimiter parameter I'm assuming the delimiter character used in the file is a comma.
Best thing to do IMHO is to create a new output file and always keep the original.
$fileIn = 'c:\temp\input.txt'
$fileOut = 'c:\temp\input.csv'
# write the header line to a new file
Set-Content -Path $fileOut -Value 'head1,head2,head3'
# read the original file and append it to the one you have just created
Get-Content -Path $fileIn -Raw | Add-Content -Path $fileOut
If your file is really large, below a faster alternative:
$fileIn = 'c:\temp\input.txt'
$fileOut = 'c:\temp\input.csv'
# write the header line to a new file
Set-Content -Path $fileOut -Value 'head1,head2,head3'
# read the original file and append it to the one you have just created
[System.IO.File]::AppendAllText($fileOut, ([System.IO.File]::ReadAllText($fileIn)))
If you really do want to take the risk and overwrite the original file, you can do this:
$file = 'c:\temp\input.txt'
$content = Get-Content -Path $fileIn -Raw
# write the header line to a the file destroying what was in there
Set-Content -Path $file -Value 'head1,head2,head3'
# append the original content to it
$content | Add-Content -Path $file

Preserve Emojis with Get-Content Powershell

I want to preserve Emojis with Get-Content.
When I pull the string from the feed I get the following result:
$WebResponse = Invoke-RestMethod $website
$str_outputNAME = $feed.title
Wanna try😉?
But when I save the content of the file and append it after I have the following result:
$content = (Get-Content -Path $file) -join "`n"
$toWrite = $top_line+$toWrite+$content
$toWrite | Out-File -FilePath $file;
Wanna try???
Background-Info
I want to use Powershell to read a rss-feed.
Therefor I need to append a string at the start of my CSV-File on update.
Because my question was regarding *.csv files I found that a better way is too use
$content = Import-Csv -Path $file
instead of
$content = Get-Content -Path $file
Now all my Emojis are preserved within the file but the processing of the script takes twice the time now.
I tried all different possible Get-Content -Encoding arguments but without luck.
Always resulted in loss towards the formatting of emojis.

Saving Find and Replace text function for .dat files in Powershell

I'm making a script that will find and replace all the instances of a word with another. However I'm unsure how to save the changes.
$file = Get-Content "C:\Script.dat" -Raw
$old = 'oldword'
$new = 'newword'
$file.Replace($old,$new)
Initially I had used the following but this caused issues.
$file.Replace($old,$new) | Set-Content $file
This caused the issue the error of
Set-Content : Cannot find drive. A drive with the same *some random stuff*...
How would I be able to save the changes and/or fix the above issue?
$file = Get-Content "C:\Script.dat" -Raw
$old = 'oldword'
$new = 'newword'
$file.Replace($old,$new) | Out-File -FilePath C:\Script.dat
You were very close, but Set-Content needs two things: a path to the file location and the value to store. Personally, I prefer to overwrite variables when using the .Replace() method instead of piping it into other cmdlets.
This will do it:
$file = Get-Content "C:\Script.dat" -Raw
$old = 'oldword'
$new = 'newword'
$file = $file.Replace($old,$new)
Set-Content -Path "C:\Script.dat" -Value $file
If possible, try to avoid storing files directly at C:\ since that often needs admin rights to write to.
Additionally, you could pipe to Set-Content in a similar way originally listed but you still need to give it the path to the file:
$file.Replace($old,$new) | Set-Content "C:\Script.dat"

Powershell. Writing out lines based on string within the file

I'm looking for a way to export all lines from within a text file where part of the line matches a certain string. The string is actually the first 4 bytes of the file and I'd like to keep the command to only checking those bytes; not the entire row. I want to write the entire row. How would I go about this?
I am using Windows only and don't have the option to use many other tools that might do this.
Thanks in advance for any help.
Do you want to perform a simple "grep"? Then try this
select-string .\test.txt -pattern "\Athat" | foreach {$_.Line}
or this (very similar regex), also writes to an outfile
select-string .\test.txt -pattern "^that" | foreach {$_.Line} | out-file -filepath out.txt
This assumes that you want to search for a 4-byte string "that" at the beginning of the string , or beginning of the line, respectively.
Something like the following Powershell function should work for you:
function Get-Lines {
[cmdletbinding()]
param(
[string]$filename,
[string]$prefix
)
if( Test-Path -Path $filename -PathType Leaf -ErrorAction SilentlyContinue ) {
# filename exists, and is a file
$lines = Get-Content $filename
foreach ( $line in $lines ) {
if ( $line -like "$prefix*" ) {
$line
}
}
}
}
To use it, assuming you save it as get-lines.ps1, you would load the function into memory with:
. .\get-lines.ps1
and then to use it, you could search for all lines starting with "DATA" with something like:
get-lines -filename C:\Files\Datafile\testfile.dat -prefix "DATA"
If you need to save it to another file for viewing later, you could do something like:
get-lines -filename C:\Files\Datafile\testfile.dat -prefix "DATA" | out-file -FilePath results.txt
Or, if I were more awake, you could ignore the script above, use a simpler solution such as the following one-liner:
get-content -path C:\Files\Datafile\testfile.dat | select-string -Pattern "^DATA"
Which just uses the ^ regex character to make sure it's only looking for "DATA" at the beginning of each line.
To get all the lines from c:\somedir\somefile.txt that begin with 'abcd' :
(get-content c:\somedir\somefile.txt) -like 'abcd*'
provided c:\somedir\somefile.txt is not an unusually large (hundreds of MB) file. For that situation:
get-content c:\somedir\somefile.txt -readcount 1000 |
foreach {$_ -like 'abcd*'}