This question already has answers here:
Replacing only the first occurrence of a word in a string
(2 answers)
Closed 2 years ago.
I would like to replace the n'th character in a file with another - so for example you have
Type:1BANKFROMBANK1TO2 -> Type:2BANKFROMBANK1TO2
Type:2BANKFROMBANK1TO2 -> Type:2BANKFROMBANK1TO2
Type:3BANKFROMBANK1TO2 -> Type:2BANKFROMBANK1TO2
Type:4BANKFROMBANK1TO2 -> Type:2BANKFROMBANK1TO2
I do not know what the value will be, but I know at what place it will be - so for this example the 6th character.
When attempting to do it like this:
$Replace = Get-ChildItem "C:\temp\" -Filter "xfil*"
Foreach ($file in $Replace) {
(Get-Content $File.fullname).replace((Get-Content $File.fullname)[5],'x') | Set-Content -Path $file.FullName
}
It replaces every occurence of the character which is expected but not exactly what I want- how do I go around that?
Your examples do not match the description of the question. However, from your comment, I gather you simply want to replace the 26th character with another.
To do that, read the file in as single string and do the replacement:
$charIndex = 26 # the character index. Remember this counts from 0
$replaceWith = 'x' # the character to put in the $charIndex place
Get-ChildItem "C:\Temp" -Filter "xfil*" -File | ForEach-Object {
$content = Get-Content -Path $_.FullName -Raw
$content.Replace($content[$charIndex], $replaceWith) | Set-Content -Path $_.FullName
}
Alternative
Get-ChildItem "C:\Temp" -Filter "xfil*" -File | ForEach-Object {
$content = Get-Content -Path $_.FullName -Raw
if ($content.Length -gt $charIndex) {
"{0}$replaceWith{1}" -f $content.Substring(0, $charIndex),
$content.Substring($charIndex + 1) |
Set-Content -Path $_.FullName
}
}
It can also be achieved with this one liner:
$Content = Get-Content -path $file.fullname
$Replace = $Content.Remove(22,1).Insert(22,$ReplaceNumber) | Set-content $file.fullname
Related
Lets say I have a bunch of text files with people's names, that all have this as the content:
number
I want to replace "number" with a value from a CSV or text file, sequentially, and based on the file name. CSV has two columns, name and number:
Joe 5551011000
Gary 5551011001
Clark 5551011002
So I want to find the text file named Joe, and replace the "number" with "5551011000", and the text file named Gary, and replace "number" with "5551011001".
Thank you!
I didn't get too far:
Get-ChildItem "C:\test\*.txt" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace 'changeme', 'MyValue' | Set-Content $_
}
This gets me party there, but I don't know how to find a specific file, then replace "number" in that file with the correct value that matches the name.
I also tried a different approach, with manual entry, and it works, but I need it to just be automated:
get-childitem c:\Marriott -recurse -include *.txt |
select -expand fullname |
foreach {
$new = Read-Host 'What is the new value you want for ' $_
(Get-Content $_) -replace 'number',$new |
Set-Content $_
}
I would convert your CSV to a hashtable, then this gets pretty simple.
$ReplaceHT = #{}
Import-Csv c:\path\to\file.csv -Delimiter ' ' -Header 'FileName','Number' | ForEach-Object {$ReplaceHT.add($_.FileName,$_.Number)}
Get-ChildItem c:\Marriott -recurse -include *.txt -PipelineVariable 'File'|Where{$_.name -in $ReplaceHT.Keys} |ForEach-Object{
(Get-Content $File.FullName) -replace 'changeme', $ReplaceHT[$File.Name] | Set-Content $File.FullName
}
Below is the code I am having trouble with. It pulls from a config.txt file and sets information to childofRoot.properties file. for some reason the string when I set it is coming with extra added on.
$date = (Get-Date -Format "MM-dd-yyyy'_'HH-mm")
$backup = 'backuplocation'
$temp = 'replace'
$p = ($PSScriptRoot + 'childofRoot.properties')
$cuidConf = Get-Content -Path ($PSScriptRoot + 'config.txt') | Select-String "cuids_rootfolder=" | Out-String
$cuidConf = $cuidConf.replace("cuids_rootfolder=", "").replace("`n", "")
$cuids = $cuidConf.Split(";")
$backuppath = ((Get-Content -Path ($PSScriptRoot + 'config.txt'))) | Select-String "backuplocation=" | Out-String
$backuppath = $backuppath.replace("backuplocation=", "").replace("`n", "")
$backuppath = $backuppath + $date + "\"
$foldername, $cuid = ($cuids[0].Split(","))
$backup1 = ($backuppath + "Folder a.lcmbiar")
((Get-content -Path $p).replace($temp, $cuid)) | Set-Content -Path $p
((Get-content -Path $p).replace($backup, $backup1)) | Set-Content -Path $p
Contents of config.txt:
backuplocation=C:\backuplcm\backupfiles\
Content of childofRoot.properties:
exportLocation=backuplocation
Expected output written to childofRoot.properties:
exportLocation=C:\backuplcm\backupfiles\08-18-2020_17-59\Folder\a.lcmbiar
Output I'm seeing written to childofRoot.properties:
exportLocation=
C:\backuplcm\backupfiles\
08-18-2020_18-02\Folder a.lcmbiar
Yes I already tried removing new line characters with .replace("`n","")
I had others look at this script too and the variable looks fine just when i set it it comes out different in the text file.
I was able to replicate this on Powershell 4 and Powershell 5 on different machines. If someone would try this on their machine and see if they can fix the problem.
The extra line breaks are from doing | Select-String "backuplocation=" | Out-String, and the reason .Replace("`n", "") doesn't solve the problem is that Windows uses the sequence "`r`n" for line breaks.
I suggest simplifying your script with Where-Object instead of Select-String | Out-String:
$backuppath = Get-Content -Path (Join-Path $PSScriptRoot config.txt) | Where-Object {$_ -match "backuplocation="}
$backuppath = $backuppath -replace 'backuplocation='
Hey it's me again with my paths :D
I write my Paths into a TXT-File.
Ex:
C:\Ex\am\ple\path.txt
C:\Ex\am\ple\file.txt
C:\Ex\am\ple\text.txt
Now I want to replace the "*.txt" at the end of every Path.
I tried the following:
(Get-Content ".\MYPATHS.txt") | Foreach-Object {$_ -replace "\*.txt"}| Set-Content ".\MYPATHS.txt"
Where's is my fault?
k, if you need just the path(without the files):
'C:\Ex\am\ple\path.txt', 'C:\Ex\am\ple\file.txt' | Split-Path -Parent
the list above
'C:\Ex\am\ple\path.txt', 'C:\Ex\am\ple\file.txt'
replaces 'Get-Content'. Output:
C:\Ex\am\ple
C:\Ex\am\ple
Ok heres what I have code wise:
$a = "C:\Users\some.deranged.character\Desktop\SomeAwfulPlace\Checklists\C_F\*.csv"
$b = "C:\Users\some.deranged.character\Desktop\SomeAwfulPlace\Checklists\C_F\merge.csv"
(get-content $a) | set-content $b
This pulls all the data of all the files into one merged file, but I need one additional item, I need to pull the name of the individual files and append it to the first column of the file for multiple files, several hundred at a time.
Not tested but something like this should do it:
$a = "C:\Users\some.deranged.character\Desktop\SomeAwfulPlace\Checklists\C_F\*.csv"
$b = "C:\Users\some.deranged.character\Desktop\SomeAwfulPlace\Checklists\C_F\merge.csv"
Get-ChildItem $a | % {
Import-Csv $_.Fullname | Add-Member -MemberType NoteProperty -Name 'File Name' -Value $_.Name
} | Export-Csv $b
Assuming the CSV files each have the same column headings, I would lean toward using Import-CSV instead of Get-Content so that you can work with the CSV contents as arrays of objects with named properties.
Then all you need to do is iterate through each item of the array and append a property containing the file path, which you can do using the Add-Member cmdlet. Once that's done, export the array of objects using the Export-CSV cmdlet.
$directory = "C:\Users\some.deranged.character\Desktop\SomeAwfulPlace\Checklists\C_F\"
$search = $directory + "*.csv"
$exportpath = "C:\Users\some.deranged.character\Desktop\SomeAwfulPlace\Checklists\C_F\merge.csv"
$paths = get-childitem $search
$objectArrays = #()
$paths | %{
$filepath = $_.fullname;
$objectArray = Import-CSV $filepath;
$objectArray | %{
Add-Member -inputobject $_ -Name "SourceFile" -Value $filepath -MemberType NoteProperty};
$objectArrays += $objectArray}
$objectArrays | export-csv -path $exportpath -notype
This puts the SourceFile property as the last column in the outputted CSV file
Ok, simplification... Search target folder, pipe to a ForEach-Object loop (shorthand % used), capture the file name as variable, import the CSV, add the sourcefile using the Select-Object cmdlet, convert it back to a CSV, end loop, pipe to destination file.
$a = "C:\Users\some.deranged.character\Desktop\SomeAwfulPlace\Checklists\C_F\*.csv"
$b = "C:\Users\some.deranged.character\Desktop\SomeAwfulPlace\Checklists\C_F\merge.csv"
GCI $a | %{$FileName=$_.Name;Import-CSV $_|Select #{l='SourceFile';e={$FileName}},*|ConvertTo-CSV -NoType} | set-content $b
I have over 1000+ files that have to be renamed.
The first set folder and/or files are grouped by location, so the first four characters are the same for each file; there are four-five different locations. I need to delete the first few characters of the folder's name.
Example:
Old File: ABC_Doe, Jane
New File: Doe, Jane
any suggestions as to the quickest way to carry this out?
I've tried all of the following:
1st Attempt
$a = Get-ChildItem C:\example
$b = Where-Object {$_.name -like “*ABC_*”}
$cmdlet_name = “Rename-Item”
$d = (cmdlet_name $a $b)
invoke-expression $d
2nd Attempt
$e = Get-ChildItem C:\example
$f = $e.TrimStart (“ABC_”)
3rd Attempt
Rename-Item -{$_.name -like “*ASD*”, “”}
Try this, get all child items (files only), remove abc_ by replacing them (with nothing) and rename each file. To rename files in sub-directories add the -Recurse switch to the Get-ChildItem command:
Get-ChildItem c:\example -Filter ABC_* | Where-Object {!$_.PSIsContainer} | Rename-Item -NewName { ($_.BaseName -replace '^ABC_') + $_.Extension }
UPDATE
Actually, this should work as well and is much shorter (no need to append the file extension cause renaming is performed on the file name).
Get-ChildItem c:\example -Filter ABC_* | Where-Object {!$_.PSIsContainer} | Rename-Item -NewName { $_.Name -replace '^ABC_' }
get-childItem ABC_* | rename-item -newname { $_.name -replace 'ABC_','' }
Source: get-help rename-item -full