This is my attempt at learning PowerShell. No edu background in coding/scripting. Only learned Batch by reading different examples here in StackOverflow and Superuser, trying to adapt found snippets to what is needed, and a lot of trial and error. Please be kind!
There are several strings (without the numbering) that needs to be added to a txt file sequentially and to the top of the file:
I attempted to "convert" what was found to something that might look usable in a Batchfile:
start "" /wait /min powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "(Get-ChildItem 'D:\Sample Path\%sample_var%\Sample file.txt' -File -recurse | Where{!(Select-String -SimpleMatch '([/This/IsJust.AnExample])|(IsThisTrue=False)|(IsThisFalse=)' -Path $_.fullname -Quiet)} | ForEach{ $Path = $_.FullName '([/This/IsJust.AnExample])|(IsThisTrue=False)|(IsThisFalse=)',(Get-Content $Path) | Set-Content $Path })"
Expectation:
Example: If it's entirely missing
[/MoreRandom /Example/In /Here]
MaybeThisIsCorrect=False
MaybeIAmConfused=True
MaybeINeedToLearnTheBasicsOfPowershell=True
MyEnglishIsTerrible=True
Apologetic=True
Expected:
[/This/IsJust.AnExample]
IsThisTrue=False
IsThisFalse=
[/MoreRandom /Example/In /Here]
MaybeThisIsCorrect=False
MaybeIAmConfused=True
MaybeINeedToLearnTheBasicsOfPowershell=True
MyEnglishIsTerrible=True
Apologetic=True
Example:
<newline/blank>
<last string>
<newline/blank>
<string1>
<newline/blank>
<existing content>
Expected:
<string1>
<string2>
<last string>
<newline/blank>
<existing content>
Example:
<newline/blank>
<newline/blank>
<newline/blank>
<string1>
<last string>
<string2>
<newline/blank>
<existing content>
Expected:
<string1>
<string2>
<last string>
<newline/blank>
<existing content>
<last string>
<newline/blank>
<existing content starts here>
Result of original attempt:
Result of attempts after receiving suggestions/info:
start "" /wait /min powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "(Get-ChildItem 'example.txt' -File -recurse -PipelineVariable FilePath | Where{!(Select-String -SimpleMatch '([/This/IsJust.AnExample])|(IsThisTrue=False)|(IsThisFalse=)' -Path $_.fullname -Quiet)} | ForEach{ [string[]]$ToAdd = [string]::Empty; $Out = Get-Content $FilePath -raw; Switch ($Out){{$_ -notmatch [regex]::Escape('[/This/IsJust.AnExample]')}{$ToAdd += '[/This/IsJust.AnExample]'};{$_ -notmatch 'IsThisTrue=False'}{$ToAdd += 'IsThisTrue=False'};{$_ -notmatch 'IsThisFalse='}{$ToAdd += 'IsThisFalse='}};$ToAdd,$Out | Set-Content -Path $FilePath})"
- works but it always adds the missing string on the top of the page not in the order they were written in. It also does not add a blank (separator) in between the last string and the first line of the existing content.'([/This/IsJust.AnExample])|(IsThisTrue=False)|(IsThisFalse=)'
- Adds a single line instead of checking each string if it exists('[/This/IsJust.AnExample]','IsThisTrue=False','IsThisFalse=')
- Adds all strings only if all of them of are missing. If there is a single string already present, it won't add the remaining.Notes:
-NoP -Ex -By -c
to -NoProfile -ExecutionPolicy Bypass -Command
as suggested by @CompoWhat is causing it to fail and how to properly do it?
A link to a dummies guide on how to convert PowerShell to Batch would also be nice.
Additionally, would appreciate to know which part can be reused in order to add more strings if needed in the future.
Mmm... If you want that the solution works in a Batch file, why not write it in a Batch file in first place? Besides, IMHO the Batch solution is simpler than the PowerShell one and it runs much faster than the PS one, specially if you want to run it in a loop...
EDIT 2023/10/16: Code modified as requested in comments...
@echo off
setlocal EnableDelayedExpansion
rem Define the strings that needs to be reviewed
set "n=0"
set "strings="
for %%a in (
"[/This/IsJust.AnExample]"
"IsThisTrue=False"
"IsThisFalse="
) do (
set /A n+=1
set "string[!n!]=%%~a"
set "strings=!strings!/C:"%%~a" "
)
rem Get the line number of the first line of "existing content"
set "skip="
for /F "tokens=1* delims=:" %%a in ('findstr /N /V /L %strings% test.txt') do (
if not defined skip if "%%b" neq "" set /A "skip=%%a-1"
)
if defined skip (
if "%skip%" neq "0" (
set "skip=skip=%skip%"
) else (
set "skip="
)
)
rem Insert the strings at beginning of output file
(
for /L %%i in (1,1,%n%) do echo !string[%%i]!
echo/
for /F "%skip% delims=" %%a in (test.txt) do echo %%a
) > output.txt
rem Last step: update input file
REM move /Y output.txt test.txt
If you want to run this code in a loop you could directly insert it in the loop, or you can convert it into a subroutine (adding a :label
at beginning and an exit /B
at end) and call :label
in the loop
PS - You said you need this code run in a for
loop, but you don't specify which value will be modified in the loop... If you do so, we could write the complete solution
EDIT 2023/10/17 New code added because there are A LOT of changes!
This question have been modified several times with new specifications each time it is modified. Let's review your examples and descriptions so far:
<existing content>
. It does NOT specify that a string could be in the <existing content>
<existing content>
Again, it does NOT specify that a string could be in the <existing content>
<last string>
the result must contain a <newline/blank>
and then <existing content starts here>
What this "existing content" is? The contents of the input file below the strings (as specified). You never specified that THE EXISTING CONTENT OF THE INPUT FILE COULD INCLUDE A STRING!!! If the "existing content" have a string, then it MUST BE MODIFIED (by removing such a string) when it is passed to the result file. In such a case, it can't be longer called EXISTING CONTENT!!!!! In other words: if you called it "existing content", then you used a term opposite to the desired result (so it is a term that generates confusion, instead of being descriptive)...You have explained A LOT of things, but not the important ones...
You should help us to help you, not hide important information that makes it difficult to help you... :(
I hope the new code below solve you problem (at least, the last one)...
@echo off
setlocal EnableDelayedExpansion
rem Define the strings that needs to be reviewed
set "n=0"
set "strings="
for %%a in (
"[/This/IsJust.AnExample]"
"IsThisTrue=False"
"IsThisFalse="
) do (
set /A n+=1
set "string[!n!]=%%~a"
set "strings=!strings!/C:"%%~a" "
)
rem Generate the output file:
(
rem First, insert the strings at beginning
for /L %%i in (1,1,%n%) do echo !string[%%i]!
echo/
rem Then, insert the lines in the file that have NOT the strings
for /F "delims=" %%a in ('findstr /V /L %strings% test.txt') do echo %%a
) > output.txt
rem Last step: update input file
REM move /Y output.txt test.txt
LAST CODE: I give up...
@echo off
setlocal EnableDelayedExpansion
rem Define the strings that needs to be reviewed
set "n=0"
set "strings="
for %%a in (
"[/This/IsJust.AnExample]"
"IsThisTrue=False"
"IsThisFalse="
) do (
set /A n+=1
set "string[!n!]=%%~a"
set "strings=!strings!/C:"%%~a" "
)
rem Process files with .ini extension
for %%f in (*.ini) do (
rem Generate the output file:
(
rem First, insert the strings at beginning
for /L %%i in (1,1,%n%) do echo !string[%%i]!
echo/
rem Then, insert the lines in the file that have NOT the strings
rem Convert a UTF-16 LE BOM file to UTF-8 via TYPE command
for /F "delims=" %%a in ('type "%%f" ^| findstr /V /L %strings%') do echo %%a
) > output.txt
rem Last step: update input file
move /Y output.txt "%%f" > NUL
)