Search code examples
powershelltextreplace

Manipulate text file - change multiple lines


Have been looking at what I thought would be a really simple task this morning.... and turns out it wasn't, at least not for me.

What I am trying to do is get powershell to read through an ini-file, and change multiple values under specific headers only.

[Datoformat]
Separator=.
[Database]
Path=servername:d:\mycompany\nextsys_db\next.fdb
DokumentDbPath=
FireBird25=Nei

[Pictures]
Path=T:\nextsys_bilde
DbExtractFolder=

[Brukerinnstillinger]
Prioriter=Ja
�pneJournalAuto=Nei
TillatBrukerBytte=Ja
EnkelJournal=Nei
AvtBokRadHoyde=
AvtBokMndKolonneBredde=
Resepsjonsmaskin=Nei
Tilgangsoversikt=Nei
AvtaleHentPasientAutomatisk=Ja
VisFargeForAnsvarlig=Nei
[Eksport]
Automatisk=Nei
[Import]
Automatisk=Nei
[Skjerm]
HuskSkjermPosisjon=Ja
ProgramSkjermPosX=-8
ProgramSkjermPosY=-8
ProgramSkjermBredde=1936
ProgramSkjermHoyde=1056
MaksimertSkjermPosisjon=Ja
EgenDefSkjermSizeX=1919
EgenDefSkjermSizeY=1080
UtvidetAvtalebok=Ja
UtvidetJournal=Ja
UtvidetRecall=Ja
UtvidetOmsetning=Ja
UtvidetUtestaaende=Ja
UtvidetRegnskap=Ja
UtvidetFakturaOversikt=Ja
UtvidetGenerelleModuler=Ja
UtvidetAlleModuler=Ja
1280800=Nei
1440900=Nei
16801050=Nei
19201080=Nei
Egendefinert=Ja
AutomaticSize=Nei
[Spesialinnstillinger]
EnForekomst=Nei
TestModusInfo=Nei
AktiverRegningskortJournalSjekk=Nei
IkkeSpmOmHelseskjema=Nei
IkkeSpmOmBrukerBytteAvtale=Nei
IkkeSpmOmBrukerBytteAnsvarlig=Nei
[Vedlegg]
Path=
[Avtalebok]
Utseende=
Bakgrunn=
[Journal]
JournalTextSize=8
JournalTextFont=
JournalTextStyle=
FetSkrift=Nei
[Rontgen]
AlternativAapning=Nei
[Utseende]
IkkeVisDagensPasienter=Nei
[MediLink]
BenyttMediLink=Nei
AutomatiskInnlesing=Nei
MediLinkInnlesingIntervall=
[AutomatiskOppdatering]
VedOppstart=Nei
Alltid=Nei
FraLokaltNettverk=Nei
NettverkPath=
UtenBekreftelse=Nei
[BankTerminal]
PosPay=Nei
BetTermAlwaysOn=Ja
BBSFlerBrukerTerminal=Nei
ThisMerchantHighest=Nei
MerchantId=
TerminalId=
BrukerBoPosDrivere=Nei
BrukerBaxiDrivere=Ja
BaxiAktiverXReport=Ja
BaxiAktiverZReport=Nei
BaxiAktiverReversal=Nei
[EasyPanel]
Benytt=Nei
Notat=Nei
Diagnose=Nei
Epikriser=Nei
Sykemelding=Nei
Resept=Nei
Henvisning=Nei
Helseskjema=Nei
Endo=Nei
Perio=Nei
Bilder=Nei
Tekn.skjema=Nei
Skjema=Nei
Dokumentmodul=Nei
[Oppstartsbilde]
VisesVedOppstart=Nei
[Printer]
LokaltOppsett=Ja
TryktA5Resept=Nei
TryktA5ReseptDesign2=Nei
TimeKortKvittSkriver=Nei
VisMinimalBaxInfo=Nei
ReseptKvittSkriver=Nei
JusteringVenstreMargX=
JusteringToppMargY=
Faktura=HP LaserJet Pro MFP M125-M126 PCLmS
Recallkort=HP LaserJet Pro MFP M125-M126 PCLmS
Timekort=HP LaserJet Pro MFP M125-M126 PCLmS
Kvittering=HP LaserJet Pro MFP M125-M126 PCLmS
Resept=HP LaserJet Pro MFP M125-M126 PCLmS
Standard=HP LaserJet Pro MFP M125-M126 PCLmS
Tekniker=HP LaserJet Pro MFP M125-M126 PCLmS
FakturaStorrelse=A4
RecallKortStorrelse=A4
TimekortStorrelse=A4
KvitteringStorrelse=A4
ReseptStorrelse=A4
TeknikerStorrelse=A4
StandardStorrelse=A4
FakturaOppsettKode=
RecallkortOppsettKode=
TimekortOppsettKode=
KvitteringOppsettKode=
ReseptOppsettKode=
TeknikerOppsettKode=
StandardOppsettKode=
FakturaPapirretning=St�ende
RecallKortPapirretning=St�ende
TimekortPapirretning=St�ende
KvitteringPapirretning=St�ende
ReseptPapirretning=St�ende
TeknikerPapirretning=St�ende
StandardPapirretning=St�ende
FakturaPreview=Ja
RecallKortPreview=Ja
TimekortPreview=Ja
KvitteringPreview=Ja
ReseptPreview=Ja
TeknikerPreview=Ja
StandardPreview=Ja
[Paaminnelse]
Automatisk=Nei
AutomatiskService=Nei
Tidspunkt=
Dagens=Nei
KunMerketOnsker=Nei
AutomatiskEpost=Nei
AntallDagerFrem=Nei
AntallDagerFremAntall=2
ErstattTekst=Nei
PaaminnelseTekst=Hei [fornavn], minner om time reservert til deg: [dato] kl. [tid]. Timer  som ikke passer m� avbestilles senest 24 timer i forveien.  Mvh.  [tittel] [brukernavn]  
[SMS]
Testmodus=Nei
VisAdvarslerVedIkkeSendtSMS=Nei
[Innlogging]
TillatInnloggingMedEldreProgramversjonEnnDatabase=Nei

I want to change the values "Automatisk=Nei" to "Automatisk=Ja", "Tidspunkt=" to "Tidspunkt=10:00" and "AntallDagerFrem=Nei" to "AntallDagerFrem=Ja"... The Tidspunkt and AntallDagerFrem values shouldn't be that hard since they only appear once in the file, but "Automatisk=Nei" appears 4 times, and I only want to change the one below [Paaminnelse]

$content = @(if ((Get-Content $inifile) -join "`n" -match '\[Paaminnelse\]([\s\S]*)\[SMS\]') { $Matches[1] }) 

$newcontent = $test -replace  'Automatisk=Nei','Automatisk=Ja' -replace 'Tidspunkt=','Tidspunkt=10:00' -replace 'AntallDagerFrem=Nei','AntallDagerFrem=Ja'

This finds the correct lines from the ini-file and changes the values I want to change, but using Set-Content $inifile -Value $newcontent will of course remove all everything else from the file which is not what I want :)

More used to cat, grep, awk and sed than PowerShell to be honest so any pointers would be helpful.


Solution

  • As Theo notes, consider using a dedicated INI file parser, such as the one provided by the third-party PsIni module - see this answer for how to install and use it.

    • Update: Your own answer now shows how to use it to solve your specific problem.

    If installing a module isn't an option, I suggest using a -switch statement, which has awk-like capabilities:

    # Array of sample lines, as would be returned by:
    #   Get-Content $inifile
    $iniFileLines = @'
    [Datoformat]
    Separator=.
    
    [Eksport]
    Automatisk=Nei
    
    [Paaminnelse]
    Automatisk=Nei
    AutomatiskService=Nei
    Tidspunkt=
    
    [Printer]
    AutomatiskEpost=Nei
    AntallDagerFrem=Nei
    AntallDagerFremAntall=2
    '@ -split '\r?\n'
    
    $inPaaminnelseSect = $false
    
    # Note: To operate directly on your file, replace 
    #       ($iniFileLines) with -File $iniFile
    switch -Regex ($iniFileLines) {
      '^(Tidspunkt)=$' { '{0}=10:00' -f $Matches[1]; continue }
      '^(AntallDagerFrem)=Nei' { '{0}=Ja' -f $Matches[1]; continue }
      '^(Automatisk)=Nei' { 
        if ($inPaaminnelseSect) { '{0}=Ja' -f $Matches[1] } else { $_ }; continue 
      }
      '^\[(.+)\]' { $inPaaminnelseSect = $Matches[1] -eq 'Paaminnelse'; $_ }
      default { $_ } # pass through
    }
    

    Note:

    • The above assumes:

      • that your file has exactly the format as shown in your question. However, it would be easy to make parsing more flexible with respect to optional whitespace.

      • that you only want to replace entries if they have a specific current value (or none); this too could easily be changed to replace the values irrespective of the current value.

    • Matching is case-insensitive, as PowerShell generally is by default; add the -CaseSensitive switch to make it case-sensitive.

    Output:

    [Datoformat]
    Separator=.
    
    [Eksport]
    Automatisk=Nei
    
    [Paaminnelse]
    Automatisk=Ja
    AutomatiskService=Nei
    Tidspunkt=10:00
    
    [Printer]
    AutomatiskEpost=Nei
    AntallDagerFrem=Ja
    AntallDagerFremAntall=2