I am grabbing the last line of a file and outputing it in another file with the same name with a "t" prefix but an errors comes up.
$path = 'D:\files\'
$inc = #("*txt_*")
$exc = #("*csv_*")
$List = Get-ChildItem -Path $path -recurse -include $inc -exclude $exc
foreach ($item in $List) {
Get-Content $item.Fullname -Tail 1 | Out-File -Encoding Ascii $path"t-"$item
}
However, if I dont prepend the file name it works fine.
Get-Content $item.Fullname -Tail 1 | Out-File -Encoding Ascii $path"t-"
What is wrong with this?
Prepend the filename with T- and build the destination path from the folder name and the modified filename:
Get-ChildItem -Path $path -Recurse -Include $inc -Exclude $exc | ForEach-Object {
$dst = Join-Path $_.Directory.FullName ($_.Name -replace '^', 'T-')
Get-Content $_.FullName -Tail 1 | Set-Content $dst -Encoding ascii
}
Related
I need to change CSV File to TSV, and also remove line breaks and double quotes.
Here's the code:
$filePath = "C:\Users\at1704171\Documents\Infinity Scorecard PBIX\converter"
$mkdir = New-Item -ItemType Directory -Force -Path (Join-Path -Path $filePath -ChildPath 'converted')
$files = Get-ChildItem (Join-Path -Path $filePath -ChildPath "*") -Include *.csv
$sep = "`t"
$ext = '.tsv'
foreach($file in $files)
{
$filename = -Join($mkdir,"\",(Get-Item $file).BaseName,$ext)
Import-Csv $file |
ConvertTo-Csv -NoTypeInformation -Delimiter $sep |
% { $_.Replace("`r"," ").Replace("`n"," ").Replace('"',"") } |
Out-File -FilePath $filename -Encoding utf8
}
it's basically converting a CSV File to TSV, but also removing line breaks and double quotes. However I noticed that there are some "tabs" (`t) within the string so I needed to insert another line between "Import" and "Convert" to replace those "tabs" by a space
I do not understand how the syntax works so I literally copied the line below "Convert" since it executes the same function and did this, but it gives an error
$filePath = "C:\Users\at1704171\Documents\Infinity Scorecard PBIX\converter"
$mkdir = New-Item -ItemType Directory -Force -Path (Join-Path -Path $filePath -ChildPath 'converted')
$files = Get-ChildItem (Join-Path -Path $filePath -ChildPath "*") -Include *.csv
$sep = "`t"
$ext = '.tsv'
foreach($file in $files)
{
$filename = -Join($mkdir,"\",(Get-Item $file).BaseName,$ext)
Import-Csv $file |
% { $_.Replace("`t"," ") } | --this is the line I added
ConvertTo-Csv -NoTypeInformation -Delimiter $sep |
% { $_.Replace("`r"," ").Replace("`n"," ").Replace('"',"") } |
Out-File -FilePath $filename -Encoding utf8
}
anybody's help is greatly appreciated here, thank you guys
I'm using the below PowerShell script to search and replace, which works fine.
$files = Get-ChildItem 'E:\replacetest' -Include "*.txt" -Recurse | ? {Test-Path $_.FullName -PathType Leaf}
foreach($file in $files)
{
$content = Get-Content $file.FullName | Out-String
$content| Foreach-Object{$_ -replace 'hello' , 'hellonew'`
-replace 'hola' , 'hellonew' } | Out-File $file.FullName -Encoding utf8
}
The issue is the script also modifies the files which does not have the matching text in it. How we ignore the files that do not have the matching text?
You can use match to see if the content is actually changed. Since you were always writing using out-file the file would be modified.
$files = Get-ChildItem 'E:\replacetest' -Include "*.txt" -Recurse | Where-Object {Test-Path $_.FullName -PathType Leaf}
foreach( $file in $files ) {
$content = Get-Content $file.FullName | Out-String
if ( $content -match ' hello | hola ' ) {
$content -replace ' hello ' , ' hellonew ' `
-replace ' hola ' , ' hellonew ' | Out-File $file.FullName -Encoding utf8
Write-Host "Replaced text in file $($file.FullName)"
}
}
You've got an extra foreach and you need an if statement:
$files = Get-ChildItem 'E:\replacetest' -Include "*.txt" -Recurse | ? {Test-Path $_.FullName -PathType Leaf}
foreach($file in $files)
{
$content = Get-Content $file.FullName | Out-String
if ($content -match 'hello' -or $content -match 'hola') {
$content -replace 'hello' , 'hellonew'`
-replace 'hola' , 'hellonew' | Out-File $file.FullName -Encoding utf8
}
}
I have a PowerShell script that I want to run to add two lines 'IM_DISABLED' & 'IM_NO_SETUP=1' to the end of each INI file.
I want to run it against a folder H:\test which has subfolders each containing a file notes.ini.
I have the following PowerShell which works using -replace. However, I'm unable to use replace and need to just append two new lines to the end of each INI.
$places = 'h:\test'
$places | Get-ChildItem -Recurse -Include Notes.ini | ForEach-Object {
(Get-Content $_) -replace 'KitType=1', "`nKitType=1`r`nIM_DISABLED=1`r`nIM_NO_SETUP=1" |
Set-Content $_
'Processed: {0}' -f $_.FullName
}
If you have PowerShell v3 or newer you can simply use Add-Content:
$places = 'h:\test'
$lines = 'IM_DISABLED', 'IM_NO_SETUP=1'
Get-ChildItem $places -Recurse -Include Notes.ini | ForEach-Object {
Add-Content $_.FullName -Value $lines
'Processed: {0}' -f $_.FullName
}
On earlier versions you can use Out-File with the parameter -Append. Note that you also need to define the encoding if the file isn't Unicode-encoded.
$places = 'h:\test'
$lines = 'IM_DISABLED', 'IM_NO_SETUP=1'
Get-ChildItem $places -Recurse -Include Notes.ini | ForEach-Object {
Out-File $_.FullName -InputObject $lines -Append -Encoding Ascii
'Processed: {0}' -f $_.FullName
}
Another option is to make an array of Get-Content output and the lines you want to add and write that back to the file with Set-Content:
$places = 'h:\test'
Get-ChildItem $places -Recurse -Include Notes.ini | ForEach-Object {
$f = $_.FullName
(Get-Content $f), 'IM_DISABLED', 'IM_NO_SETUP=1' | Set-Content $f
'Processed: {0}' -f $f
}
I use below code to change strings in files:
Set-Location -Path C:\Users\Documents\corporate
foreach ($file in get-ChildItem *.rdl)
{
$_.Replace("Protection", "Converters") | Set-Content $file
$_.Replace("Drives", "Automation") | Set-Content $file
$_.Replace("MACHINES", "Generators") | Set-Content $file
$file.name
}
I want to add information what has changed in individual files.
For example:
file 1 Protection
file 3 Protection, MACHINES
try this way ...
Get-Content -Path "C:\Users\Documents\corporate" -Filter "*.rdl" | ForEach-Object {
$Local:CurrentFileFullName = $_.FullName
((Get-Content -Path $CurrentFileFullName ) -replace "Protection", "Converters" -replace "Drives", "Automation" -replace "MACHINES", "Generators" | Set-Content $CurrentFileFullName -Force)
}
I'm trying to do a replace in content of all files in a certain directory structure.
get-childItem temp\*.* -recurse |
get-content |
foreach-object {$_.replace($stringToFind1, $stringToPlace1)} |
set-content [original filename]
Can I get the filename from the original get-childItem to use it in the set-content?
Add processing for each file:
get-childItem *.* -recurse | % `
{
$filepath = $_.FullName;
(get-content $filepath) |
% { $_ -replace $stringToFind1, $stringToPlace1 } |
set-content $filepath -Force
}
Key points:
$filepath = $_.FullName; — get path to file
(get-content $filepath) — get content and close file
set-content $filepath -Force — save modified content
You can simply use $_, but you need a foreach-object around each file, too. While #akim's answer will work, the use of $filepath is unnecessary:
gci temp\*.* -recurse | foreach-object { (Get-Content $_) | ForEach-Object { $_ -replace $stringToFind1, $stringToPlace1 } | Set-Content $_ }