lonelydev101
lonelydev101

Reputation: 1911

alter .txt file and save it with PowerShell

I am doing classic find&replace in some .txt file with powershell. How can I "save" file at the end? I tried with | Set-Content but nothing happens. Maybe I need to Add-Content first?

#Find what?
$optionBuilderStringToFind = "optionsBuilder.UseSqlServer"
$findUsingKeywordString = "using Microsoft."

#Replace with
$namespaceAdd = "using Microsoft.Extensions.Configuration;"
$optionBuilderConfigurable ="optionsBuilder.UseSqlServer(_configuration.GetConnectionString(`"Database`") 
 );"

gc -Path .\APSContext.cs | % { 
if ($_ -match "using System;") {
    $_ = $_ + "`n" + $namespaceAdd
    #write-host $_
}
if ($_ -match "optionsBuilder.UseSqlServer") {
    $_ = $optionBuilderConfigurable
    #write-host $_
}
} | Set-Content -Path .\test.cs

Update: Here is testFile where I am looking to alter it. The content of the file is not important. I want to add another reference like "using Something.Something" and in the middle of the file to replace "optionsBuilder.UseSqlServer("dfjidfjljfiejf88");" with "optionsBuilder.UseSqlServer("_configtest");":

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

namespace SRC.APS.Model.APSDB
{
public partial class APSContext : DbContext
{
    public APSContext()
    {
    }

    public APSContext(DbContextOptions<APSContext> options)
        : base(options)
       protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {

            optionsBuilder.UseSqlServer("dfjidfjljfiejf88");
        }
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasAnnotation("ProductVersion", "2.2.0-rtm-35687");

    }

Maybe I need to use Out-String instead?

Upvotes: 0

Views: 57

Answers (2)

Tomalak
Tomalak

Reputation: 338316

Any script block in Powershell can produce values. This is done by not storing a value in a variable:

  • { $foo = 3 } produces nothing
  • { 3 } produces the integer 3.

In the same way

  • ForEach-Object { $_ = "something" } produces nothing
  • ForEach-Object { $_ = "something"; $_ } produces the string "something"

Your loop body does not output anything, it's like the upper example above. Therefore, Set-Content has nothing to do. Modify the block to actually return the changed value of $_:

$replacements = @(
    @{regex='using (System|Potentially|Others);'; replacement='using Microsoft.$1;' }
    @{regex='optionsBuilder\.UseSqlServer\("[^"]*"\)'; replacement='optionsBuilder.UseSqlServer("Database")' }
    # more search/replace pairs
)

Get-Content .\APSContext.cs -Encoding UTF8 | ForEach-Object {
    foreach ($item in $replacements) {
        $_ = $_ -replace $item.regex, $item.replacement
    }
    $_   # <--- this is what produces the line
} | Set-Content -Path .\test.cs -Encoding UTF8

That being said, never load or save text files without specifying their encoding. For C# source code files, I think UTF-8 is the default.

And that being said, modifying source code with regular expressions is not a good thing to do. If this is a one-off, fine. If you plan to do this on a regular basis, you are doing something wrong. Work with configuration files or environment variables instead of keeping in your codebase literal values that are subject to regular change.

Upvotes: 1

Lee_Dailey
Lee_Dailey

Reputation: 7489

as i mentioned - and as Tomalak pointed out - your mucking with the current pipeline object is the source of the glitch. [grin] this code fixes a logic error in your IF cascade [which may be better done with a switch block], removes the unwise $_ fiddling, and then ensures there is always some output.

# fake reading in a text file
#    in real life, use Get-Content
$InStuff = @'
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

namespace SRC.APS.Model.APSDB
{
public partial class APSContext : DbContext
{
    public APSContext()
    {
    }

    public APSContext(DbContextOptions<APSContext> options)
        : base(options)
       protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {

            optionsBuilder.UseSqlServer("dfjidfjljfiejf88");
        }
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasAnnotation("ProductVersion", "2.2.0-rtm-35687");

    }
'@ -split [environment]::NewLine

#Find what?
$optionBuilderStringToFind = "optionsBuilder.UseSqlServer"
$findUsingKeywordString = "using Microsoft."

#Replace with
$namespaceAdd = 'using Microsoft.Extensions.Configuration;'
$optionBuilderConfigurable ='optionsBuilder.UseSqlServer(_configuration.GetConnectionString("Database"));'

$InStuff | ForEach-Object { 
    if ($_ -match "using System;")
        {
        $_ + "`n" + $namespaceAdd
        #write-host $_
        }
        elseif ($_ -match "optionsBuilder.UseSqlServer")
        {
        $optionBuilderConfigurable
        #write-host $_
        }
        else
        {
        $_
        }
    }

output ...

using System;
using Microsoft.Extensions.Configuration;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

namespace SRC.APS.Model.APSDB
{
public partial class APSContext : DbContext
{
    public APSContext()
    {
    }

    public APSContext(DbContextOptions<APSContext> options)
        : base(options)
       protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {

optionsBuilder.UseSqlServer(_configuration.GetConnectionString("Database"));
        }
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasAnnotation("ProductVersion", "2.2.0-rtm-35687");

    }

Upvotes: 0

Related Questions