Here what I want to do is get the list of the folders that have files which has the value of ErrorCode > 0.
This is what I have done till now.
$fileNames = Get-ChildItem -Path $scriptPath -Recurse -Include *.data
$FoldersToRename = #() #initialize as array
foreach ($file in $fileNames) {
If (Get-Content $file | %{$_ -match '"ErrorCode": 0'})
{
echo "matched"
}
Now I have .data file which are being searched by this program. It contains an object with a value of "ErrorCode":value. I want to perform some operations only if that value is greater than zero.
How do I solve this?
One way to do it is like this:
Get-ChildItem -Path $scriptPath -Filter *.data |
ForEach-Object {
if((Get-Content -Path $_.FullName -Raw) -match '"ErrorCode": [1-9]\d*') {
"Matched"
}
}
Related
cd 'A:\P\E\D'
$files = Get-ChildItem . *.CSV -rec
ForEach ($file in $files) {
(Get-Content $file -Raw) | ForEach-Object {
*some simple code*
} | Set-Content $file
}
How to modify this powershell script to locate only files starting with letters A/a to O/o and ending with .csv in specified directory cd?
I thought the solution below would work, but the test file M_K_O_X.CSV stored in the cd directory was not found and modified. The solution above will find and modify the file. It's possible that I have the regex expression wrong or the problem is somewhere else? I tried also this regex -- "[A-O]..CSV"
cd 'A:\P\E\D'
$files = Get-ChildItem . -rec | Where-Object { $_.Name -like "[a-oA-O]*.*.CSV" }
ForEach ($file in $files) {
(Get-Content $file -Raw) | ForEach-Object {
*some simple code*
} | Set-Content $file
}
Looking at your wildcard pattern, seems like you have an extra *. that shouldn't be there:
'M_K_O_X.CSV' -like '[a-oA-O]*.*.CSV' # False
'M_K_O_X.CSV' -like '[a-oA-O]*.CSV' # True
In this case you could simply use the -Include Parameter which supports character ranges. Also PowerShell is case insensitive by default, [a-oA-O]*.CSV can be reduced to [a-o]*.CSV:
Get-ChildItem 'A:\P\E\D' -Recurse -Include '[a-o]*.csv' | ForEach-Object {
($_ | Get-Content -Raw) | ForEach-Object {
# *some simple code*
} | Set-Content -LiteralPath $_.FullName
}
As commented, I would use the standard wildcard -Filter to filter for all files with a .csv extension.
Then pipe to a Where-Object clause in which you can use regex -match
$files = Get-ChildItem -Path 'A:\P\E\D' -Filter '*.csv' -File -Recurse |
Where-Object { $_.Name -match '^[a-o]' }
foreach ($file in $files) {
# switch `-Raw` makes Get-Content return a single multiline string, so no need for a loop
$content = Get-Content -Path $file.FullName -Raw
# *some simple code manipulating $content*
$content | Set-Content -Path $file.FullName
}
However, if these are valid csv files, I would not recommend using a pure textual manipulation on them, instead use Import-Csv -Path $file.FullName and work on the properties on each of the objects returned.
In a directory, there are files with the following filenames:
ExampleFile.mp3
ExampleFile_pn.mp3
ExampleFile2.mp3
ExampleFile2_pn.mp3
ExampleFile3.mp3
I want to iterate through the directory, and IF there is a filename that contains the string '_pn.mp3', I want to test if there is a similarly named file without the '_pn.mp3' in the same directory. If that file exists, I want to remove it.
In the above example, I'd want to remove:
ExampleFile.mp3
ExampleFile2.mp3
and I'd want to keep ExampleFile3.mp3
Here's what I have so far:
$pattern = "_pn.mp3"
$files = Get-ChildItem -Path '$path' | Where-Object {! $_.PSIsContainer}
Foreach ($file in $files) {
If($file.Name -match $pattern){
# filename with _pn.mp3 exists
Write-Host $file.Name
# search in the current directory for the same filename without _pn
<# If(Test-Path $currentdir $filename without _pn.mp3) {
Remove-Item -Force}
#>
}
enter code here
You could use Group-Object to group all files by their BaseName (with the pattern removed), and then loop over the groups where there are more than one file. The result of grouping the files and filtering by count would look like this:
$files | Group-Object { $_.BaseName.Replace($pattern,'') } |
Where-Object Count -GT 1
Count Name Group
----- ---- -----
2 ExampleFile {ExampleFile.mp3, ExampleFile_pn.mp3}
2 ExampleFile2 {ExampleFile2.mp3, ExampleFile2_pn.mp3}
Then if we loop over these groups we can search for the files that do not end with the $pattern:
#'
ExampleFile.mp3
ExampleFile_pn.mp3
ExampleFile2.mp3
ExampleFile2_pn.mp3
ExampleFile3.mp3
'# -split '\r?\n' -as [System.IO.FileInfo[]] | Set-Variable files
$pattern = "_pn"
$files | Group-Object { $_.BaseName.Replace($pattern,'') } |
Where-Object Count -GT 1 | ForEach-Object {
$_.Group.Where({-not $_.BaseName.Endswith($pattern)})
}
This is how your code would look like, remove the -WhatIf switch if you consider the code is doing what you wanted.
$pattern = "_pn.mp3"
$files = Get-ChildItem -Path -Filter *.mp3 -File
$files | Group-Object { $_.BaseName.Replace($pattern,'') } |
Where-Object Count -GT 1 | ForEach-Object {
$toRemove = $_.Group.Where({-not $_.BaseName.Endswith($pattern)})
Remove-Item $toRemove -WhatIf
}
I think you can get by here by adding file names into a hash map as you go. If you encounter a file with the ending you are interested in, check if a similar file name was added. If so, remove both the file and the similar match.
$ending = "_pn.mp3"
$files = Get-ChildItem -Path $path -File | Where-Object { ! $_.PSIsContainer }
$hash = #{}
Foreach ($file in $files) {
# Check if file has an ending we are interested in
If ($file.Name.EndsWith($ending)) {
$similar = $file.Name.Split($ending)[0] + ".mp3"
# Check if we have seen the similar file in the hashmap
If ($hash.Contains($similar)) {
Write-Host $file.Name
Write-Host $similar
Remove-Item -Force $file
Remove-Item -Force $hash[$similar]
# Remove similar from hashmap as it is removed and no longer of interest
$hash.Remove($similar)
}
}
else {
# Add entry for file name and reference to the file
$hash.Add($file.Name, $file)
}
}
Just get a list of the files with the _pn then process against the rest.
$pattern = "*_pn.mp3"
$files = Get-ChildItem -Path "$path" -File -filter "$pattern"
Foreach ($file in $files) {
$TestFN = $file.name -replace("_pn","")
If (Test-Path -Path $(Join-Path -Path $Path -ChildPath $TestFN)) {
$file | Remove-Item -force
}
} #End Foreach
I try to read big data log file, in folder C: \ log \ 1 \ i put 2 txt files, i need open-> read all file .txt and find with filter some text like whis: [text]
# Filename: script.ps1
$Files = Get-ChildItem "C:\log\1\" -Filter "*.txt"
foreach ($File in $Files)
{
$StringMatch = $null
$StringMatch = select-string $File -pattern "[Error]"
if ($StringMatch) {out-file -filepath C:\log\outputlog.txt -inputobject $StringMatch}
}
# end of script
not work
Would doing something like a select-string work?
Select-String C:\Scripts\*.txt -pattern "SEARCH STRING HERE" | Format-List
Or if there are multiple files you are wanting to parse maybe use the same select-string but within a loop and output the results.
$Files = Get-ChildItem "C:\log\1\" -Filter "*.txt"
foreach ($File in $Files)
{
$StringMatch = $null
$StringMatch = select-string $File -pattern "SEARCH STRING HERE"
if ($StringMatch) {out-file -filepath c:\outputlog.txt -inputobject $StringMatch}
}
This will print out the file name along with the line number in the file. I hope this is what you are looking for.
Remove-Item -Path C:\log\outlog.txt
$Files = Get-ChildItem "C:\log\1\" -Filter "*.txt"
foreach ($File in $Files)
{
$lineNumber = 0
$content = Get-Content -Path "C:\log\1\$File"
foreach($line in $content)
{
if($line.Contains('[Error]'))
{
Add-Content -Path C:\log\outlog.txt -Value "$File -> $lineNumber"
}
$lineNumber++
}
}
Code below works
It selects strings in txt files in your folder based on -SimpleMatch and then appends it to new.txt file.
Though i do not know how to put two simple matches in one line. Maybe someone does and can post it here
Select-String -Path C:\log\1\*.txt -SimpleMatch "[Error]" -ca | select -exp line | out-file C:\log\1\new.txt -Append
Select-String -Path C:\log\1\*.txt -SimpleMatch "[File]" -ca | select -exp line | out-file C:\log\1\new.txt -Append
Regards
-----edit-----
If you want to you may not append it anywhere just display - simply dont pipe it to out-file
use index then check it :
New-Item C:\log\outputlog.txt
$Files = Get-ChildItem "C:\log\1\" -Include "*.txt"
foreach ($File in $Files)
{
$StringMatch = $null
$StringMatch = Get-Content $File
if($StringMatch.IndexOf("[Error]") -ne -1)
{
Add-Content -Path C:\log\outputlog.txt -Value ($StringMatch+"
-------------------------------------------------------------
")
}
}
# end of script
I have made this loop to iterate some files that I want to replace content in.
The content that I want to replace is a string which can look something like this: foo="1".
What I need your help with is how to find the string (regexp I guess) and update the file with a new value, like 2 for example.
$files = Get-ChildItem -Recurse -Filter "*.config"
foreach ($file in $files)
{
Get-Content $file.FullName
}
Read-Host
From the sample code in the question, I assume you're attempting to update a .NET configuration file (ie. a web.config or app.config file).
Given that these files are really XML files, you may want to treat them as such:
$files = Get-ChildItem -Recurse -Filter "*.config"
foreach ($file in $files)
{
# Create an XmlDocument object from the file
$configXml = [xml](Get-Content $file.FullName)
# Find all the nodes in the document
$xmlNodes = $configXml.SelectNodes('//*')
# Keep track of whether we make changes or not
$changeCount = 0
foreach($node in $xmlNodes)
{
# Check if node has a "foo" attribute
if($node.HasAttribute('foo'))
{
# Set 2 as the value
$node.SetAttribute('foo',2)
$changeCount++
}
}
if($changeCount)
{
# At least one node was updated, save to file
$configXml.Save($file.FullName)
}
}
You can try regex. Ex.
$files = Get-ChildItem -Recurse -Filter "*.config"
$find = 'foo=".*?"'
$replace = 'foo="4"'
foreach ($file in $files)
{
Get-Content $file.FullName |
Foreach-Object { $_ -replace $find, $replace } |
Set-Content $file.Fullname
}
}
Read-Host
Or to only modify files that match:
$files = Get-ChildItem -Recurse -Filter "*.config"
$find = 'foo=".*?"'
$replace = 'foo="4"'
foreach ($file in $files)
{
$content = Get-Content $file.FullName
if(Select-String -InputObject $content -Pattern $find -Quiet) {
$content |
Foreach-Object { $_ -replace $find, $replace } |
Set-Content $file.Fullname
}
}
Read-Host
This should answer your question
$files = Get-ChildItem -Recurse -Filter "*.config"
foreach ($file in $files)
{
$fileContent = Get-Content $file.FullName
$newContent = $fileContent -replace 'foo="1"', 'foo="2"'
Set-Content $file.FullName $newContent
}
Further reading here: Use PowerShell to Replace Text in Strings
I am using following coe to replace the string
$folders=Get-ChildItem -Path "C:\temp\Database Scripts"
foreach($folder in $folders)
{
Write-Host $folder
$spath=[string]::Concat("C:\temp\Database Scripts\", $folder)
$subfolders=Get-ChildItem $spath
foreach($subfolder in $subfolders )
{
if($subfolder -match "Running Scripts")
{
$subfolerpath=[string]::Concat($spath,"\",$subfolder,"\*")
$files =get-childitem -Path $subfolerpath -include "AVEVAScripts*"
if($files -ne $null)
{
foreach( $file in $files)
{
Write-Host $file;
(Get-Content $file) | ForEach-Object {$_ -replace "DATABASE_USER","fhghjgj" `
-replace "DATABASE_PASSWORD", "DFGHFHJGJH" } |Set-Content $file
}
}
}
}
}
But ending up with following error.
Set-Content : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
Please help :)
Remove the $x in the end of Set-Content. $x is never declared.
Also, you could simplify it a lot. Ex:
Get-ChildItem -Filter "Running Scripts" -Path "C:\temp\Database Scripts" -Recurse | ForEach-Object {
Get-ChildItem -Path $_.FullName -Filter "AVEVAScripts*" -Recurse | ForEach-Object {
(Get-Content $_.FullName) | ForEach-Object {
$_ -replace "DATABASE_USER","fhghjgj" -replace "DATABASE_PASSWORD", "DFGHFHJGJH"
} | Set-Content $_.FullName
}
}
Or find all files that includes "AVEVAScripts" in it's name, then check if their full path includes "Running Scripts"
Get-ChildItem -Filter "AVEVAScripts*" -Path "C:\temp\Database Scripts" -Recurse |
Where-Object { $_.FullName -like "*Running Scripts*" } |
ForEach-Object {
(Get-Content $_.FullName) | ForEach-Object {
$_ -replace "DATABASE_USER","fhghjgj" -replace "DATABASE_PASSWORD", "DFGHFHJGJH"
} | Set-Content $_.FullName
}