How to replace '= ' with '=none' - powershell

i have this noempty.txt
Caption=http://support.microsoft.com/?kbid=3150513
CSName=DC04
Description=Update
FixComments=
HotFixID=KB3150513
InstallDate=
InstalledBy=NT AUTHORITY\SYSTEM
InstalledOn=11/29/2022
Name=
ServicePackInEffect=
Status=
for example the line "FixComments=" or "InstallDate=" or "name=" i have to add in every line the word "none"
I try whit
(Get-Content -Path c:\path\noempty.txt) | ForEach-Object {$_ -Replace '=\s', '=NONE'} | Set-Content -Path c:\path\noempty2.txt
But it doesn't work
Any advice?
Thank you very much
Alex
(Get-Content -Path c:\path\noempty.txt) | ForEach-Object {$_ -Replace '=\s', '=NONE'} | Set-Content -Path c:\path\noempty2.txt
for example the line "FixComments=" or "InstallDate=" or "name=" i have to add in every line the word "none"

You could read the whole file, match the parts that you are interested in and using the full match with $0 followed by NONE in the replacement.
$pattern = "(?m)^[^\s=]+=[\p{Zs}\t]*$"
(Get-Content c:\path\noempty.txt -Raw) -replace $pattern, '$0NONE'
The pattern matches:
(?m) Inline modifier to enable multiline
^ Start of string
[^\s=]+ Match 1+ times a non whitespace character except for =
= Match literally
[\p{Zs}\t]* Match optional horizontal whitespace characters
$ End of string
See the regex matches.
Output
Caption=http://support.microsoft.com/?kbid=3150513
CSName=DC04
Description=Update
FixComments=NONE
HotFixID=KB3150513
InstallDate=NONE
InstalledBy=NT AUTHORITY\SYSTEM
InstalledOn=11/29/2022
Name=NONE
ServicePackInEffect=NONE
Status=NONE
If you don't want to keep possible trailing spaces after the equals sign, you can use a capture group, and that group 1 in the replacement instead of the whole match:
$pattern = "(?m)^([^\s=]+=)[\p{Zs}\t]*$"
(Get-Content c:\path\noempty.txt -Raw) -replace $pattern, '$1NONE'
See the group 1 matches.

Related

how to replace text ($) with quotation marks in a text file by using powershell

I am trying to replace the text ($) with quotation marks in a text file by using PowerShell
Here is the code I am trying, But not giving expected results:
$FilePath = "C:\PT\Test\"
Get-ChildItem $FilePath -Filter *.TXT | ForEach-Object {
(Get-Content $_.FullName) | Foreach-Object {
$_ -replace ',"$"', ',"$",'
} | Set-Content $_.FullName
}
As pointed out by Abraham in his comment, the $ is a reserved character in regex known as Anchor, if you want to match a literal $ using -replace you would need to escape it: \$:
Get-ChildItem $FilePath -Filter *.TXT | ForEach-Object {
(Get-Content $_.FullName -Raw) -replace ',"\$"',',"$",' |
Set-Content $_.FullName
}
The other alternative is to use the .Replace(..) string method which will match literal characters.
Get-ChildItem $FilePath -Filter *.TXT | ForEach-Object {
(Get-Content $_.FullName -Raw).Replace(',"$"',',"$",') |
Set-Content $_.FullName
}
By looking at your code seems like you want to replace ,"$" with ,"$",, if this was not the case let me know.
The -replace operator:
uses a regex as the search-pattern operand, and therefore requires a verbatim $ to be escaped as \$ in order to be interpreted as such (an unescaped $ is a regex metacharacter representing the end of the input string)
also uses $ as a metacharacter in the substitution operand, namely to refer to the text that the regex captured ($&) or parts thereof (e.g. $1 to refer to what the first capture group ((...)) captured). In this case, escape it as $$.
Note: Situationally, even an unescaped $ may work, namely if, in combination with the subsequent characters, if any, it cannot be interpreted as a placeholder such as $& or $1. However, in the interest of robustness it is better to escape.
Therefore, use:
PS> ',"$"20' -replace ',"\$"', ',"$$",'
,"$",20
Taking a step back:
As Abraham Zinala suggests, for verbatim string replacements, the .Replace() string method is sufficient, whose use doesn't necessitate escaping, and which is faster to boot:
PS> ',"$"20'.Replace(',"$"', ',"$",')
,"$",20
Caveat: Unlike -replace, .Replace() is case-sensitive - invariably in Windows PowerShell and by default in PowerShell (Core) 7+.
See this answer for a detailed juxtaposition of -replace and .Replace(), including how to perform escaping for -replace programmatically.
To put it all together, along with an optimization that reads each file in full, with Get-Content -Raw, for much faster processing (to avoid appending a trailing newline, -NoNewLine is used with Set-Content):
$FilePath = "C:\PT\Test"
Get-ChildItem $FilePath -Filter *.TXT | ForEach-Object {
(Get-Content -Raw $_.FullName).Replace(',"$"', ',"$",') |
Set-Content -NoNewLine $_.FullName
}

Replace a non-unique line of text under a unique line of text in a text file using powershell

I have the following txt file.
[AppRemover]
Enable=0
[CleanWipe]
Enable=0
[RerunSetup]
Enable=0
How do I change the Enable=0 to Enable=1 under [CleanWipe] only?
Below is how I plan on using the code with my file.
$Path = C:\temp\file.txt
$File = Get-Content -Path $Path
# Code to update file
$File | Out-File $Path
You can use -replace to update the value if it is 0.
$Path = C:\temp\file.txt
(Get-Content $Path -Raw) -replace "(?<text>\[CleanWipe\]\r?\nEnable=)0",'${text}1' |
Set-Content $Path
Using a module that parses INI files will be the best solution though. I'd recommend trying PsIni.
Explanation:
The -Raw switch reads the file contents as a single string. This makes it easier to work with newline characters.
-replace performs a regex match and then replace. Below is the regex match breakdown.
(?<text>) is a named capture group. Anything matched within that capture group can be recalled in the replace string as '${text}'.
\[CleanWipe\] is a literal match of [CleanWipe] while escaping the [] characters with \.
\r? is optional carriage return
\n is the newline character
Enable= is a literal match
0 is a literal match
The replace string is the capture group contents and 1 when a match exists. Technically, a capture group is not needed if you want to use a positive lookbehind instead. The positive lookbehind assertion is (?<=). That solution would look like the following:
$Path = C:\temp\file.txt
(Get-Content $Path -Raw) -replace "(?<=\[CleanWipe\]\r?\nEnable=)0",'1' |
Set-Content $Path
The problem with the -replace solutions as they written is they will update the file regardless of a change actually being made to the contents. You would need to add an extra comparison to prevent that. Other issues could be extra white space on any of these lines. You can account for that by adding \s* where you think those possibilities may exist.
Alternative With More Steps:
$file = Get-Content $Path
$TargetIndex = $file.IndexOf('[CleanWipe]') + 1
if ($file[$TargetIndex] -match 'Enable=0') {
$file[$TargetIndex] = 'Enable=1'
$file | Set-Content $Path
}
This solution will only update the file if it meets the match condition. It uses the array method IndexOf() to determine where [CleanWipe] is. Then assumes the line you want to change is in the next index.
IndexOf() is not the only way to find an index. The method requires that your line match the string exactly. You can use Select-String (case-insensitive by default) to return a line number. Since it will be a line number and not an index (indexes start at 0 while line numbers start at 1), it will invariably be the index number you want.
$file = Get-Content $Path
$TargetIndex = ($file | Select-String -Pattern '[CleanWipe]' -SimpleMatch).LineNumber
if ($file[$TargetIndex] -match 'Enable=0') {
$file[$TargetIndex] = 'Enable=1'
$file | Set-Content $Path
}

Change pipe delimited file to comma delimited in Powershell

I have a pipe delimited .TXT file. I need to change the delimiter to a comma instead but still keep the file extension as .TXT. The file looks like this:
Column 1 |Column 2
13|2019-09-30
96|2019-09-26
173|2019-09-25
I am using Windows Powershell 5.1 version for my script.
I am using the following code:
$file = New-Object System.IO.StreamReader -Arg "c:\file.txt"
$outstream = [System.IO.StreamWriter] "c:\out.txt"
while ($line = $file.ReadLine()) {
$s = $line -replace '|', ','
$outstream.WriteLine($s)
}
$file.close()
$outstream.close()
Instead of just replacing the pipe with a comma, the output file looks like this:
C,o,l,u,m,n, 1 , |,C,o,l,u,m,n, 2
1,3,|,2,0,1,9,-,0,9,-,3,0
9,6,|2,0,1,9,-,0,9,-,2,6
1,7,3,|,2,0,1,9,-,0,9,-,2,5
The only problem with your answer is in how you try to replace the | characters in the input:
$s = $line -replace '|', ',' # WRONG
PowerShell's -replace operator expects a regex (regular expression) as its first RHS operand, and | is a regex metacharacter (has special meaning)[1]; to use it as a literal character, you must \-escape it:
# '\'-escape regex metacharacter '|' to treat it literally.
$s = $line -replace '\|', ','
While PowerShell's -replace operator is very flexible, in simple cases such as this one you can alternatively use the [string] type's .Replace() method, which performs literal string replacements and therefore doesn't require escaping (it's also faster than -replace):
# Use literal string replacement.
# Note: .Replace() is case-*sensitive*, unlike -replace
$s = $line.Replace('|', ',')
[1] | denotes an alternation in a regex, meaning that the subexpressions on either side are matched against the input string and one of them matching is sufficient; if your full regex is just |, it effectively matches the empty string before and after each character in the input, which explains your symptom; e.g., 'foo' -replace '|', '#' yields #f#o#o#
You can use Import-Csv and Export-Csv by specifying the -Delimiter.
Import-Csv -Delimiter '|' -Path "c:\file.txt" | Export-Csv -Delimiter ',' -Path "c:\file.txt" -NoTypeInformation
You will find the -split and -join operators to be of interest.
Get-Content -Path "C:\File.TXT" | ForEach-Object { ($_ -split "\|") -join "," } | Set-Content -Path "C:\Out.TXT"

-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*"} | ...

Find and Replace character only in certain column positions in each line

I'm trying to write a script to find all the periods in the first 11 characters or last 147 characters of each line (lines are fixed width of 193, so I'm attempting to ignore characters 12 through 45).
First I want a script that will just find all the periods from the first or last part of each line, but then if I find them I would like to replace all periods with 0's, but ignore periods on the 12th through 45th line and leaving those in place. It would scan all the *.dat files in the directory and create period free copies in a subfolder. So far I have:
$data = get-content "*.dat"
foreach($line in $data)
{
$line.substring(0,12)
$line.substring(46,147)
}
Then I run this with > Output.txt then do a select-string Output.txt -pattern ".". As you can see I'm a long ways from my goal as presently my program is mashing all the files together, and I haven't figured out how to do any replacement yet.
Get-Item *.dat |
ForEach-Object {
$file = $_
$_ |
Get-Content |
ForEach-Object {
$beginning = $_.Substring(0,12) -replace '\.','0'
$middle = $_.Substring(12,44)
$end = $_.Substring(45,147) -replace '\.','0'
'{0}{1}{2}' -f $beginning,$middle,$end
} |
Set-Content -Path (Join-Path $OutputDir $file.Name)
}
You can use the powershell -replace operator to replace the "." with "0". Then use substring as you do to build up the three portions of the string you're interested in to get the updated string. This will output an updated line for each line of your input.
$data = get-content "*.dat"
foreach($line in $data)
{
($line.SubString(0,12) -replace "\.","0") + $line.SubString(13,34) + ($line.substring(46,147) -replace "\.","0")
}
Note that the -replace operator performs a regular expression match and the "." is a special regular expression character so you need to escape it with a "\".