Search for Multiple strings in a text file in Powershell - powershell

I have a text 'File.txt'. There are 100's of lines.
The file contains the string 'XX' (in any line), 'YY' (in any line) and 'ZZ' (in any line).
I want to check if the text file really contains 'XX' or 'YY' or 'ZZ'. If it yes then exit the script.
I'm not sure how to give multiple search patterns in the below line Or any modification to this existing code would help.
$myString = Select-String -Path C:\Temp\File.txt -Pattern "XX"
Edited Code:
$myFile = Get-Content -Path 'C:\file.txt | Out-String
if (Select-String $myFile -Pattern 'XX|YY' -NotMatch)
{
Do something else
}

Select-String accepts a regular expression as a pattern, so you can just use a logical OR to check for all three strings:
if ( Select-String -Path C:\Temp\File.txt -Pattern 'XX|YY|ZZ' ) {
echo "yes"
# Do something else
}

Related

Powershell update string in each file within all sub-folders

I have a set of config files stored in each subfolder within a directory. These config files only contain a single string in the format XXX_YYYYMMDD where XXX is a number e.g. 006, 007 etc, so an example string would be 006_20150101. I want the powershell script to replace the XXX number with a new one in each of these config files. I'm using the below script to achieve that and it works fine. However, the issue is that it puts a new line character (ENTER) at the end of the string which I don't want. Any way to fix this?
$sourceDir = "C:\Users\001"
$configFiles = Get-ChildItem $sourceDir *.dat -rec
foreach ($file in $configFiles)
{
(Get-Content $file.PSPath) |
Foreach-Object { $_ -replace "006", "007" } |
Set-Content $file.PSPath
}
By default set-content ends with a newline, use -NoNewline to not have this behavior:
Set-Content -path $file.PSPath -NoNewline
I dont know if u can use this but you can use regex replace to match the first 3 digits in the string:
$regex = "^\d{3}"
# matches any 3 digits("\d{3}") at the beginning("^") of a string
"124_20201030" -replace $regex, "007"

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
}

powershell Parsing for multiple keywords and sending output to a text file

I'm trying to write a powershell cmdlet to find multiple words in lines in file. Example. I need to parse "word1", "word2", "word3" are in the same line of a file. I'm doing something wrong because I tried this with no success:
(gci -File -Filter FileName | Select-String -SimpleMatch word1, word2,word3) > outputFileName.txt
where FileName = name of file, outputFileName = generated file from my search of the three words. Thank you.
Select-String doesn't have any combination operator that I can think of. If your words were always in that order, then you could do -Pattern 'word1.*word2.*word3' as your match, but if they could be in any order that would get complex very quickly. Instead, I'd look at
.. | Select-String 'word1' | Select-String 'word2' | Select-String 'Word3'
so, all the lines which match word1. Out of those, the ones which match word2 somewhere. Out of that even smaller result, the ones which also match word3.
try this:
$wordlist=#("word1", "word2", "word3")
Get-ChildItem "c:\temp\" -file | %{$currentfile=$_.FullName; Get-Content $_.FullName |
%{
$founded=$true
foreach ($item in $wordlist)
{
if (!$_.Contains($item))
{
$founded=$false
break
}
}
if ($founded)
{
$currentfile
}
}
}

Find group of words in a text file and extract the line to new text file

txt contains word "hi" "hello" "aloha" as per below
hi
hello
aloha
And I have one more file abc.txt which contains many words including the above 3 words. Now I developed a PowerShell script to search the words in abc.txt and extract the line containing the words to a new file done.txt. I use
-match command to find the word.
How to use the file ref.txt which contains the words for the finding, instead of declare the words in coding?
I would like to develop it in cmd.exe instead of PowerShell.
$source = "C:\temp\abc.txt"
$destination = "C:\temp\done.txt"
$hits = select-string -Path $source -SimpleMatch "hi","hello","aloha"
$filecontents = get-content $source
foreach($hit in $hits)
{
$filecontents[$hit.linenumber-1]| out-file -append $destination
"" |out-file -append $destination
}
This should do the batch trick:
findstr /G:ref.txt abc.txt >> done.txt
This would print all lines containing the stings in ref.txt in abc.txt to done.txt
Have I understood you question correctly?
To cover the PowerShell aspect of this question...
To get the patterns you want from file is rather easy since Select-String supports strings arrays for the -Pattern parameter. In its simplest form you could just do something like this
$patterns = Get-Content c:\temp\ref.txt | Where-Object{$_}
$hits = Select-String c:\temp\test.txt -Pattern $patterns -SimpleMatch
Your file contained a blank which I was not sure was on purpose or not. I used Where-Object{$_} to filter that out just in case. Then just pass that string array $patterns to the parameter -Pattern.
The rest of your code after that could use a little tune up. There is no need to read the source file in a second time just to output the matches again. Your output is just the matching line with a newline following.
$patterns = Get-Content c:\temp\ref.txt | Where-Object{$_}
$results = Select-String c:\temp\test.txt -Pattern $patterns -SimpleMatch
$results.Line | ForEach-Object{"$_`r`n"} | Set-Content C:\temp\out.txt
Probably not the best way to get the desired output but it should work regardless.

How to read a string from text file using powershell

I want to read a specific string from a text file and output the string into another text file.
My text file (Sample.txt) looks like below:
#{AssemblyName=Microsoft.Office.Excel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1y08bdf1111e0105c; Path=C:\Tes\app1\cc\application; ProjectPath=C:\test\application\Application.vbproj; Name=Microsoft.Office.Excel}
#{AssemblyName=System; Path=C:\Tes\app2\ser\application; ProjectPath=C:\test\application2\Application.vbproj; Name=System}
I do not want to include anything except the assemblyname.. i.e, the script should not consider version, culture etc.
The text file has lot of such assembly information.
I would like to read only the AssemblyName and write that to another text file in powersehll.
For Ex: The output.txt should contain only Microsoft.Office.Excel.
Also, I want to exclude few assembly names that start with a specific string like for eg: System. How can I do that?
I tried below, but it's not writing anything to the output.txt.
$workdir = "C:\Test"
$Txt = "$workdir\Sample.txt"
Function GetAsmName($rTxt)
{
Get-Content $Txt
$regex = '#{AssemblyName="(\w*?)"[,|;]'
$matches = (select-string -Path $Txt -Pattern $regex)
$matches | Select -Expandproperty Matches | Select #{n="Name";e={$_.Groups[1].Value}}
Set-Content -path $workdir\Output.txt -value $matches
}
Any help would be greatly appreciated.
Thanks
Try:
$workdir = "C:\Test"
$Txt = "$workdir\Sample.txt"
Function GetAsmName($rTxt)
{
$captures = gc $rTxt |
select-string -Pattern '(?<=AssemblyName=)([^;|,]*)' -allmatches |
select -expa matches | select -expa value
Set-Content -path $workdir\Output.txt -value $captures
}
GetAsmName $Txt