powershell replace command if line starts with a specific character - powershell

I have a text file that I would like to read and do some replacements using powershell only if the line starts with a specific character.
SAy i want to change all the dash (-) to an 'x' if and only if the line starts with a y.
I tried using the command
(Get-Content trial.log2) | Foreach-Object {$_ -replace "-", 'x'} | Set-Content trial.log2
However, it actually replaces all occurrences of the dash, not only for the line the starts with a y.
Can this be also done if I want to have multiple find replace and string manipulation using one get content command?
I have another string manipulation but only if it starts with an F
If line starts with an F, then get first 4 characters of the line, then append 'NEW' then get the next characters from character 20 to 30.
if line starts with a y, then do a replace of - with an X.
$F=(get-content $file) -like 'F*'
(Get-Content $file) | Foreach-Object {
$_ -replace "^F.+", -join("$F".Substring(0,4), "$NEW3",
} | Set-Content trial.log2
Get-Content trial.log2 | ForEach-Object {
if ( $_ -match '^y' ) {
$_ -replace '-', 'X'
}
else {
$_
}
} | Set-Content trial.log3
However, if i do this, texts are being written twice. I think there is something wrong with how I look for the line that starts with the F
Any help is appreciated. Thanks!

You can use a look-behind ((?<=pattern)) to assert that the preceding characters include a y following the start of the string:
(Get-Content trial.log2) | Foreach-Object {$_ -replace '(?<=^y.*)-','x'} | Set-Content trial.log2

How about something like:
Get-Content trial.log2 | ForEach-Object {
if ( $_ -match '^y' ) {
$_ -replace '-', 'x'
}
else {
$_
}
} | Out-File trial.log2.temp

Related

How to search and replace combined with if & else in powershell

Every night I got a text file that needs to be edited manually.
The file contains approximately 250 rows. Three example of a rows:
112;20-21;32;20-21;24;0;2;248;271;3;3;;
69;1;4;173390;5;0;0;5460;5464;3;3;;
24;7;4;173390;227;0;0;0;0;3;3;;
I need to replace the two last values in each row.
All rows ending with ;0;3;3;; should be replaced with ;0;17;18;; (the last one, solved)
The logic for the other two:
If the row contain a '-' it should replace the two last values from ;3;3;; to ;21;21;;
If it don´t have a '-' it should replace the two last values from ;3;3;; to ;22;22;;
This is my script
foreach ($file in Get-ChildItem *.*)
{
(Get-Content $file) -replace ';0;3;3;;',';;0;17;18;;' -replace ';3;3;;',';21;21;;' |Out-file -encoding ASCII $file-new}
If I could add a '-' in the end of each row continga a '-' I could solve the issue with a modified script:
(Get-Content $file) -replace ';0;3;3;;',';;0;17;18;;' -replace ';3;3;;-',';22;22;;' -replace ';3;3;;',';21;21;;'|Out-file -encoding ASCII $file-new}`
But how do I add a '-' in the end of a row, if the row contain a '-'?
Best Regards
Mr DXF
I tried with select-string, but I can´t figure it out...
if select-string -pattern '-' {append-text '-'|out-file -encoding ascii $file-new
else end
}
The following might do the trick, it uses a switch with the -Regex flag to read your files and match lines with regular expressions.
foreach ($file in Get-ChildItem *.* -File) {
& {
switch -Regex -File $file.FullName {
# if the line ends with `;3;3;;` but is not preceded by `;0`
'(?<!;0);3;3;;$' {
# if it contains a `-`
if($_.Contains('-')) {
$_ -replace ';3;3;;$', ';21;21;;'
continue
}
# if it doesn't contain a `-`
$_ -replace ';3;3;;$', ';22;22;;'
continue
}
# if the line ends with `';0;3;3;;`
';0;3;3;;$' {
$_ -replace ';0;3;3;;$', ';0;17;18;;'
continue
}
# if none of the above conditions are matched,
# output as is
Default { $_ }
}
} | Set-Content "$($file.BaseName)-new$($file.Extension)" -Encoding ascii
}
Using the content example in question the end result would become:
112;20-21;32;20-21;24;0;2;248;271;21;21;;
69;1;4;173390;5;0;0;5460;5464;22;22;;
24;7;4;173390;227;0;0;0;0;17;18;;

Powershell5 Compact code by combining foreach, begin, process, and replace command

Can I get the same results with less code?
The code searches sample.bat for the strings AROUND LINE {1-9999} and LINE2 {1-9999} and replaces {1-9999} with the {line number} the code is on.
sample.bat:
AROUND LINE 262
LINE2 1964
Old code:
gc $env:temp\sample.bat | foreach -Begin {$lc = 1} -Process {
$_ -replace "AROUND LINE \d*", "AROUND LINE $lc";
$lc += 1
} | Out-File -Encoding Ascii $env:temp\results.bat
(gc $env:temp\results.bat) | foreach -Begin {$lc = 1} -Process {
$_ -replace "LINE2 \d*", "LINE2 $lc";
$lc += 1
} | Out-File -Encoding Ascii $env:temp\results.bat
Current code:
(gc $env:temp\sample.bat) | foreach -Begin {$lc = 1} -Process {
$_ -replace "AROUND LINE \d*", "AROUND LINE $lc";
$lc += 1
} | foreach -Begin {$lc = 1} -Process {
$_ -replace "LINE2 \d*", "LINE2 $lc";
} | Out-File -Encoding Ascii $env:temp\sample.bat
Expected results:
AROUND LINE 1
LINE2 2
Actual results:
AROUND LINE 1
LINE2 2
You can make this work with a single regex:
gc $env:temp\sample.bat | foreach -Begin {$lc = 1} -Process {
$_ -replace '(?<=AROUND LINE |LINE2 )\d+', $lc++
} | Set-Content -Encoding Ascii $env:temp\results.bat
Note that I'm using '...' (single quotes) rather than "..." (double quotes) to enclose the regex, which is preferable to rule out potential confusion arising from PowerShell performing string expansion (interpolation) first.
$lc++ returns the current $lc value and increments it by 1 afterwards, obviating the need for the $lc += 1 statement.
Also, I've replaced Out-File with Set-Content, as they're functionally the same for saving strings, but the latter is faster.
Finally, to match one or more digits, use \d+ rather than \d*.
A note on $_ -replace '(?<=AROUND LINE |LINE2 )\d+', $lc++:
Regex (?<=AROUND LINE |LINE2 )\d+ uses a look-behind assertion ((?<=...) to look for either (|) string AROUND LINE  or string LINE2 before one or more (+) digits (\d).
The look-behind assertion is by design not considered part of the match, so that the substring getting replaced is limited to the run of digits, i.e., the number only.
$lc++ is the replacement operand: it returns the current value of variable $lc and increments its value afterwards; note that even though $lc is a number ([int]), PowerShell automatically converts it to a string for the replacement.
Generally, though, you can simply chain -replace operations:
# ...
$_ -replace 'AROUND LINE \d+', "AROUND LINE $lc" -replace 'LINE2 \d+', "LINE2 $lc"
++$lc
# ...

Split untill end of line powershell

I'm trying to do a script in PowerShell which adds a hyphen after every each 2 characters which is in a text file, and i have done it but I am facing an issue which is.
Code >
$file = get-content .\textfile.txt
($file -split "([a-z0-9]{2})" | ?{ $_.length -ne 0 }) -join "-" | Set-Content .\textfile.txt
If i have a value like below in a .txt file
000000000000
111111111111
Output is coming like.
00-00-00-00-00-00-11-11-11-11-11-11
I need an output like.
00-00-00-00-00-00
11-11-11-11-11-11
Kindly suggest what should i have to change.
Get-Content removes all the newlines, and outputs strings to the pipeline, one for each line.
$file is an array of two strings, #('000000000000', '111111111111'). When you -split it applies to both of the strings, and it turns into #('00', '00', '00', '00', '00', '00', '11', '11', '11', '11', '11', '11') and now you cannot tell where the lines start or end.
To fix it, you need to process each line separately:
(Get-Content .\textfile.txt) | ForEach-object {
($_ -split "([a-z0-9]{2})" |? { $_ }) -join "-"
} | Set-Content .\textfile.txt
Or change what you're doing to do a replace, that will work within the lines instead of merging them together:
(gc .\textfile.txt) -replace '([a-z0-9]{2})\B', '$1-' | sc textfile.txt
and the \B stops it from putting a - at the end of the line.
As answered on the TechNet Forums at https://social.technet.microsoft.com/Forums/en-US/e60e33d2-f065-4219-82cf-5797aaf10891/split-foreach-line?forum=winserverpowershell
This will add a dash (-) after every two characters in a line. Since it will also do this at the end of a line, we trim it.
$inputFile = Get-Content -Path C:\temp\file.txt
$newFile = foreach ($line in $inputFile) {
($line -replace '(..)', '$1-').trim('-')
}
$newFile | Set-Content -Path C:\temp\file.txt

Splitting in Powershell

I want to be able to split some text out of a txtfile:
For example:
Brackets#Release 1.11.6#Path-to-Brackets
Atom#v1.4#Path-to-Atom
I just want to have the "Release 1.11.6" part. I am doing a where-object starts with Brackets but I don't know the full syntax. Here is my code:
"Get-Content -Path thisfile.txt | Where-Object{$_ < IM STUCK HERE > !
You could do this:
((Get-Content thisfile.txt | Where-Object { $_ -match '^Brackets' }) -Split '#')[1]
This uses the -match operator to filter out any lines that don't start with Brackets (the ^ special regex character indicates that what follows must be at the beginning of the line). Then it uses the -Split operator to split those lines on # and then it uses the array index [1] to get the second element of the split (arrays start at 0).
Note that this will throw an error if the split on # doesn't return at least two elements and it assumes that the text you want is always the second of those elements.
$bracketsRelease = Get-Content -path thisfile.txt | foreach-object {
if ( $_ -match 'Brackets#(Release [^#]+)#' )
{
$Matches[1]
}
}
or
(select-string -Path file.txt -Pattern 'Brackets#(Release [^#]+)#').Matches[0].Groups[1].value

-notmatch with ... (3 dots)

I have a strange problem with my PowerShell CSV tool. I have tried to write a small check that filters out certain names and characters. These names/characters are in a textfile like this:
XXX
nana
YYY
...
DDD
I do the check lie this:
$reader = [System.IO.File]::OpenText($fc_file.Text)
try {
for() {
$line = $reader.ReadLine()
if ($line -eq $null) { break }
# process the line
Import-Csv $tempfile -Delimiter $delimeter -Encoding $char |
where {$_.$fc_suchfeld -notmatch $line} |
Export-Csv $tempstorage -Delimiter $delimeter -Encoding $char -NoTypeInfo
It works great until the line with the 3 dots. At this point almost all lines are deleted. How can I solve this problem?
The -match operator does regular expression matches. . is a metacharacter in regular expressions, matching any character except newlines. Thus a regular expression ... matches any line with at least 3 characters. If you want to use the lines from $fc_file as literal string matches you need to escape them:
... | where {$_.$fc_suchfeld -notmatch [regex]::Escape($line)} | ...
or do a wildcard match:
... | where {$_.$fc_suchfeld -notlike "*$line*"} | ...