I am trying to search for the string, replace it and then output the file. I believe I have the syntax correct but for whatever reason it is not working. Can anyone spot why or is this even possible?
$DesiredTimeoutTime = '<Settings maxTimeout="04:00:00" />'
$path = "C:\Windows\Settings.log"
$currentTimeoutTime = Select-String -Path $path -SimpleMatch '<Settings maxTimeout=' -CaseSensitive
Write-Host $currentTimeoutTime
(Get-Content $path).Replace((Select-String -Path $path -SimpleMatch '<Settings maxTimeout="'), $DesiredTimeoutTime) | out-file $path
It finds the line and path but it is not saving the changes.
Thank you
You're overcomplicating things. Simply use the -replace operator with an appropriate regular expression:
$DesiredTimeoutTime = '04:00:00'
(Get-Content $path) -replace '(?<=<Settings maxTimeout=")[^"]*', $DesiredTimeoutTime |
Set-Content $path
(?<=...) is a positive lookbehind assertion, which basically means "look for something that is preceded by this pattern".
Related
How can i read every csv file the specific folder? When script below is executed, it only will remove quote character of one csv file.
$file="C:\test\IV-1-2020-04-02.csv"
(GC $file) | % {$_ -replace '"', ''} > $file
Get-ChildItem -Path C:\test\ -Filter '*.csv'
The output only will remove the quote character of "IV-1-2020-04-02.csv". What if i have different filename ?
You can iterate each .csv file from Get-ChildItem and replace the quotes " with '' using Set-Content.
$files = Get-ChildItem -Path "YOUR_FOLDER_PATH" -Filter *.csv
foreach ($file in $files)
{
Set-Content -Path $file.FullName -Value ((Get-Content -Path $file.FullName -Raw) -replace '"', '')
}
Make sure to pass your folder path to -Path, which tells Get-ChildItem to fetch every file from this folder
Its also faster to use the -Raw switch for Get-Content, since it reads the file into one string and preserves newlines. If you omit this switch, Get-Content will by default split the lines by newlines into an array of strings
If you want to read files in deeper sub directories as well, then add the -Recurse switch to Get-ChildItem:
$files = Get-ChildItem -Path "YOUR_FOLDER_PATH" -Filter *.csv -Recurse
Addtionally, you could also use Foreach-Object here:
Get-ChildItem -Path "YOUR_FOLDER_PATH" -Filter *.csv -Recurse | ForEach-Object {
Set-Content -Path $_.FullName -Value ((Get-Content -Path $_.FullName -Raw) -replace '"', '')
}
Furthermore, you could replace Foreach-Object with its alias %. However, If your using VSCode and have PSScriptAnalyzer enabled, you may get this warning:
'%' is an alias of 'ForEach-Object'. Alias can introduce possible problems and make scripts hard to maintain. Please consider changing alias to its full content.
Which warns against using aliases for maintainability. Its much safer and more portable to use the full version. I only use the aliases for quick command line usage, but when writing scripts I use the full versions.
Note: The above solutions could potentially corrupt the CSV if some lines need quoting. This solution simply goes through the whole file and replaces every quote with ''. PowerShell 7 offers a -UseQuotes AsNeeded option for Export-Csv, so you may look into that instead.
Don't just replace all the " unless you are very certain that it's a good idea; otherwise replace the " when it shouldn't matter because the field doesn't contain text with a comma, double quote, nor line break. (see RFC-4180 section 2, #6 and #7)
As with any script that overwrites its working files, make sure you have backups of those files should you want an undo option later on...
$tog = $true
$sep = ':_:'
$header=#()
filter asString{
$obj=$_
if($tog){
$header=(gm -InputObject $obj -Type NoteProperty).Name
$hc = $header.Count-1
$tog=$false
$str = $header -join $sep
$str = "$sep$str" -replace '"','""'
$str = $str -replace "$sep(((?!$sep)[\s\S])*(,|""|\n)((?!$sep)[\s\S])*)",($sep+'"$1"')
($str -replace $sep,',').Substring(1)
}
$str = (0..$hc | %{$obj.($header[$_])}) -join $sep
$str = "$sep$str" -replace '"','""'
$str = $str -replace "$sep(((?!$sep)[\s\S])*(,|""|\n)((?!$sep)[\s\S])*)",($sep+'"$1"')
($str -replace $sep,',').Substring(1)
}
ls *.csv | %{$tog=$true;import-csv $_ | asString | sc "$_.new";$_.FullName} | %{if(test-path "$_.new"){mv "$_.new" $_ -force}}
Note: the CSV files are expected to contain their own headers. You could work around that if you needed to with the use of the -Header option of Import-Csv
I need to check the contents line by line by selecting the string of the line.
I have declared each line matching string to a variable.Is it possible to use switch cases for looking into the variables
I have used if condition to check the each line with the help of variables .
I wanted to know whether we could use switch cases?
Consider file.txt having following contents :
$q = Get-Content -Path .\file.txt |Select-String 'Hello' -SimpleMatch
$w = Get-Content -Path .\file.txt |Select-String 'new' -SimpleMatch
$e = Get-Content -Path .\file.txt |Select-String 'World' -SimpleMatch
$r = Get-Content -Path .\file.txt |Select-String 'Hi' -SimpleMatch
$t = Get-Content -Path .\file.txt |Select-String 'greet' -SimpleMatch
So can we check the variables using the switch options. Is it possible to output the variables which are not present. How can we achieve the same if the file contents are large?
Can we use switch options and output the desired result?
If you just want to know which of the 5 words are not in any of the lines in the file, you can do this
$Pattern = 'Hello|new|World|Hi|greet'
$Test = (Get-Content -Path .\file.txt | Select-String -Pattern $Pattern -AllMatches).foreach{$_.matches.Value}
$($pattern -split '\|').where{$Test -notcontains $_}
But is that your goal?
I am trying to filter files having any of the words January or February in their content.
$files = Get-ChildItem "C:\Users\Desktop\NewFolder\" -Recurse -Filter "*Support*"
$count = 0
$p = 'january', 'February'
foreach ($file in $files){
if((Get-Content $file.FullName) | Select-String -Pattern '^%january%'){
Write-Host "File found"
#write-host $file.FullName
$count++
}
else {
Write-Host "File NOt found"
}
}
Write-Host $count
Currently I am just getting "File NOt found" even though the file exists
Your issue might simply be your regex string although improvement could still be made as a whole. The percent sign is not a wildcard character in regex also are you expecting the month to appear at the start of a line? That is what the anchor ^ represents.
So likely your files do not have the string %January% at the start of any line. Like I mentioned earlier I don't think that is what you wanted.
So lets find all the files you want and filter those files based on the presence of either of the works in $p (like in your example above)
$p ='january','February'
$regexPattern = ($p | ForEach-Object{[regex]::Escape($_)}) -join "|"
$files = Get-ChildItem -Path "c:\temp\" -filter "*.txt"
$files | Where-Object{Select-String -Path $_.Fullname -Pattern $regexPattern}
That will spit out any file objects that have the work January or February in them anywhere in the line.
$regexPattern would end up being a pipeline delimited string of the words in $p. [regex]::Escape() is a good way to avoid special regex characters in your strings especially if you are just using examples.
You would of course need to change the -Path and -Filter accordingly as well as including -Recurse if the situation calls for it.
I think
Select-String -Path "C:\Users\Desktop\NewFolder\*Support*" -Pattern January,february
or (if you need to recurse the path)
Get-ChildItem -Path "C:\Users\Desktop\NewFolder" -Include *Support* -Recurse | Select-String -Pattern January,february
should get you what you want?
(Select-String also has a -CaseSensitive switch if you should need that)
I want to select a string "install status" from a log file by using powershell. For that i have used the command $status=selectstring -path $path -pattern "installstatus" .This cmd given an output installstatus=success with path and logtime and line details at beginning and i removed the path by adding |{$_.Line} after pattern in $status.And i want to remove line details also.how can i remove those details.I only want the pattern to be displayed .Any help will be apperciated.Thanks in advancd.
here the scenarios
$path="C:\Users\sumith\filename.log";
$status=select-string -path $path -pattern "Install_status"
output is
C:\Users\sumith\filename.log:79:ISS_LOG [14:45:41]: INSTALL_STATUS:SUCCESS
if i give
$status=select-string -path $path -pattern "Install_status" | {$_.Line}
the output will be
ISS_LOG [14:45:41]: INSTALL_STATUS:SUCCESS
now i want to remove ISS_LOG [14:45:41]: from output
IMO you are better of using a regular expression for this:
$File = ".\filename.log"
$Content = (Get-Content $File -raw)
$Pattern = [regex]'INSTALL_STATUS:\s*(\w+)'
"Using -Match operator"
if ($Content -Match $Pattern){
$Matches[0]
$Matches[1]
} Else {
"couldn#T find a match"
}
"Using [RegEx] .Matches method"
$Matches = $Pattern.Matches($Content)
$Matches.Captures[0].Value
$Matches.Captures.Groups[1].Value
Your question and comment differ in the file content,
a space following the colon INSTALL_STATUS: SUCCESS.
Sample output :
Using -Match operator
INSTALL_STATUS: SUCCESS
SUCCESS
Using [RegEx] .Matches method
INSTALL_STATUS: SUCCESS
SUCCESS
Try this,
$status=select-string -path $path -pattern "Install_status" | {$_.Line}
$status.Substring(19)OR
$status=select-string -path $path -pattern "Install_status" | {$_.Line}
$status.Substring($status.IndexOf('IN'))
or
$status=select-string -path $path -pattern "Install_status" | {$_.Line}
$status.Substring($status.IndexOf(']:')+2)
Or using Regex (Credits to LotPengs)
$Content=Get-Content D:\creditdetails.txt
$Pattern = [regex]'INSTALL_STATUS:\s*(\w+)'
if( $Pattern.Matches($Content) -ne $null){
$Matches=$Pattern.Matches($Content)
$Matches.Captures[0].Value
}else{
$Matches='No Match Found'
}
Assuming the log structure remains the same.
For console output (modified Chetan Kulkarni answer)
(Select-String -Path .\file.txt -Pattern 'abcde').line
I have a text (.txt) file with following content:
Car1
Car2
Car3
Car4
Car5
For changing Car1 for random text I used this script:
Get-ChildItem "C:\Users\boris.magdic\Desktop\q" -Filter *.TXT |
Foreach-Object{
$content = Get-Content $_.FullName
$content | ForEach-Object { $_ -replace "Car1", "random_text" } | Set-Content $_.FullName
}
This is working ok, but now I want to add one text line under Car2 in my text file.
How can I do that?
Just chain another -replace and use a new line!
Get-ChildItem "C:\Users\boris.magdic\Desktop\q" -Filter *.TXT |
Foreach-Object{
$file = $_.FullName
$content = Get-Content $file
$content | ForEach-Object { $_ -replace "Car1", "random_text" -replace "(Car2)","`$1`r`nOtherText" } | Set-Content $file
}
First thing is that | Set-Content $_.FullName would not work since the file object does not exist in that pipe. So one simple this to do it save the variable for use later in the pipe. You can also use the ForEach($file in (Get-ChildItem....)) construct.
The specific change to get what you want is the second -replace. We place what you want to match in brackets to that we can reference it in the replacement string with $1. We use a backtick to ensure PowerShell does not treat it as a variable.
We can remove some redundancy as well since -replace will work against the strings of file as a whole
Get-ChildItem "c:\temp" -Filter *.TXT |
Foreach-Object{
$file = $_.FullName
(Get-Content $file) -replace "Car1", "random_text" -replace "(Car2)","`$1`r`nOtherText" | Set-Content $file
}
While this does work with your sample text I want to point out that more complicated strings might require more finesse to ensure you make the correct changed and that the replacements we are using are regex based and do not need to be for this specific example.
.Replace()
So if you were just doing simple replacements then we can update your original logic.
Foreach-Object{
$file = $_.FullName
$content = Get-Content $_.FullName
$content | ForEach-Object { $_.replace("Car1", "random_text").replace("Car2","Car2`r`nOtherText")} | Set-Content $file
}
So that is just simple text replacement chained using the string method .Replace()