Recently this question was posted on stackoverflow, I have a similar problem as J. Williams except I only need to remove empty lines (removing spaces would not hurt the program though, it just isn't necessary). When I tried his original as well as the solution compo gave it only cleared the file instead of removing extra lines. I'm using it by itself in a batch file.
Example:
I need this:
Joe
Bob
Mark
Frank
Dutch
(blank line here too)
to become this:
Joe
Bob
Mark
Frank
Dutch
I'm open to attaching such a solution to this powershell script too, as it is what is giving me the blank lines: (Get-Content friends.txt) | Where-Object {$_ -notmatch "\bJoe\b"} | Set-Content friends.txt Thank's for your help.
This should work for you - in short, it reads all the lines of the file, then writes back only the lines with something in it to the file.
$friends = Get-Content friends.txt
$friends | Where-Object { $_ } | Set-Content friends.txt
If it's a relatively small file:
(Get-Content $infile) -match '\S' | Set-Content $infile
If it's too large to read into memory all at once:
Get-Content $infile -ReadCount 1000 |
ForeachObject {
$_ -match '\S' |
Add-Content $outfile
}
Another PowerShell method would be to use the Select-String cmdlet using the regex pattern .+ which means one or more of any character. Also if using Set-Content be sure to use the -NoNewLine parameter to prevent the unwanted blank line at the end. (Requires PS5+)
Select-String -Path C:\example.txt -Pattern '.+' |
Select-Object -ExpandProperty line |
Set-Content C:\exampleoutput.txt -NoNewline
Related
Go easy on me, first time posting.
I'm trying to use Powershell to Get-Content from an INI file. Particularly, I need to change two separate lines in the file. It runs, but instead of just replacing those 2 lines, it duplicates everything. It also doesn't replace the line I'm trying to tell it to replace, but instead it just adds my new line leaving the original in as well.
$FilePath = "C:\Users\folder\*.ini"
(Get-Content $FilePath) |
ForEach-Object {
$_ -replace "MailBell=0","MailBell=1"
$_ -replace "MailWindow=0","MailWindow=1"
} |
Set-Content $FilePath
There is a look at the code. Any help is greatly appreciated.
I have a script that searches for the lastest modified log file. It then is suppose to read that text file and pick up a key phrase then display the line after it.
So far i have this
$logfile = get-childitem 'C:\logs' | sort {$_.lastwritetime} | where {$_ -notmatch "X|Zr" }| select -last 1
$error = get-content $logfile | select-string -pattern "Failed to Modify"
an example line it reads is this
20150721 12:46:26 398fbb92 To CV Failed to Modify
CN=ROLE-x-USERS,OU=Role Groups,OU=Groups,DC=gyp,DC=gypuy,DC=net
MDS_E_BAD_MEMBERSHIP One or more members do not exist in the directory
They key bit of information im trying to get here is
Can anyone help?
Thanks
Try this:
$error = get-content $logfile |
Where-Object { $_ -like "*Failed to Modify*" } |
Select-Object -First 1
This is provided you are looking for the first match in the file. The Select-String cmdlet returns a MatchInfo object. Depending on your requirements there might be no reason to add that level of complexity if you're just looking to pull the first occurrence of this error in the file.
Failing this, my recommendation would be to debug this and step through it. Break on the Get-Content call and see what $logfile is. Run Get-Content $logfile and see what that content looks like. Then do your Select-String on that output. See what MatchInfo.ToString() looks like. Maybe you'll see some disconnect.
Again, my recommendation would be to just parse manually through the file and work with the Where-Object cmdlet at this point.
This shoul work:
get-childitem 'c:\logs' | where {$_.Name -notmatch "X|Zr" } | sort {$_.lastwritetime} | select -last 1 | select-string "Failed to Modify"
But I don't like "X|Zr" part. If your log files have .txt extension, it'll not list them because you're saying you don't want any file containing "x" or "zr" in entire name. Use $_.BaseName (name without extension), or modify regular expression.
I'm trying to write a simple script that reads a file, locates a string, replaces the string with another string, and stores all new file contents (with replaced string), in a new file. Here is what I'm using:
(Get-Content C:\file1.txt) | {$_ -replace "this:text", "withthis:text"} | Set-Content C:\file2.txt
The error I'm receiving is: "Expressions are only allowed as the first element of a pipeline"
I'm pretty sure this is because of the colon ":" character being in both the string I'm locating and replacing it with. I've tried escaping the colon character with "\" and "`" characters, but I'm receiving the same errors. Does anyone know what's wrong with this?
Thanks for the help.
The problem is the second element in your pipeline.
{$_ -replace "this:text", "withthis:text"}
This is a scriptblock (i.e. a piece of code). If you want to apply a scriptblock to all of the incoming items on a pipeline you can use the foreach-object cmdlet like this:
(Get-Content C:\file1.txt) | foreach-object {$_ -replace "this:text", "withthis:text"} | Set-Content C:\file2.txt
#shagun is using the % alias for the foreach-object cmdlet, so that code looks correct as well.
I guess it is because after first pipe you are not processing each result. so the right one will be according to me :
(Get-Content C:\file1.txt) | %{$_ -replace "this:text", "withthis:text"} | Set-Content C:\file2.txt
I have 3 .csv files that I am combining into one. This bit of code works:
Get-ChildItem 'C:\Scripts\testing\csvStuffer\temp\Individual.*.csv' |
ForEach-Object {Import-Csv $_} |
Export-Csv -NoTypeInformation 'C:\Scripts\testing\csvStuffer\temp\MergedCsvFiles.csv'
The problem is that each .csv file has a header and a footer.
I do not want to keep the header or footer from any of the files.
Any suggestions of what I need to add to the above code to remove the headers and footers???
Thanks!
This is not the most elegant solution but it worked for my test files.
Get-ChildItem 'C:\Scripts\testing\csvStuffer\temp\Individual.*.csv' |
ForEach-Object {
$filecontent = get-content $_ | select-object -skip 1;
$filecontent | select -First $($filecontent.length -1) | Set-Content -Path $_;
};
Skipping the first line is easy with select-object. Dropping the last line requires a bit more work, but since get-content returns an array of lines, you can just grab all but the last element in that array.
Looks like alroc already gave an answer, but since I already had it written up I figured I'd post this too. It doesn't load it all into a variable, it just reads each file, strips the first and last line of the current file, and then pipes to out-file with -append on it.
gci 'C:\Scripts\testing\csvStuffer\temp\Individual.*.csv' | %{
$(gc $_.fullname|skip 1)|select -First ($(gc $_.fullname|skip 1).count-1)
}|Out-File -Append 'C:\Scripts\testing\csvStuffer\temp\MergedCsvFiles.csv'
i hope someone can help.
I am trying to manipulate a file created by powershell.
I managed to get to the end result that i want, but i am sure it would be easier if it was only one command.
# Invoke the Exchange Snapping ( make sure you are Exchange Admin to do it SO)
add-pssnapin Microsoft.Exchange.Management.PowerShell.E2010
#Create a file with list of DL in the organization
Get-DistributionGroup | Select-Object Name | Out-File C:\Pre_DLGroups.txt
$content = Get-Content C:\Pre_DLGroups.txt
#Remove the 3 first lines of the file that you dont need it
$content | Select-Object -Skip 3 | Out-file C:\DLGroups.txt
#Trim the space in the end and crate the Final file
Get-Content C:\DLGroups.txt | Foreach {$_.TrimEnd()} | Set-Content c:\FinalDLGroup.txt
is that way to make the end result in a single file rather than creating 3?
cheers
Elton
You can send your content across the pipeline without writing it out to files. You can use parenthesis to group the output of certain sets of cmdlets and/or functions, and then pipe that output through to the intended cmdlets.
This can all be applied on a single line, but I've written it here on multiple lines for formatting reasons. The addition of Out-String is something of a safety measure to ensure that whatever output you're intending to trim can actually be trimmed.
Since we're not getting this content from a text file anymore, powershell could possibly return an object that doesn't understand TrimEnd(), so we need to be ready for that.
(Get-DistributionGroup | Select-Object Name) |
Out-String |
Select-Object -Skip 3 |
Foreach {$_.TrimEnd()} |
Set-Content c:\FinalDLGroup.txt
However, an even smaller solution would involve just pulling each name and manipulating it directly. I'm using % here as an alias for Foreach-Object. This example uses Get-ChildItem, where I have some files named test in my current directory:
(Get-ChildItem test*) |
% { $_.Name.TrimEnd() } |
Set-Content c:\output.txt
Get-DistributionGroup |
Select-Object -ExpandProperty Name -Skip 3 |
Set-Content c:\FinalDLGroup.txt