Search code examples
powershellbatch-fileeditini

Grab an unknown IP from ipconfig and edit an unknown .ini line with that IP with BATCH script


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.


Solution

  • 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.