Home > Blockchain >  Creating new files from multiple files that have been scanned and manipulated in powershell
Creating new files from multiple files that have been scanned and manipulated in powershell

Time:11-18

First of all, I'm a complete newbie at Powershell. I've basically compiled a script from a number google search results and it works to a certain degree, so be gentle :)

I have a number of large plain text files that need scanning, junk data needs removing, and characters need renaming. Then create a new file in the same directory

Here is the script I have for individual files, I have replaced actual keywords for something unrelated, but for testing purposes you should see what I am trying to achieve:

Get-Content C:\Temp\Tomatoes-2022-09-27.txt |
    Where-Object { - $_.Contains('red') } |            # Keeping only lines containing "red"
    Foreach {$_ -replace "[/()]",":"}|                 # replacing specific characters to a colon
    Where-Object { -not $_.Contains('too red') } |     # removing lines containing "too red"
Set-Content C:\Temp\Tomatoes-2022-09-27Ripe.txt        # saving as a new file *Ripe.txt

This works for individual files just fine but what I need to do is the same process for any file within the Temp directory. They all have similar names other than the date.

Here's what I have compiled for all files, but it overwrites existing files rather than creating a new one and I don't know how to get it to write to new files ie Tomotoes*Ripe.txt: *being the unique date

Get-ChildItem C:\Temp\*.* -Recurse | ForEach-Object { 
    (Get-Content $_) | 
    Where-Object { - $_.Contains('red') } |  
    ForEach-Object { $_ -replace "[/()]", ":" } | 
    Where-Object { -not $_.Contains('too red') } | 
    Set-Content $_ 
}

Or will it be better to create a copy first using New-Item then process the other jobs?

It's going to be something very simple I know! And will most definitely kick myself once corrected.

Thanks in advance

CodePudding user response:

Looks like what you want is something like this:

Get-ChildItem -Path 'C:\Temp' -File -Recurse | ForEach-Object { 
    $newFile    = Join-Path -Path $_.DirectoryName -ChildPath ('{0}Ripe{1}' -f $_.BaseName, $_.Extension)
    $newContent = Get-Content $_.FullName | 
                  Where-Object { $_ -like '*red*' -and $_ -notlike '*too red*' } |  
                  ForEach-Object { $_ -replace "[/()]", ":" } 
    $newContent | Set-Content -Path $newFile
}

CodePudding user response:

To complement Theo's helpful answer - which is probably the most straightforward in your case - with a streaming, single-pipeline solution that showcases two advanced techniques:

  • the common -PipelineVariable (-pv) parameter, which allows you to store a cmdlet's current pipeline output object in a self-chosen variable that can be referenced later in a script block in a later pipeline segment.

  • delay-bind script blocks, which allow you to use a script block to dynamically determine a parameter value, typically based on the pipeline input object at hand; in this case, the pipeline variable is used.

# Create sample files
'red1' > t1.txt
'red2' > t2.txt

Get-ChildItem -PipelineVariable file t?.txt | # note `-PipelineVariable file`
  Get-Content |                               # read file line by line
  Where-Object { $_.Contains('red') } |       # sample filter
  ForEach-Object { $_ -replace 'e', '3' } |   # sample transformation
  Set-Content -LiteralPath {                  # delay-bind script block
    # Determine the output file name based on pipelinve variable $file
    '{0}Ripe{1}' -f $file.BaseName, $file.Extension 
  } 

This results in files t1Ripe.txt and t2Ripe.txt, containing r3d1 and r3d2, respectively.

  • Related