How to Read and Write to an INI File in Batch Script
INI (Initialization) files are a common, human-readable format for storing configuration settings for applications. Their simple [Section] and Key=Value structure makes them easy to edit manually. However, from a batch script, interacting with them is surprisingly complex because there is no native command to parse INI files. A script must treat it as a plain text file and manually implement the logic to find the right section and key.
This guide will walk you through the pure-batch scripting methods for both reading a value from and writing a value to an INI file. We will also cover the far more robust and recommended modern approach using a PowerShell one-liner, which avoids the many pitfalls of the native batch solution.
The Challenge: No Native INI Parser
The difficulty with INI files is context. The meaning of Version=1.0 depends entirely on which [Section] it's under. A simple findstr can't reliably distinguish between [Database] Version and [Application] Version. Therefore, a batch script needs to create a "state machine", i.e. it must first find the correct section, and only then start looking for the key.
Reading a Value from an INI File (Pure Batch)
This script demonstrates the logic required to find a specific section, then find a specific key within that section, and finally extract its value.
Consider this config.ini file as example:
[Database]
Server=db.example.com
Port=1433
[Application]
Version=1.2.5
Theme=Dark
The following script reads the Version from the [Application] section:
@ECHO OFF
SETLOCAL
SET "FILENAME=config.ini"
SET "TARGET_SECTION=Application"
SET "TARGET_KEY=Version"
SET "inSection=0"
FOR /F "usebackq delims=" %%L IN ("%FILENAME%") DO (
SET "line=%%L"
REM Check if the line is a section header
IF "!line:~0,1!"=="[" IF "!line:~-1!"=="]" (
REM Extract the section name
FOR /F "delims=[]" %%S IN ("!line!") DO (
IF /I "%%S"=="%TARGET_SECTION%" (
SET "inSection=1"
) ELSE (
SET "inSection=0"
)
)
)
REM If we are in the correct section, look for the key
IF !inSection! EQU 1 (
FOR /F "tokens=1,* delims==" %%A IN ("!line!") DO (
IF /I "%%A"=="%TARGET_KEY%" (
SET "FoundValue=%%B"
GOTO :ValueFound
)
)
)
)
:ValueFound
IF DEFINED FoundValue (
ECHO Found value for [%TARGET_SECTION%] %TARGET_KEY%: %FoundValue%
) ELSE (
ECHO Value not found.
)
ENDLOCAL
This script requires SETLOCAL ENABLEDELAYEDEXPANSION, which is not explicitly written because the !line! syntax implicitly requires it. It's better to enable it explicitly for clarity.
How the Read Script Works
inSectionFlag: The script uses a variable,inSection, as a switch. It is0(false) by default.- Find the Section: The
FOR /Floop reads the file. For each line, it checks if it's a section header (starts with[and ends with]). If it finds the[Application]section, it setsinSectionto1(true). If it finds a different section, it resets it to0. - Find the Key: Only when
inSectionis1does the script start looking for the key. It splits the line by the=delimiter. If the first part matchesVersion, it grabs the second part. GOTO :ValueFound: Once the value is found,GOTOis used to exit the loop immediately for efficiency.
Writing or Updating a Value in an INI File (Pure Batch)
Writing is even more complex. You must read the source file line by line and write to a temporary file, making the change when you encounter the correct line.
The following script updates Version to 1.3.0:
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "FILENAME=config.ini"
SET "TEMP_FILE=config.tmp"
SET "TARGET_SECTION=Application"
SET "TARGET_KEY=Version"
SET "NEW_VALUE=1.3.0"
IF EXIST "%TEMP_FILE%" DEL "%TEMP_FILE%"
SET "inSection=0"
FOR /F "usebackq delims=" %%L IN ("%FILENAME%") DO (
SET "line=%%L"
SET "isTargetKey="
REM Section detection logic (same as reading)
IF "!line:~0,1!"=="[" IF "!line:~-1!"=="]" (
FOR /F "delims=[]" %%S IN ("!line!") DO (
IF /I "%%S"=="%TARGET_SECTION%" (SET "inSection=1") ELSE (SET "inSection=0")
)
)
REM Key detection logic
IF !inSection! EQU 1 (
FOR /F "tokens=1 delims==" %%A IN ("!line!") DO (
IF /I "%%A"=="%TARGET_KEY%" SET "isTargetKey=1"
)
)
REM Write the line to the temp file
IF DEFINED isTargetKey (
ECHO %TARGET_KEY%=%NEW_VALUE% >> "%TEMP_FILE%"
) ELSE (
ECHO(!line! >> "%TEMP_FILE%"
)
)
DEL "%FILENAME%"
REN "%TEMP_FILE%" "%FILENAME%"
ECHO Update complete.
The Superior Method: Using PowerShell for Reliability
The pure-batch methods are brittle and fail easily with spaces or special characters. A PowerShell one-liner is vastly more robust.
The following script allows to read with PowerShell:
@ECHO OFF
SET "FILENAME=config.ini"
SET "TARGET_SECTION=Application"
SET "TARGET_KEY=Version"
FOR /F "delims=" %%V IN (
'powershell -Command "(Get-Content '%FILENAME%' | Where-Object {$_ -match '^\s*\[%TARGET_SECTION%\]\s*'} -Context 0,999 | Select-Object -Skip 1 | Where-Object {$_ -match '^\s*%TARGET_KEY%\s*='} | ForEach-Object {($_ -split '=', 2)[1].Trim()})"'
) DO (
SET "FoundValue=%%V"
)
ECHO PowerShell found value: %FoundValue%
The following script allow to write with PowerShell:
@ECHO OFF
SET "FILENAME=config.ini"
SET "TARGET_KEY=Version"
SET "NEW_VALUE=1.3.0"
powershell -Command "(Get-Content '%FILENAME%') -replace ('(?<=%TARGET_KEY%=).*', '%NEW_VALUE%') | Set-Content '%FILENAME%'"
This PowerShell command for writing is simple, powerful, and handles almost all edge cases automatically. It is the recommended method for any write operation.
Common Pitfalls and How to Solve Them
- Spaces around
=: The batchdelims==trick fails if your INI hasKey = Value. Thetokens=1,*modifier helps by assigning everything after the first=to the second variable. - Special Characters: Characters like
& | < > !will break the pure-batch scripts, especially whenDelayedExpansionis enabled. The PowerShell method is not affected by this. - Case Sensitivity: The
/Iswitch onIFhelps, but string comparisons in batch are tricky. PowerShell's-replaceis case-insensitive by default.
Practical Example: Reading and Incrementing a Build Number
This script uses the pure-batch method to read a build number, increment it, and write it back to the INI file, i.e. a common task in a build process.
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "FILENAME=build.ini"
SET "TARGET_SECTION=BuildInfo"
SET "TARGET_KEY=BuildNumber"
REM --- Read the current build number (using simplified read logic) ---
FOR /F "tokens=1,* delims==" %%A IN ('FINDSTR /B /I "%TARGET_KEY%=" "%FILENAME%"') DO (
SET "CurrentBuild=%%B"
)
ECHO Current build number is: %CurrentBuild%
REM --- Increment the build number ---
SET /A "NewBuild=%CurrentBuild% + 1"
ECHO New build number will be: %NewBuild%
REM --- Write the new build number back (using simplified write logic) ---
(FOR /F "usebackq tokens=1,* delims==" %%A IN ("%FILENAME%") DO (
IF /I "%%A"=="%TARGET_KEY%" (
ECHO %TARGET_KEY%=%NewBuild%
) ELSE (
ECHO %%A=%%B
)
)) > build.tmp
DEL "%FILENAME%"
REN build.tmp "%FILENAME%"
ECHO INI file updated.
Conclusion
While you can read and write to INI files using pure batch scripts, the process is complex and fragile.
- Reading requires a "state machine" logic to track which section you are in.
- Writing requires reading the entire file and outputting it to a temporary file while making your change in-stream.
- Both methods are highly susceptible to errors from unexpected formatting, spaces, or special characters.
For any serious or professional scripting, it is highly recommended to use the PowerShell one-liner method. It is more robust, handles edge cases correctly, and is often simpler to write and maintain.