-notmatch with ... (3 dots) - powershell

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

Related

How to replace '= ' with '=none'

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.

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
# ...

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

powershell replace command if line starts with a specific character

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

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 "\".