Batch Replace Multiple Texts in a file - powershell

I need to replace multiple different instances of text in a file using a .bat.
(Note: SQF is just a server config file, Encoding is not an issue)
I have tried:
powershell -Command "(gc Structures.sqf) -replace 'WOOD_WALL', 'CINDERBLOCK_WALL' | Out-File BrickMe.sqf"
powershell -Command "(gc Structures.sqf) -replace 'e614ee17-4467-4d51-a3f2-d4faa61de89e', 'a59f5b71-2b9a-45a2-85bb-ec29a47f78aa' | Out-File BrickMe.sqf"
powershell -Command "(gc Structures.sqf) -replace 'Wood Wall', 'Cinderblock Wall' | Out-File BrickMe.sqf"
But it only performs the last command. Eg. WOOD_WALL remains.
And
sed -e "s/WOOD_WALL/CINDERBLOCK_WALL/" -e "s/Wood Wall/Cinderblock Wall/" <Structures.sqf>BrickMe.sqf
Just creates an empty file called BrickMe.sqf
I have also tried a VBScript to no avail. I would rather keep it able to run on any Windows machine provided the code can handle the file size but I don't know how to replace multiple instances of different text without repeating the whole command and taking a long time.
I have also looked at this http://www.dostips.com/?t=batch.findandreplace
But was unsure of where to put my "WOOD_WALL" instances and my file names.
I have found heaps of results on google for replacing 1 piece of text in multiple files but hardly anything on replacing multiple texts in 1 file.
The Story:
I am running an Arma 3 server and have built a wooden admin base in game that I wish to convert to a cinderblock base. I have done this before but only manually by replacing the Instance Name, Instance_ID and Entity Name. I would like to do it using a batch file if possible and upload it to http://www.exilemod.com to help other admins. The files are usually no larger then 15 Megabytes in size.
I'm pretty awesome with Windows batch files but am new to PowerShell.

It's no wonder that your actions are not successfull.
You always take the original input file, perform actions and save to the same output file this way overwriting the previous action.
For better understanding the PowerShell part broken up:
(gc Structures.sqf) -replace 'WOOD_WALL', 'CINDERBLOCK_WALL' `
-replace 'e614ee17-4467-4d51-a3f2-d4faa61de89e',
'a59f5b71-2b9a-45a2-85bb-ec29a47f78aa' `
-replace 'Wood Wall', 'Cinderblock Wall' |
Out-File BrickMe.sqf
As the -replace operator is RegEx based the 1st and 3rd replace can be joined by:
placing a character class [_ ] underscore or space inside
a capture group ([_ ]) and
using the capture group in the replacement string $1
(gc Structures.sqf) -replace 'WOOD([_ ])WALL', 'CINDERBLOCK$1WALL' `
-replace 'e614ee17-4467-4d51-a3f2-d4faa61de89e',
'a59f5b71-2b9a-45a2-85bb-ec29a47f78aa' |
Out-File BrickMe.sqf
All this wrapped again in a cmd line:
powershell -NoProfile -Command "(gc Structures.sqf) -replace 'WOOD([_ ])WALL', 'CINDERBLOCK$1WALL' -replace 'e614ee17-4467-4d51-a3f2-d4faa61de89e','a59f5b71-2b9a-45a2-85bb-ec29a47f78aa'|Out-File BrickMe.sqf"

Related

PowerShell for-each cleanup

I know PowerShell is up to v5, but as I am new to PowerShell, I've been looking through Stack Overflow to generate the script I have. I've found that I need a generic non-version specific way of accomplishing this process...
Here is the issue - Step 1 - I'm pulling application installation locations information from the registry and am using a temporary file to house the results.
dir "HKLM:\SOFTWARE\Wow6432Node\companyname" | Get-ItemProperty | Select installdir | Out-File "$env:USERPROFILE\Desktop\KDI-Admin\Export\$env:COMPUTERNAME-SC-Installs.txt"
This provides me a list of installation directories for the company's software that is installed on a particular machine. I then want to take these results, append *.config to each line, as well as taking these results and appending *.xml to each line, and output to a new text file.
The input for the process would be the contents of the initial results file, and the output file should have each line listed in the first results, added to the final results file, once appended with *.xml, and once appended with *.config.
The net effect I am looking for is the creation of a #file for a 7z command. I am attempting this by using the following -
(Get-Content "$env:USERPROFILE\Desktop\KDI-Admin\Export\$env:COMPUTERNAME-SC-Installs.txt") -replace '\S+$','$&*.config' | Out-File "$env:USERPROFILE\Desktop\KDI-Admin\Export\$env:COMPUTERNAME-SC-config.txt" -Encoding utf8
(Get-Content "$env:USERPROFILE\Desktop\KDI-Admin\Export\$env:COMPUTERNAME-SC-Installs.txt") -replace '\S+$','$&*.xml' | Out-File "$env:USERPROFILE\Desktop\KDI-Admin\Export\$env:COMPUTERNAME-SC-config.txt" -Append -Encoding utf8
However, I'm only getting one line that has *.xml and one line that has *.config appended -
After getting this far, I'm thinking that some for-each loop is needed, but I'm not getting anywhere with what I have tried adapting from here. I'm looking now for some way to combine the three lines into one function, if that is possible, and eliminate the temporary file step in the first command, by reading and outputting in the same step. This would also need to remove the "installdir" and "----------" lines from the output. Anyone have some ideas and maybe examples?
Taken your above command dir "HKLM:\SOFTWARE\Wow6432Node\companyname" | Get-ItemProperty | Select installdir | Out-File "$env:USERPROFILE\Desktop\KDI-Admin\Export\$env:COMPUTERNAME-SC-Installs.txt" you could put the result of your query into a variable $result:
$result = dir "HKLM:\SOFTWARE\Wow6432Node\microsoft" | Get-ItemProperty | Select installdir;
From there you can easily loop through the array, skipping empty ones and process the rest of it:
foreach($path in $result.installdir)
{
# skip empty paths
if([string]::IsNullOrWhiteSpace($path)) { continue; }
# now do your processing ...
$path;
}
Is this what you were asking for?

Script to replace line that contains text

I found another discussion on this, where there were numerous different options available but most of them didn't seem to work for myself or the original poster. I did however find an example that is confirmed working, however I am struggling with getting it to work and hoping for help.
I need to find a line that begins with "ServerName=" and replace this with my own line. I have used the example that was found and modified it, but I am getting errors when using it.
PowerShell Command:
powershell -Command "(Get-Content 'KFGame\Config\PCServer-KFGame.ini') | Foreach-Object {$_ -replace '^ServerName.$', ('ServerName=Network BUF 12345 Normal')} | Set-Content 'KFGame\Config\PCServer-KFGame.ini'"
Error Message:
) was unexpected at this time
If you want to run complex PowerShell statements from CMD you need to put them in quotes so that CMD just sees a string and doesn't try to handle special characters (like pipes):
powershell -Command "(Get-Content 'C:\Host400.txt') | Foreach-Object {$_ -replace '^workstationID.*$', (""WorkstationID=$computerName""} | Set-Content 'C:\Host400.txt'"
Note that you need to either escape or replace double quotes within the command string.
A better approach is to put the PowerShell statement(s) into a .ps1 script and run that via the -File parameter:
powershell -File "C:\path\to\your.ps1"

Replace all in multiple CSV - Powershell

I'm attempting to replace the hostname from inside a CSV file with a blank space " ", but I am struggling to understand how this works, as when I attempt to call $env:computername it takes it as a string rather than the variable as per below:
$var = $env:computername
[io.file]::readalltext("C:\test\test.csv").replace("$var"," ") | Out-File c:\test\test-new.csv -Encoding ascii –Force
I have tested this and can see that the script is looking for the string $var in the CSV rather than the variable. Ultimately I would like to run this against a directory of CSV files that contain different hostnames in them and output the newly edited files to a separate location also.
I removed the quotes and tested this script and it worked for my test csv file
The quotes should be expanding the variable but if not you can simply pass the environmental variable directly like so:
[io.file]::readalltext("C:\test\test.csv").replace($env:ComputerName,"") | Out-File c:\test\test-new.csv -Encoding ascii –Force

Replace . with new lines in text file using powershell

I have a text file containing names of people seperated by . how to replace the . with new lines so that each name is in new line with powershell
If you have the latest version of PSCX (3.2.0) http://pscx.codeplex.com, we just added a new command to simplify this type of task a bit:
Edit-File -Path c:\path\to\file.txt -Pattern '\.' -Replacement "`r`n"
Or using positional params:
Edit-File c:\path\to\file.txt '\.' "`r`n"
This command also handles taking care that the file's original encoding is preserved. Using Out-File will output using Unicode unless you override with the -Encoding parameter which of course requires that you know the file's encoding in the first place. :-)
You can do a simple replace...
(gc c:\path\to\file.txt) -replace "\.","`n" | out-file c:\path\to\newfile.txt

How do I concatenate two text files in PowerShell?

I am trying to replicate the functionality of the cat command in Unix.
I would like to avoid solutions where I explicitly read both files into variables, concatenate the variables together, and then write out the concatenated variable.
Simply use the Get-Content and Set-Content cmdlets:
Get-Content inputFile1.txt, inputFile2.txt | Set-Content joinedFile.txt
You can concatenate more than two files with this style, too.
If the source files are named similarly, you can use wildcards:
Get-Content inputFile*.txt | Set-Content joinedFile.txt
Note 1: PowerShell 5 and older versions allowed this to be done more concisely using the aliases cat and sc for Get-Content and Set-Content respectively. However, these aliases are problematic because cat is a system command in *nix systems, and sc is a system command in Windows systems - therefore using them is not recommended, and in fact sc is no longer even defined as of PowerShell Core (v7). The PowerShell team recommends against using aliases in general.
Note 2: Be careful with wildcards - if you try to output to inputFiles.txt (or similar that matches the pattern), PowerShell will get into an infinite loop! (I just tested this.)
Note 3: Outputting to a file with > does not preserve character encoding! This is why using Set-Content is recommended.
Do not use >; it messes up the character encoding. Use:
Get-Content files.* | Set-Content newfile.file
In cmd, you can do this:
copy one.txt+two.txt+three.txt four.txt
In PowerShell this would be:
cmd /c copy one.txt+two.txt+three.txt four.txt
While the PowerShell way would be to use gc, the above will be pretty fast, especially for large files. And it can be used on on non-ASCII files too using the /B switch.
You could use the Add-Content cmdlet. Maybe it is a little faster than the other solutions, because I don't retrieve the content of the first file.
gc .\file2.txt| Add-Content -Path .\file1.txt
To concat files in command prompt it would be
type file1.txt file2.txt file3.txt > files.txt
PowerShell converts the type command to Get-Content, which means you will get an error when using the type command in PowerShell because the Get-Content command requires a comma separating the files. The same command in PowerShell would be
Get-Content file1.txt,file2.txt,file3.txt | Set-Content files.txt
I used:
Get-Content c:\FileToAppend_*.log | Out-File -FilePath C:\DestinationFile.log
-Encoding ASCII -Append
This appended fine. I added the ASCII encoding to remove the nul characters Notepad++ was showing without the explicit encoding.
If you need to order the files by specific parameter (e.g. date time):
gci *.log | sort LastWriteTime | % {$(Get-Content $_)} | Set-Content result.log
You can do something like:
get-content input_file1 > output_file
get-content input_file2 >> output_file
Where > is an alias for "out-file", and >> is an alias for "out-file -append".
Since most of the other replies often get the formatting wrong (due to the piping), the safest thing to do is as follows:
add-content $YourMasterFile -value (get-content $SomeAdditionalFile)
I know you wanted to avoid reading the content of $SomeAdditionalFile into a variable, but in order to save for example your newline formatting i do not think there is proper way to do it without.
A workaround would be to loop through your $SomeAdditionalFile line by line and piping that into your $YourMasterFile. However this is overly resource intensive.
To keep encoding and line endings:
Get-Content files.* -Raw | Set-Content newfile.file -NoNewline
Note: AFAIR, whose parameters aren't supported by old Powershells (<3? <4?)
I think the "powershell way" could be :
set-content destination.log -value (get-content c:\FileToAppend_*.log )