2

I have a root folder C:\EncryptedFiles. There could be multiple subfolders. Each subfolder could have up to one file. No way of knowing before hand how many subfolders will be there. I need to iterate over each file, decrypt it and output in a separate folder the decrypted file with a file name matching the naming convention ParentDirectoryOfFile_YYYYMMDD.

Initially I was struggling with looping over to decrypt, but that was answered in this post:

set "ROOTDIR=C:\EncryptedFiles"
for /R %ROOTDIR% %%i in (*.gpg) do (
     gpg --batch --yes --passphrase mypassword --output "%%~dpni" --decrypt "%%~i"
)

In above code --output "%%~dpni" puts the output file (which has same name as input file, but without extension .gpg) in same folder. But I want all decrypted files to be stored in C:\DecryptedFiles with naming convention of ParentDirectoryOfFile_YYYYMMDD.

For example, I have this directory structure:

C:\EncryptedFiles
    \Folder1
        File1.csv.gpg
    \Folder2
        File2.csv.gpg

Current code will produce a final output as:

C:\EncryptedFiles
    \Folder1
        File1.csv.gpg
        File1.csv
    \Folder2
        File2.csv.gpg
        File2.csv

So it puts the decrypted files exactly where respective encrypted files were. However, what I want is that all decrypted files go into a separate folder (and leave C:\EncryptedFiles folder structure as is). I want the output to be like this:

C:\DecryptedFiles
      Folder1_20191119.csv
      Folder2_20191119.csv

I know the requirement may sound foolish, but that's how it is. Original names of encrypted files have no significance here. What folder they were originally put in is what identifies them.

So this is what I tried so far:

set "ROOTDIR=C:\EncryptedFiles"
set "DESTINATIONDIR=C:\DecryptedFiles"
for /R %ROOTDIR% %%i in (*.gpg) do (
    gpg --batch --yes --passphrase mypassword --output "%DESTINATIONDIR%\%%~ni_%date:~10,4%%date:~7,2%%date:~4,2%" --decrypt "%%~i"
)

The problem with above code is that %%~ni gives original file name, so I get following output:

C:\DecryptedFiles
    File1.csv_20191119.csv
    File2.csv_20191119.csv

Instead of that File1.csv and File2.csv parts, I want their parent directory's name to appear.

I understand that %%i contains the full path name of the encrypted file. I should somehow be able to extract immediate parent directory's name from it. There are some good discussions here: https://www.dostips.com/forum/viewtopic.php?t=2427, but when I try it, parent directory turns out to be blank.

Mofi
  • 46,139
  • 17
  • 80
  • 143
user2957592
  • 223
  • 2
  • 8

2 Answers2

1

I suggest following batch code for this task not using delayed expansion as not really needed and for that reason also working for files of which name or path contains one or more exclamation marks.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "RootDirectory=C:\EncryptedFiles"
set "DestinationDirectory=C:\DecryptedFiles"

if not exist "%DestinationDirectory%\" md "%DestinationDirectory%"
if not exist "%DestinationDirectory%\" (
    echo ERROR: Failed to create directory: "%DestinationDirectory%"
    echo(
    pause
    goto EndBatch
)

rem Get current date in format yyyyMMdd region independent.
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "FileNameDate=%%I"
set "FileNameDate=%FileNameDate:~0,8%"

for /R "%RootDirectory%" %%I in (*.csv.gpg) do for %%J in ("%%~dpI.") do gpg.exe --batch --yes --passphrase mypassword --output "%DestinationDirectory%\%%~nxJ_%FileNameDate%.csv" --decrypt "%%I"

:EndBatch
endlocal

Please read my answer on Why does %date% produce a different result in batch file executed as scheduled task? It explains very detailed the two command lines to get current date in format yyyyMMdd region independent.

For each non-hidden file found by the wildcard pattern *.csv.gpg in specified root directory or one of its subdirectories one more FOR is used to get just the name of the folder containing this file by referencing full path of the file ending always with a backslash and appending a dot to reference the directory itself. See the Microsoft documentation page Naming Files, Paths, and Namespaces.

The inner FOR determines the full qualified name of the folder containing the file which is %%~dpI without backslash at end. %%~nxJ references the string after last backslash which is the full name of the folder containing current encrypted file without path. It would be also possible to use just %%~nJ to reference the folder name if it is guaranteed that no folder contains ever a . in name which is unusual, but nevertheless possible.

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.

  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • md /?
  • pause /?
  • rem /?
  • set /?
  • setlocal /?
  • wmic /?
  • wmic os /?
  • wmic os get /?
  • wmic os get localdatetime /?
Mofi
  • 46,139
  • 17
  • 80
  • 143
0

This is not well tested.

setlocal enabledelayedexpansion
set "ROOTDIR=C:\EncryptedFiles"
set "DESTINATIONDIR=C:\DecryptedFiles"
for /R %ROOTDIR% %%i in (*.gpg) do (
   set "curfolder=%%~pi"
   for /f %%b in ('dir /ad /b "!curfolder:~0,-1!.*"') do (
      gpg --batch --yes --passphrase mypassword --output "%DESTINATIONDIR%\%%~b_%date:~10,4%%date:~7,2%%date:~4,2%" --decrypt "%%~i"
)

It is prone to having duplicate filenames if there are duplicate subfolder names in different folders.
It could have issues with any folders that include a period in the folder name.

avery_larry
  • 2,069
  • 1
  • 5
  • 17