Foreword
I'm new to batch and have been doing it for about 2 weeks. My function isn't following what I would consider normal program flow rules when I add a specific for loop to it. When the for loop is removed, the function follows what I expect program flow to be, but the output still isn't what I want. The root problem is delayed expansion variables inside delayed expansion variables.
I've checked the parentheses multiple times and I can't find anything unbalanced about them in the full code near the bottom. Program flow wise, this makes no sense, the addition of a for loop affects statements before the for loop. The only thing I can think of is that some weird error is happening where the code simply doesn't execute the full loop and reaches my pause statement right after the loop.
What I'm actually trying to do
I am trying to delimit a one line string by ; with an unknown/variable number of tokens and other possible delimiters in the string (like commas) that I want to delimit LATER. This can't be done with the for loops that batch has premade, FOR /F can only do lines and or set numbers of tokens and the regular for loop delimits by semi colons AND commas at the same time. I want to delimit FIRST by semicolons and THEN by commas later seperately. To do this I'm trying to make my own simple split a line for loop with labels. I ran into a problem involving delayed expansion of my variables. Example here:
Not full code, but code up to the delayed expansion problem
setlocal EnableDelayedExpansion
set "TestArgument=%~1"
set /a "CurrentIndex=0"
set /a "DelimIndex=0"
set /a "LoopCount=0"
:ForEach
IF "!TestArgument:~%CurrentIndex%,1!"=="" (goto :ForEachEnd & echo End of list)
echo testing semicolon
IF NOT "!TestArgument:~%CurrentIndex%,1!"==";" (SET /a CurrentIndex=%CurrentIndex%+1 & goto :ForEach & echo found non ;) ELSE (
set /a "LengthToSearch=%CurrentIndex%-%DelimIndex%"
SET "currentArg=!TestArgument:~%DelimIndex%,!LengthToSearch!!
What I want from this specific part of the function
Example inputs:
set "ICMPv4RuleTest="Enable Echo Ping Request ICMPv4;Protocol,ICMPv4;Enabled,Yes;LocalIP,Any;RemoteIP,Any;Direction,In;Action,Allow""
Example desired outputs: a For loop (the labels of the above) where each iteration takes one string delimited by ; so the first iteration would take the Enable Echo Ping Request ICMPv4
value. The whole point of the above is to take the input and substring it in a way so that each iteration is delimited by the semicolon
The code above, specifically the last line causes the problem because (I think) the program reads this as delay expanding !TestArgument:~%DelimIndex%,!
(which would error out) then !! (which is nothing) leaving only LengthToSearch as a raw string. What I want is to have the LengthToSearch value be expanded before the substring operation, then expand/run/do the expansion of the substring operation and set that to CurrentArg (a single line string delimited by a ;). I can't use the % signs with LengthtoSearch since it seems to be in the same scope as the substring operation however I can use % signs with DelimIndex (because thats out of scope? I don't know).
What I've tried
I've tried variations of the substring line (last line) including:
SET "currentArg=!TestArgument:~%DelimIndex%,%LengthToSearch%!
prints nothing.SET "currentArg=!TestArgument:~%DelimIndex%,!!LengthToSearch!!!
prints 31 (the literal argument of DelimIndex).SET "currentArg=%TestArgument:~%DelimIndex%,!!LengthToSearch!!%
prints nothing.SET "currentArg=%TestArgument:~%DelimIndex%,!LengthToSearch!%
prints nothing.
I've tried some others but they definitely aren't right. The way I think it should be was the
SET "currentArg=!TestArgument:~%DelimIndex%,!LengthToSearch!!
.
way, but that just has the aforementioned problems. I did some research on here and found out that someone else had somethign similar to my problem with string search and replace and they used a FOR loop to insert the delayed expansion values into a delayed expansion substring operation as the for loop parameter. I thought I could use the same methodology so I tried this (big change to the last line):
setlocal EnableDelayedExpansion
set "TestArgument=%~1"
set /a "CurrentIndex=0"
set /a "DelimIndex=0"
set /a "LoopCount=0"
:ForEach
IF "!TestArgument:~%CurrentIndex%,1!"=="" (goto :ForEachEnd & echo End of list)
echo testing semicolon
IF NOT "!TestArgument:~%CurrentIndex%,1!"==";" (SET /a CurrentIndex=%CurrentIndex%+1 & goto :ForEach & echo found non ;) ELSE (
set /a "LengthToSearch=%CurrentIndex%-%DelimIndex%"
FOR /F "tokens=*" %%A IN ("!LengthToSearch!") DO (SET "currentArg=!TestArgument:~%DelimIndex%,%%A!)
And thats when things got REALLY weird. For some reason, the addition of the forloop causes the whole ELSE case to not execute. When I run my code, the
IF NOT "!TestArgument:~%CurrentIndex%,1!"==";"
Only "runs" once (it doesn't really run all of what it should) and then the loop literally breaks. I don't mean it goes to the end of the loop it simply ignores the whole rest of the function entirely. I've checked parenthesis multiple times in the full code HERE:
Full Code of function
:FirewallRuleTestFunc
echo got to function
setlocal EnableDelayedExpansion
set "TestArgument=%~1"
ECHO PARAM WAS "%~1"
echo TestArgument was "%TestArgument%"
set /a "CurrentIndex=0"
set /a "DelimIndex=0"
set /a "LoopCount=0"
echo trying foreach
:ForEach
echo got to foreach
IF "!TestArgument:~%CurrentIndex%,1!"=="" (goto :ForEachEnd & echo End of list)
echo testing semicolon
IF NOT "!TestArgument:~%CurrentIndex%,1!"==";" (SET /a CurrentIndex=%CurrentIndex%+1 & goto :ForEach & echo found non ;) ELSE (
echo WHY IS THIS NOT BEING REACHED.
echo CurrentIndex is %CurrentIndex%
echo startposition was first: %DelimIndex%
set /a "LengthToSearch=%CurrentIndex%-%DelimIndex%"
echo length to search was: !LengthToSearch!
echo length to search was: %LengthToSearch%
echo startposition was: %DelimIndex%
FOR /F "tokens=*" %%A IN ("!LengthToSearch!") DO (SET "currentArg=!TestArgument:~%DelimIndex%,%%A!)
echo loop of ; Arg was: !currentArg!
set /a DelimIndex=!CurrentIndex!
echo Delim index was: %DelimIndex%
IF !LoopCount! NEQ 0 (
echo afterfirstloop
FOR /F "tokens=1,2 delims=," %%A IN ('netsh advfirewall firewall show rule name^="!RuleName!" ^| FIND "%%A"') DO (
echo loop of , A was '%%A'
SET "FoundArgument=%%B"
SET "FirewallRuleExists=%%A"
IF "!FirewallRuleExists!"=="" (echo TEST FAILED firewall rule with name "!RuleName!" NOT FOUND)
IF "!FoundArgument!"=="Yes" (echo Test Passed) ELSE (echo Test Failed was "!FoundArgument!")
)
) ELSE (SET "RuleName=!currentArg!" & set /a "LoopCount=%LoopCount%+1" & echo firstloop done)
echo got past if else
)
:ForEachEnd
echo end of THING
endlocal
echo SOMETHING
goto:EOF
And none of the echos in either the ELSE case of the second IF (IF NOT "!TestArgument:~%CurrentIndex%,1!"==";"
), nor any other echos besides the ones before the second IF ever actually happen. This makes absolutely no sense to me and I can't comprehend why it ignores program flow when the for loop is added and program flow works when the for loop is commented out. All I want to do is have a for loop that loops once per a delimiter that I can specify. My only guess is there is some error happening causing it to go directly to EOF. right after my function is called there is a pause because the rest of my program should be irrelevant. And I'm currently working on just this part. The inputs to the function are like specified below:
Example of function call:
set "ICMPv4RuleTest="Enable Echo Ping Request ICMPv4;Protocol,ICMPv4;Enabled,Yes;LocalIP,Any;RemoteIP,Any;Direction,In;Action,Allow""
call :FirewallRuleTestFunc %ICMPv4RuleTest%
I am beyond frustrated and I just need some help. I'll keep trying various things but this is the last part of my program I need to complete and I just want to get something stable, working and efficient and not have to do what I did previously, use line columns and magic numbers to check firewall settings by token. (I'm testing a script to configure some settings so a company network can be set up).