2

Currently i have a setup where a program wants my LAN IP to attach their data to and this LAN IP are always random when i reboot my system. My LAN IP is always different as i do use a VPN so it's kind of a hazzle everytime i either change network or reboot as i do need to run the program, change it, restart it.

I do have a script that will make a variable with the correct IP, as it's always the first IPv4 Address. I did find it on this site.

set ip_address_string="IPv4 Address"
rem Uncomment the following line when using older versions of Windows without IPv6 support (by removing "rem")
rem set ip_address_string="IP Address"
for /f "usebackq tokens=2 delims=:" %%f in (`ipconfig ^| findstr /c:%ip_address_string%`) do (
    echo Your IP Address is: %%f
    goto :eof
)

This is golden, but every .ini edit post i've found do not actually work for me as it prints the line infinetly instead of editing the line.

As the size of the .ini is unknown i do need a powershell script in order for it to work as BATCH has limitations.

One user on Stackoverflow had this code:

(Get-Content C:\ProgramData\Nuance\NaturallySpeaking12\nssystem.ini) | ForEach-Object { $_ -replace 'Default NAS Address=.*','Default NAS Address=BHPAPPDGN01V' } | Set-Content C:\ProgramData\Nuance\NaturallySpeaking12\nssystem.ini

The line that needs to be changed is mostly random. Well, not random, but it'll move sometimes as users can make some changes and it'll push the IP line down or up depending on the settings.

I'm a bit novice when it comes to BATCH and powershell and i haven't figured out a way to transfer information to powershell. For example, BATCH will grab the IP, make a variable, run a powershell script editing the .ini. I do remember having a code that grabbed the IP to clipboard but i cannot find it in this moment.

My current progress is

@echo off
setlocal EnableExtensions
echo Exiting PROGRAM...
taskkill /IM PROGRAM.exe
timeout /t 1 /nobreak>nul
:check
for /F %%a in ('tasklist /NH /FI "IMAGENAME eq PROGRAM.exe"') do if %%a == PROGRAM.exe goto waiting
echo Restarting PROGRAM...
start "" "%ProgramFiles%\PROGRAM\PROGRAM.exe"
timeout /t 1 /nobreak>nul
exit
:waiting
echo PROGRAM is still running. Retrying...
timeout /t 3 /nobreak>nul
goto check

I don't need setlocal EnableExtensions but i did try to get it to work and it was needed then. Currently the script look if the program is running, if it is, kill it softly (wait for it to natively quit) then restart it. My goal is to kill it softly, edit the .ini and then restarting it with the changed made.

Hetsig
  • 29
  • 5

2 Answers2

1

A pure PowerShell solution would be most likely the best for this task because of Windows command processor cmd.exe is not designed for editing files.

But here is a pure batch file solution for determining the current IPv4 address and write it into the INI file if it contains currently a different address.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "IniFile=C:\ProgramData\Nuance\NaturallySpeaking12\nssystem.ini"
if exist "%IniFile%" goto GetIpAddress

echo ERROR: File missing: "%IniFile%"
echo(
pause
goto EndBatch

:GetIpAddress
set "ip_address_string=IPv4 Address"
rem Uncomment the following line when using older versions of Windows without IPv6 support (by removing "rem")
rem set "ip_address_string=IP Address"
rem The string above must be IP-Adresse on a German Windows.
for /F "tokens=2 delims=:" %%I in ('%SystemRoot%\System32\ipconfig.exe ^| %SystemRoot%\System32\findstr.exe /C:"%ip_address_string%"') do set "IpAddress=%%I" & goto IpAddressFound

echo ERROR: Could not find %ip_address_string% in output of ipconfig.
echo(
pause
goto EndBatch

:IpAddressFound
set "IniEntry=Default NAS Address"
rem Remove leading (and also trailing) spaces/tabs.
for /F %%I in ("%IpAddress%") do set "IpAddress=%%I"
rem Do not modify the INI file if it contains already the current IP address.
%SystemRoot%\System32\findstr.exe /L /X /C:"%IniEntry%=%IpAddress%" "%IniFile%" >nul
if errorlevel 1 goto UpdateIniFile

echo The file "%IniFile%"
echo contains already the line: %IniEntry%=%IpAddress%
echo(
goto EndBatch

:UpdateIniFile
for %%I in ("%IniFile%") do set "TempFile=%%~dpnI.tmp"
(for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /N "^" "%IniFile%" 2^>nul') do (
    set "Line=%%I"
    setlocal EnableDelayedExpansion
    set "Line=!Line:*:=!"
    if not defined Line echo(
    for /F delims^=^=^ eol^= %%J in ("!Line!") do (
        set "FirstToken=%%J"
        if "!FirstToken!" == "%IniEntry%" (
            echo %IniEntry%=%IpAddress%
        ) else echo(!Line!
    )
    endlocal
))>"%TempFile%"

rem Replace the INI file by the temporary file, except the temporary file is empty.
if exist "%TempFile%" (
    for %%I in ("%TempFile%") do if not %%~zI == 0 (
        move /Y "%TempFile%" "%IniFile%" >nul
        echo Updated the file "%IniFile%"
        echo with the %ip_address_string% "%IpAddress%" for INI entry "%IniEntry%".
        echo(
    )
    del "%TempFile%" 2>nul
)

:EndBatch
endlocal

Please read my answer on How to read and print contents of text file line by line?
It explains the awful slow code to update the INI file using just Windows Commands.

To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.

  • del /?
  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • goto /?
  • if /?
  • ipconfig /?
  • move /?
  • pause /?
  • rem /?
  • set /?
  • setlocal /?

See also Single line with multiple commands using Windows batch file for an explanation of operator &.

Read the Microsoft article about Using command redirection operators for an explanation of >, 2>nul and |. The redirection operator | must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded command line with ipconfig and findstr with using a separate command process started in background with %ComSpec% /c and the command line between the two ' appended.

Mofi
  • 46,139
  • 17
  • 80
  • 143
  • this is the final code that i got thanks to you. it is too long for a comment but i'll link pastebin for it. https://pastebin.com/n3xh7790 it basically, at this point, soft exits the program (if it needs to flush settings or data before quitting), grabbing IP, inputs it on a line in an .ini that you define and restarting the program. thank you again! – Hetsig Nov 07 '19 at 18:26
0

Mofi had a great batch solution, but he mentioned that CMD was not really designed for file output like this. So here's a pure powershell solution that should do what you want. It does borrow a bit from the powershell snippet you included in your question.

$ip = Get-NetIPAddress -InterfaceAlias "Ethernet" #| Out-File PathTo:\net.ini
$content = get-content PathTo:\net.ini | ForEach-Object { $_ -replace "172.23.*","$($ip.IPAddress)"} 
$content | Set-Content PathTo:\net.ini

Obviously this depends on you knowing the Interface Alias you want to grab, but you can find that easily with Get-NetIPAddress, and it shouldn't change. You'll also need to update the path information.

  • hi, sorry for the late respons. this do find the line and change accordingly, but the LAN IP is too vague as it always start with 10.**.**.* (*=random number) so it does find a lot more lines to change than normal. i did try to modify your work a bit to find a line instead but it spit out a lot of errors. ``` "IPv4Address=*","$(IPv4Address=$ip.IPAddress)" ``` the error is "expression is not valid". – Hetsig Nov 07 '19 at 18:02
  • Hi Hetsig, with $() you are creating a subexpression that PS interprets as a property of a variable, but then you're giving it a string and not a variable. Try something like this: "IPv4Address= 1*","IPv4Address = $($ip.IPv4Address)" – TheIdesOfMark Nov 12 '19 at 13:11
  • oh is see, thank you! both solutions work and both have their merits! – Hetsig Nov 16 '19 at 18:12