Hey, unfortunatly I'm getting on my limits with Batch and I should have learned PowerShell long time ago but I'm not confident enough with PowerShell. So it would be nice if someone can help me starting some problem I have. I have several Reg files (Reg are similar InI files) which contain many different registry keys. I want to split every key with Value into a single file. example Source: regfile-blob: Code: [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System] "WallpaperStyle"="5" [HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\DriverSearching] "DontSearchCD"=dword:00000001 "DontSearchFloppies"=dword:00000001 "DontSearchWindowsUpdate"=dword:00000001 I want to export this one file blob into a folder structure (like the reg key) and many flat files. So based on the example a File like/in should be generated: C:\User\Software\Policies\Microsoft\Windows\DriverSearching.reg DriverSearching than contains:. Code: [HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\DriverSearching] "DontSearchCD"=dword:00000001 "DontSearchFloppies"=dword:00000001 "DontSearchWindowsUpdate"=dword:00000001 If file exisit (because auf mutiple files can contain same content) a number should be added (DriverSearching1.reg) C:\User\Software\Microsoft\Windows\CurrentVersion\Policies\System.reg Commented ( lines should NOT be skipped and just added to the section / regkey So to clearify: Every full regkey should be one single file and can contain mutiple value and data, everything after [KEY] should just be added into the file (up till the next key) It may also shloud be possible to skip/ignore the prefix of HKLM / HKCU
something like this should get you started, I added comments to make it easier to modify... Code: @echo off set "filetoparse=%~dpnx1" setlocal EnableDelayedExpansion REM parse registry file adding line number for /f "tokens=1* delims=:" %%a IN ('findstr /n "^" "%filetoparse%"') do ( set "linenumber=%%a" set "regkey=%%b" if "!regkey:~0,3!"=="[HK" ( call :loopprocess ) ) pause exit /b :loopprocess set "var1=!regkey!" set "var2=!regkey!" set "tok=0" REM count tokens :loopprocess2 for /F "tokens=1* delims=[\]" %%G in ( "!var1!" ) do ( set /A "tok+=1" set var1=%%H goto loopprocess2 ) REM echo The string contains !tok! tokens. REM get last token name for /F "tokens=%tok% delims=[\]" %%J in ( "!var2!" ) do ( set "last=%%J" ) REM create reg file with last token name echo Windows Registry Editor Version 5.00>"%~dp0%last%.reg" echo: >>"%~dp0%last%.reg" echo !regkey!>>"%~dp0%last%.reg" REM parse next lines :loopprocess3 set /a "linenumber+=1" for /f "tokens=1* delims=:" %%S IN ('findstr /n "^" "%filetoparse%"') do ( set "newlinenumber=%%S" set "linevalue=%%T" if "!newlinenumber!"=="!linenumber!" ( REM exit loop if next line is a registry key if "!linevalue:~0,3!"=="[HK" ( goto :eof ) REM print next line if line exist if defined linevalue ( echo !linevalue!>>"%~dp0%last%.reg" goto :loopprocess3 ))) goto :eof for HKLM not sure what you meant...You can do string replacement before echoing the key, something like this REM create reg file with last token name set "regkey=!regkey:HKEY_CURRENT_USER=HKCU!" set "regkey=!regkey:HKEY_LOCAL_MACHINE=HKLM!"
Thank you VERY much for the starting! Really appricated. I thought it would be easier in PS than Batch but I take what I get as this is only for internal Tools.. I modded and tweaked the script in some areas (we have differnt coding style ^^ - I like to work will call and you seem a pro with recursiv loops) I figured 2 problems. 1) Delete with [-HK is not yet supported (but I can solve this on my own (just skip loop 3) 2) It works but I don't like that in loop3 every line starts a new instance of findstr. - Do you have some other solution in mind? (IncrementFileName isn't working yet.. it's more like a ToDo currently) I would have all done it very different ^^ but I like the approach! Code: @echo off setlocal EnableDelayedExpansion set "filetoparse=%~dpnx1" REM parse registry file adding line number for /f "tokens=1* delims=:" %%a IN ('findstr.exe /n "^" "%filetoparse%"') do ( set "linenumber=%%a" set "regfileline=%%b" if "!regfileline:~0,3!"=="[HK" (call :loopprocess %%a %%b) if "!regfileline:~0,4!"=="[-HK" (call :delete) ) exit /b :loopprocess set "regkey=!regfileline!" set "tok=0" REM count tokens :loopprocess2 for /F "tokens=1* delims=[\]" %%G in ( "!regkey!" ) do ( if !tok! EQU 0 (set reg_path=%%H) REM echo !tok! %%G set /A "tok+=1" set regkey=%%H set last=%%G goto loopprocess2 ) call :CleanUpRegPath call :FolderCheckAndCreate call :CreateFile call :loopprocess3 goto :EOF REM parse next lines :loopprocess3 set /a "linenumber+=1" for /f "tokens=1* delims=:" %%S IN ('findstr.exe /n "^" "%filetoparse%"') do ( set "newlinenumber=%%S" set "linevalue=%%T" if "!newlinenumber!"=="!linenumber!" ( REM exit loop if next line is a registry key if "!linevalue:~0,3!"=="[HK" (goto :EOF) if "!linevalue:~0,4!"=="[-HK" (goto :EOF) REM print next line if line exist if defined linevalue ( echo !linevalue!>>"%reg_export%" goto :loopprocess3 ) ) ) goto :eof :CleanUpRegPath set "reg_path=!reg_path:[=!" set "reg_path=!reg_path:]=!" set "reg_path=!reg_path:\%last%=!" goto :EOF :FolderCheckAndCreate set "RegFullPath=%~dp0!reg_path!" if not exist "%RegFullPath%" (mkdir "%RegFullPath%") goto :EOF :CreateFile set "reg_export=%RegFullPath%\%last%.reg" if exist "%reg_export%" (call :IncrementFileName "%last%") echo Windows Registry Editor Version 5.00>"!reg_export!" echo: >>"!reg_export!" echo !regfileline!>>"!reg_export!" goto :EOF :IncrementFileName for /l %%i in (1 1 99) do (if NOT exist "%RegFullPath%\%last%_%%i.reg" (set "last=%last%_%%i" && goto :EOF)) goto :EOF
I am working on the problem 2 with all the findstr. instances. I pretty close but I have another problem I never got it right to solve. If I want to expand a variable which is part of a !! variable I don't know how the expand it. I need to resolve (get the data of): %section%_Line_!%section%_count! which "might result" in !%section%_Line_!%section%_count!! But double !!var!! does not work that way. I know this but never found a solution to it - any Idea? Current Version: Code: @echo off setlocal EnableDelayedExpansion set "filetoparse=%~dpnx1" REM parse registry file adding line number for /f "tokens=1* delims=:" %%a IN ('findstr.exe /n "^" "%filetoparse%"') do ( set "linenumber=%%a" set "regfileline=%%b" if "!regfileline:~0,3!"=="[HK" (call :loopprocess %%a %%b) if "!regfileline:~0,4!"=="[-HK" (call :delete) ) exit /b :loopprocess set "regkey=!regfileline!" set "tok=0" REM count tokens :loopprocess2 for /F "tokens=1* delims=[\]" %%G in ( "!regkey!" ) do ( if !tok! EQU 0 (set reg_path=%%H) REM echo !tok! %%G set /A "tok+=1" set regkey=%%H set last=%%G set section=%%G goto loopprocess2 ) call :CleanUpRegPath call :FolderCheckAndCreate call :CreateFile call :InitLoop call :ValueLoop goto :EOF :InitLoop set /a "%section%_Count=0" for /f "tokens=1* delims=:" %%S IN ('findstr.exe /n "^" "%filetoparse%"') do ( set /a "%section%_Count+=1" REM echo Count: !%last%_count! set "%section%_Line_!%section%_count!=%%S" set "%section%_LineValue_!%section%_count!=%%T" ) goto :EOF :ValueLoop set /a "linenumber+=1" echo Maxcount: !%section%_Count! echo "!%section%_Line_!%section%_count!!" echo "%section%_Line_!%section%_count!"=="!linenumber!" for /l %%i in (1 1 !%section%_Count!) do ( if "%section%_Line_!%section%_count!"=="!linenumber!" ( REM exit loop if next line is a registry key if "!section%_LineValue_!%section%_count:~0,3!"=="[HK" (goto :EOF) if "!section%_LineValue_!%section%_count:~0,4!"=="[-HK" (goto :EOF) REM print next line if line exist if defined %section%_LineValue_!%section%_count! ( REM echo !%Last%_linevalue! echo !%section%_LineValue_!%section%_count!!>>"%reg_export%" goto :ValueLoop ) ) goto :EOF :CleanUpRegPath set "reg_path=!reg_path:[=!" set "reg_path=!reg_path:]=!" set "reg_path=!reg_path:\%last%=!" goto :EOF :FolderCheckAndCreate set "RegFullPath=%~dp0!reg_path!" if not exist "%RegFullPath%" (mkdir "%RegFullPath%") goto :EOF :CreateFile set "reg_export=%RegFullPath%\%last%.reg" REM if exist "%reg_export%" (call :IncrementFileName "%last%") echo Windows Registry Editor Version 5.00>"!reg_export!" echo: >>"!reg_export!" echo !regfileline!>>"!reg_export!" goto :EOF
If I have the time today, and a full solution has not been posted, I will post how this can be done in PowerShell by just using regular expressions within a single loop process.
That would be great as this would be a nice challenge for me to learn from your code (have it side by side) I also would donate like 5-10$ via paypal to each of you or donate it to some NGO.
Pretty much done. Code: @echo off setlocal EnableDelayedExpansion set "filetoparse=%~dpnx1" REM shift the file into variables for /f "tokens=1* delims=:" %%a IN ('findstr.exe /n "^" "%filetoparse%"') do ( set /a "Count+=1" set "Line_!count!=%%a" set "LineValue_!count!=%%b" ) REM parse registry file adding line number for /f "tokens=1* delims=:" %%a IN ('findstr.exe /n "^" "%filetoparse%"') do ( set "linenumber=%%a" set "regfileline=%%b" if "!regfileline:~0,3!"=="[HK" (call :loopprocess) if "!regfileline:~0,4!"=="[-HK" (call :delete) ) echo Done exit /b :loopprocess set "regkeypath=!regfileline!" set "tok=0" REM count tokens :loopprocess2 for /F "tokens=1* delims=[\]" %%G in ( "!regkeypath!" ) do ( if !tok! EQU 0 (set reg_path=%%H) set /A "tok+=1" set regkeypath=%%H set lastregkeypath=%%G goto loopprocess2 ) call :CleanUpRegPath reg_path call :FolderCheckAndCreate reg_path call :CreateBaseFile call :RegValueLoop !linenumber! goto :EOF exit /b :RegValueLoop set /a "linenumber+=1" for /l %%i in (%~1 1 %Count%) do ( REM set "CurrentLine=" REM set "CurrentLineValue= if "!Line_%%i!" == "!linenumber!" ( REM exit loop if next line is a registry key if "!LineValue_%%i:~0,3!"=="[HK" (goto :EOF) if "!LineValue_%%i:~0,4!"=="[-HK" (goto :EOF) REM print next line if line exist if defined LineValue_%%i ( echo !LineValue_%%i!>>"%reg_export%" ) else ( echo.>>"%reg_export%" ) goto :RegValueLoop ) ) goto :EOF :CleanUpRegPath set "%~1=!%~1:[=!" set "%~1=!%~1:]=!" set "%~1=!%~1:\%lastregkeypath%=!" goto :EOF :FolderCheckAndCreate set "RegFullPath=%~dp0!%~1!" if not exist "%RegFullPath%" (mkdir "%RegFullPath%") goto :EOF :CreateBaseFile set "reg_export=%RegFullPath%\%lastregkeypath%.reg" REM if exist "%reg_export%" (call :IncrementFileName "%last%") echo Windows Registry Editor Version 5.00>"!reg_export!" echo. >>"!reg_export!" echo !LineValue_%linenumber%!>>"%reg_export%" goto :EOF
Increment file name "windows style" : name (1) name (2) etc... Code: :CreateBaseFile set "reg_export=%RegFullPath%\%lastregkeypath%.reg" if not exist "%reg_export%" ( call :Exportfile ) else ( call :IncrementFileName ) goto :EOF :IncrementFileName setlocal EnableDelayedExpansion set "baseName=%lastregkeypath% (" set "n=0" :Incrementloop for /f "delims=" %%F in ( '2^>nul dir /b /ad "%baseName%*)"^|findstr /xri /c:"%baseName%[0-9]*)"' ) do ( set "name=%%F" set "name=!name:*%baseName%=!" set "name=!name:)=!" echo !name! if !name! gtr !n! set "n=!name!" ) set /a n+=1 set "newregkeypath=%baseName%%n%" set "reg_export=%RegFullPath%\%newregkeypath%).reg" if exist "%reg_export%" ( goto :Incrementloop ) :Exportfile echo Windows Registry Editor Version 5.00>"!reg_export!" echo. >>"!reg_export!" echo !LineValue_%linenumber%!>>"%reg_export%" goto :EOF Full script with much less lines... Code: @echo off set "filetoparse=%~dpnx1" setlocal EnableDelayedExpansion for /f "tokens=1* delims=:" %%a IN ('findstr /n "^" "%filetoparse%"') do ( set "linenumber=%%a" set "regkey=%%b" if "!regkey:~0,3!"=="[HK" ( call :loopprocess ) if "!regkey:~0,4!"=="[-HK" ( call :delete ) ) <nul set /p DummyName=Done. timeout /t 2 /nobreak >nul 2>&1 exit /b :loopprocess set "var1=!regkey!" &set "var2=!regkey!" &set "tok=0" :loopprocess2 for /F "tokens=1* delims=[\]" %%G in ( "!var1!" ) do ( set /A "tok+=1" set "var1=%%H" goto :loopprocess2 ) for /F "tokens=%tok% delims=[\]" %%J in ( "!var2!" ) do ( set "lastregkeypath=%%J" ) set "RegFullPath=!regkey:HKEY_CURRENT_USER\=!" &set "RegFullPath=!RegFullPath:HKEY_LOCAL_MACHINE\=!" set "RegFullPath=!RegFullPath:HKCU\=!" &set "RegFullPath=!RegFullPath:HKLM\=!" set "RegFullPath=!RegFullPath:[=!" &set "RegFullPath=!RegFullPath:]=!" set "RegFullPath=!RegFullPath:%lastregkeypath%=!" set "RegFullPath=%~dp0!RegFullPath!" if not exist "%RegFullPath%" ( mkdir "%RegFullPath%" 2>nul ) set "reg_export=%RegFullPath%\%lastregkeypath%.reg" if exist "!reg_export!" ( call :IncrementFileName ) call :Exportfile :loopprocess3 set /a "linenumber+=1" for /f "tokens=1* delims=:" %%S IN ('findstr /n "^" "%filetoparse%"') do ( set "newlinenumber=%%S" set "linevalue=%%T" if "!newlinenumber!"=="!linenumber!" ( if "!linevalue:~0,3!"=="[HK" ( goto :eof ) if "!linevalue:~0,4!"=="[-HK" ( goto :eof ) if defined linevalue ( echo !linevalue!>>"!reg_export!" goto :loopprocess3 ))) goto :EOF :IncrementFileName set "baseName=%lastregkeypath% (" set "n=0" :Incrementloop for /f "delims=" %%F in ( '2^>nul dir /b /ad "%baseName%*)"^|findstr /xri /c:"%baseName%[0-9]*)"' ) do ( set "name=%%F" set "name=!name:*%baseName%=!" set "name=!name:)=!" echo !name! if !name! gtr !n! set "n=!name!" ) set /a n+=1 set "newregkeypath=%baseName%%n%" set "reg_export=%RegFullPath%\%newregkeypath%).reg" if exist "!reg_export!" ( goto :Incrementloop ) goto :EOF :Exportfile echo Windows Registry Editor Version 5.00>"!reg_export!" echo: >>"!reg_export!" echo !regkey!>>"!reg_export!" goto :EOF Just saw now your comment about the findstr thingy... We can maybe use skip to skip "n" lines, but don't know if would be faster, you'll have to make a for /f loop anyway. ok last one Code: @echo off set "filetoparse=%~dpnx1" setlocal EnableDelayedExpansion for /f "tokens=1* delims=:" %%a IN ('findstr /n "^" "%filetoparse%"') do ( set "linenumber=%%a" set "regfileline=%%b" if "!regfileline:~0,3!"=="[HK" ( call :loopprocess ) if "!regfileline:~0,4!"=="[-HK" ( call :delete ) ) <nul set /p DummyName=Done. timeout /t 2 /nobreak >nul 2>&1 exit /b :loopprocess set "var1=!regfileline!" &set "var2=!regfileline!" &set "tok=0" :loopprocess2 for /F "tokens=1* delims=[\]" %%G in ( "!var1!" ) do ( set /A "tok+=1" set "var1=%%H" goto :loopprocess2 ) for /F "tokens=%tok% delims=[\]" %%J in ( "!var2!" ) do ( set "lastregkeypath=%%J" ) set "RegFullPath=!regfileline:HKEY_CURRENT_USER\=!" &set "RegFullPath=!RegFullPath:HKEY_LOCAL_MACHINE\=!" set "RegFullPath=!RegFullPath:HKCU\=!" &set "RegFullPath=!RegFullPath:HKLM\=!" set "RegFullPath=!RegFullPath:[=!" &set "RegFullPath=!RegFullPath:]=!" set "RegFullPath=!RegFullPath:%lastregkeypath%=!" set "RegFullPath=%~dp0!RegFullPath!" if not exist "%RegFullPath%" ( mkdir "%RegFullPath%" 2>nul ) set "reg_export=%RegFullPath%\%lastregkeypath%.reg" if exist "!reg_export!" ( call :IncrementFileName ) call :Exportfile :loopprocess3 for /f "skip=%linenumber% usebackq delims=" %%S in ( "%filetoparse%" ) do ( set "linevalue=%%S" if "!linevalue:~0,3!"=="[HK" ( goto :eof ) if "!linevalue:~0,4!"=="[-HK" ( goto :eof ) if defined linevalue ( echo !linevalue!>>"!reg_export!" set /a "linenumber+=1" goto :loopprocess3 )) goto :EOF :IncrementFileName set "baseName=%lastregkeypath% (" set "n=0" :Incrementloop for /f "delims=" %%F in ( '2^>nul dir /b /ad "%baseName%*)"^|findstr /xri /c:"%baseName%[0-9]*)"' ) do ( set "name=%%F" set "name=!name:*%baseName%=!" set "name=!name:)=!" echo !name! if !name! gtr !n! set "n=!name!" ) set /a n+=1 set "newregkeypath=%baseName%%n%" set "reg_export=%RegFullPath%\%newregkeypath%).reg" if exist "!reg_export!" ( goto :Incrementloop ) goto :EOF :Exportfile echo Windows Registry Editor Version 5.00>"!reg_export!" echo: >>"!reg_export!" echo !regfileline!>>"!reg_export!" goto :EOF ps: I think you don't need to add a blank line, it should already add a CR at the end (unless you want the file to end with 2 blank lines) ps2: Later thought, to increment truely "Windows style" you can replace "n=0" with "n=1", as I think windows would not create "file (1)", but directly "file (2)".