I have an issue that I cannot resolve no matter which way I am wrapping it up. I am including my latest code which is not giving me the desired outcome and the code for a solution that does work but for only one file at a time. I cannot work out how to loop through each of the files automatically however.
In a nutshell, I have a directory with many CSV files some of the entries within the CSVfile have a negative value (-) I need to remove this minus sign in all instances.
Now what works is if I use the following (on a single file)
$content = Get-Content "L:\Controls\BCR\0001cash.csv" | ForEach {$_ -replace $variable, ""} | Set-Content "L:\controls\bcr\0001temp.csv"
What I am trying to do is iterate through the many thousand of these objects automatically and not have to refer to them individually.
I started with:
$Directory = "L:\Controls\BCR\"
$variable = "-"
$suffix = ".tmp"
To define the directory, minus symbol that I want to remove and the suffix of the file I want to change to...
$Files = Get-ChildItem $Directory | Where-Object {$_.Extension -like "*csv*"} | Where-Object {$_.Name -like "*cash*"}
Is obtaining each of the files that I wish to work with
And I am then working with
ForEach ($File in $Files) { Get-Content $Files | ForEach {$_ -replace $variable, ""} | Set-Content {$_.Basename + $Variable}
The results however are nothing...
At a loss? Anyone???
$Directory = "L:\Controls\BCR\"
$variable = "-"
$suffix = ".tmp"
$Files = Get-ChildItem $Directory | Where-Object {$_.Extension -like "*csv*"} | Where-Object {$_.Name -like "*cash*"}
$process = ForEach ($File in $Files) { Get-Content $Files | ForEach {$_ -replace $variable, ""} | Set-Content {$_.BaseName + $suffix}
}
You are using the wrong variable in the Get-Content cmdlet ($Files instead of $File). Also You can simplify your script:
$Directory = "L:\Controls\BCR\"
$variable = "-"
$suffix = ".tmp"
Get-ChildItem $Directory -Filter '*cash*csv' |
ForEach-Object {
(Get-Content $_ -Raw) -replace $variable |
Set-Content {$_.BaseName + $suffix}
}
Related
How to select strings from file via one lines?
For example my file contains strings
string1
string2
string3
string4
i want get
string2
string4
I try it this way
Get-Content -Path "E:\myfile.txt" | Select-String
but i don't know how make this from Select-String method
If you literally want to select these two lines, then I guess this is the shortest way to do that:
(Get-Content -Path "E:\myfile.txt")[1,3]
or
Get-Content -Path "E:\myfile.txt" | Select-Object -Index 1,3
However, if you mean you want to select only the even numbered lines from the file, you could do this:
# return only the even lines (for odd lines, do for ($i = 0; ...)
$text = Get-Content -Path "E:\myfile.txt"; for ($i = 1; $i -lt #($text).Count; $i+=2) { $text[$i] }
Or by using Select-String
# return only the even lines (for odd lines, remove the ! exclamation mark
(Select-String -Path "E:\myfile.txt" -Pattern '.*' | Where-Object {!($_.LineNumber % 2)}).Line
Get-Content -Path "~\Desktop\strings.txt" | Select-String -Pattern "string2|string4"
You can use the Where-Object cmdlet to filter a stream of objects (strings in this case):
Get-Content -Path "E:\myfile.txt" | Where-Object {$_ -match '[24]$'}
# or
Get-Content -Path "E:\myfile.txt" | Where-Object {$_ -like '*[24]'}
# or
Get-Content -Path "E:\myfile.txt" | Where-Object {$_.EndsWith('2') -or $_.EndsWith('4')'}
If you want only even-numbered lines from the file:
Get-Content -Path "E:\myfile.txt" | Where-Object {$_.ReadCount % 2 -eq 0}
im quiet new to powerhsell and I have the following goal:
My code is supposed to loop through selected subfolders and compare those. The names of the subfolders are identical in both parent folders, however the path before those selected folders are different: C:\temp\parentF1\BackUp* and C:\temp\parentF2\BackUp*
The problem that I have is that even tho I think my $vars that I use for the comparison should have a value, are NULL and I cant think of why!
$path = "subfolder1","subfolder2","subfolder3"
$excludeF1 = #(C:\temp\parentF1\BackUp\*\subfolder5)
$excludeF2 = #(C:\temp\parentF2\BackUp\*\subfolder5)
$x = 0
while($x -lt $path.Count){
$F1 = Get-ChildItem -Recurse -Path "C:\temp\parentF1\BackUp\$path[$x]" |
Where-Object {$_.FullName -notlike $excludeF1}
$F2 = Get-ChildItem -Recurse -Path "C:\temp\parentF2\BackUp\$path[$x]" |
Where-Object {$_.FullName -notlike $excludeF2}
Compare-Object -ref $F1 -dif $F2 |
Select-Object #{Label="$path[$x]";e={$_.InputObject}},`
#{n="Fundort";e={if($_.SideIndicator -like "=>") {write-output "BackUp F1"}`
elseif($_.SideIndicator -like "<="){Write-Output "BackUp F2"}}} | Out-File dif.txt
$x++
}
start .\dif.txt
also the out-file cmdlet doesnt work but that`s a dif topic
Thanks for any help in advance
This does not work as you expect:
Get-ChildItem ... -Path "C:\temp\parentF1\BackUp\$path[$x]"
When using -Path, PowerShell interprets [...] as part of its own wildcard syntax. Use -LiteralPath to prevent that.
Anything more complex than simple variable name ($var) must be enclosed in a subexpression $(...).
Similar issue:
Select-Object #{Label="$path[$x]"; ...
This can be solved by simply removing the quotation, as $path already contains strings.
Solution:
$F1 = Get-ChildItem -Recurse -LiteralPath "C:\temp\parentF1\BackUp\$($path[$x])" | ...
$F2 = Get-ChildItem -Recurse -LiteralPath "C:\temp\parentF2\BackUp\$($path[$x])" | ...
Compare-Object ... |
Select-Object #{Label=$path[$x]; ...
The above fixes your current code, but your code could be simplified like this to avoid the subexpressions:
foreach($currentPath in $path) {
$F1 = Get-ChildItem -Recurse -Path "C:\temp\parentF1\BackUp\$currentPath" |
Where-Object FullName -notlike $excludeF1
$F2 = Get-ChildItem -Recurse -Path "C:\temp\parentF2\BackUp\$currentPath" |
Where-Object FullName -notlike $excludeF2
Compare-Object -ref $F1 -dif $F2 |
Select-Object #{Label=$currentPath;e={$_.InputObject}},`
#{n="Fundort";e={if($_.SideIndicator -like "=>") {write-output "BackUp F1"}`
elseif($_.SideIndicator -like "<="){Write-Output "BackUp F2"}}} | Out-File dif.txt
}
I have many folder
ex: folder1,folder2,folder3... about folder100
In those folder have many files
ex: 1.html,2.html,3.html,4.html...about 20.html
I want to replace some text in those all html file in all folder
but not all text i want to replace is same.
ex:(for 1.html, i want to replace ./1_files/style.css to style.css) and (for 2.html, i want to replace ./2_files/style.css to style.css)....
So i try something like this and it work well
Get-ChildItem "*\1.html" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './1_files/style.css', 'style.css' | Set-Content $_
}
Get-ChildItem "*\2.html" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './2_files/style.css', 'style.css' | Set-Content $_
}
Get-ChildItem "*\3.html" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './3_files/style.css', 'style.css' | Set-Content $_
}
Get-ChildItem "*\4.html" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './4_files/style.css', 'style.css' | Set-Content $_
}
but i have to write many of those code "\4.html" "\5.html" "*\6.html" ...
i try this but it do not work
Do {
$val++
Write-Host $val
$Fn = "$val.html"
Get-ChildItem "*\$Fn" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './$val_files/style.css', 'style.css' |
Set-Content $_
}
} while($val -ne 100)
Please show me correct way to do..loop replace
thanks you
Assuming all your subfolders can be found inside one source folder path, you can do below to do the replacement in all those files:
# the path where all subfolders and html files can be found
$sourcePath = 'X:\Wherever\Your\Subfolders\Are\That\Contain\The\Html\Files'
Get-ChildItem -Path $sourcePath -Filter '*.html' -Recurse -File |
# filter on html files that have a numeric basename
Where-Object {$_.BaseName -match '(\d+)'} | ForEach-Object {
# construct the string to repace and escape the regex special characters
$replace = [regex]::Escape(('./{0}_files/style.css' -f $matches[1]))
# get the content as one single multiline string so -replace works faster
(Get-Content -Path $_.FullName -Raw) -replace $replace, 'style.css' |
Set-Content -Path $_.FullName
}
I have some powershell code that is meant to take specific characters out of file names recursively. This works great, unless taking the characters out causes 2 files to match names in the same folder.
I found the Powershell here PowerShell script to remove characters from files and folders but it doesn't solve the issue I am having.
$characters = "$#"
$regex = "[$([regex]::Escape($characters))]"
$filesandfolders = Get-ChildItem -recurse "D:\projects\filenameCleaner\TEST" | Where-Object {$_.name -match $regex}
$filesandfolders | Where-Object {!$_.PsIscontainer} | foreach {
$New=$_.name -Replace $regex
Rename-Item -path $_.Fullname -newname $New -passthru
}
$filesandfolders | Where-Object {$_.PsIscontainer} | foreach {
$New=$_.name -Replace $regex
Rename-Item -path $_.Fullname -newname $New -passthru
}
I'm not very versed in Powershell yet and would love some help with this. I just want the script that, if it finds a duplicate, it should just add a (1) or (2) etc at the end, depending on how many there are.
Please don't just give me an answer, explain it so that I can learn what is happening
I think the way to tackle this is to create a new PSOBJECT which contains your source and target paths. You can then use the Group-object to group on the target path which will give you a count which you can then use to determine which files will need a number suffix.
Something like this:
Get-ChildItem -recurse "D:\projects\filenameCleaner\TEST" | ? {!$_.PsIscontainer} | % {
New-Object psobject -Property #{
source = $_.FullName
target = ($_.FullName -replace [regex]::Escape($_.Name)) + ($_.Name -replace '[\$#]+', '')
}
} | Group-Object target | % {
$g = $_.Group
0..($g.Count - 1) | % {
New-Object psobject -Property #{
source = $g[$_].source
target = $g[$_].target -replace '\.', #('.', "($($_)).")[$_ -gt 0]
}
}
} | % {Rename-Item -Path $_.source -NewName $_.Target}
The nice thing about doing it this way is that it can two, three or more duplcates
I have only done the code for files so you would need another version for folders.
I was able to do this by adding an if-statement that checks the new path
$characters = "$#}"
$regex = "[$([regex]::Escape($characters))]"
$path = "D:\projects\filenameCleaner\TEST"
$filesandfolders = Get-ChildItem -recurse $path | Where-Object {$_.name -match $regex}
$filesandfolders | Where-Object {!$_.PsIscontainer} | foreach {
$New=$_.name -Replace $regex
$newPath = $path+"\"+$New
$loop = 0
while (Test-Path $newPath) {
$loop = $loop + 1
$basename = $_.basename -Replace $regex
$New = $basename + " ("+$loop+")"+$_.extension
$newPath = $path+"\"+$New
}
"Rename `""+$_.name+"`" to `""+$New+"`""
Rename-Item -path $_.Fullname -newname $New -passthru
}
$filesandfolders | Where-Object {$_.PsIscontainer} | foreach {
$New=$_.name -Replace $regex
$newPath = $path+"\"+$New
$loop = 0
while (Test-Path $newPath) {
$loop = $loop + 1
$basename = $_.basename -Replace $regex
$New = $basename + " ("+$loop+")"+$_.extension
$newPath = $path+"\"+$New
}
"Rename `""+$_.name+"`" to `""+$New+"`""
Rename-Item -path $_.Fullname -newname $New -passthru
}
-- Another update that handles the extensions separately when adding the number to the string for duplicates. I was having issues that the number would go onto the file name after the extension which is obviously a no-go
How can I change the following code to look at all the .log files in the directory and not just the one file?
I need to loop through all the files and delete all lines that do not contain "step4" or "step9". Currently this will create a new file, but I'm not sure how to use the for each loop here (newbie).
The actual files are named like this: 2013 09 03 00_01_29.log. I'd like the output files to either overwrite them, or to have the SAME name, appended with "out".
$In = "C:\Users\gerhardl\Documents\My Received Files\Test_In.log"
$Out = "C:\Users\gerhardl\Documents\My Received Files\Test_Out.log"
$Files = "C:\Users\gerhardl\Documents\My Received Files\"
Get-Content $In | Where-Object {$_ -match 'step4' -or $_ -match 'step9'} | `
Set-Content $Out
Give this a try:
Get-ChildItem "C:\Users\gerhardl\Documents\My Received Files" -Filter *.log |
Foreach-Object {
$content = Get-Content $_.FullName
#filter and save content to the original file
$content | Where-Object {$_ -match 'step[49]'} | Set-Content $_.FullName
#filter and save content to a new file
$content | Where-Object {$_ -match 'step[49]'} | Set-Content ($_.BaseName + '_out.log')
}
To get the content of a directory you can use
$files = Get-ChildItem "C:\Users\gerhardl\Documents\My Received Files\"
Then you can loop over this variable as well:
for ($i=0; $i -lt $files.Count; $i++) {
$outfile = $files[$i].FullName + "out"
Get-Content $files[$i].FullName | Where-Object { ($_ -match 'step4' -or $_ -match 'step9') } | Set-Content $outfile
}
An even easier way to put this is the foreach loop (thanks to #Soapy and #MarkSchultheiss):
foreach ($f in $files){
$outfile = $f.FullName + "out"
Get-Content $f.FullName | Where-Object { ($_ -match 'step4' -or $_ -match 'step9') } | Set-Content $outfile
}
If you need to loop inside a directory recursively for a particular kind of file, use the below command, which filters all the files of doc file type
$fileNames = Get-ChildItem -Path $scriptPath -Recurse -Include *.doc
If you need to do the filteration on multiple types, use the below command.
$fileNames = Get-ChildItem -Path $scriptPath -Recurse -Include *.doc,*.pdf
Now $fileNames variable act as an array from which you can loop and apply your business logic.
Other answers are great, I just want to add... a different approach usable in PowerShell:
Install GNUWin32 utils and use grep to view the lines / redirect the output to file http://gnuwin32.sourceforge.net/
This overwrites the new file every time:
grep "step[49]" logIn.log > logOut.log
This appends the log output, in case you overwrite the logIn file and want to keep the data:
grep "step[49]" logIn.log >> logOut.log
Note: to be able to use GNUWin32 utils globally you have to add the bin folder to your system path.