xsdshi008 发表于 2021-4-7 18:05

(完善后重发)用脚本实现qpdf批量查找并解除pdf文件密码

qpdf(见:https://sourceforge.net/projects/qpdf/files/qpdf/)是免费的pdf解密工具,但其命令行方式使用起来不够方便,故在自用时写了个脚本实现qpdf批量查找并解密pdf文件,同时给出执行状态(运行后建立Success.log及Fail.log,备查)。

脚本功能:
查找加密的pdf文件,如可能则将其解密。

基本操作说明:
1.先将脚本qpdf.bat建立个快捷方式,并复制到操作方便的文件夹(目录),拖放待(查找)解密文件(夹)到快捷方式上,则将对该文件(夹)(含子文件夹)所有的pdf文件是否有加密进行检查,在无打开密码或确切知道打开密码的情况下,可移除打开密码(打开密码无法破解,请列示于open_passwd_list.txt文件中后可移除),只要能打开,则可移除编辑限制密码(只要能打开就无需知道其限制功能密码)
2.拖放非pdf文件到快捷方式上,功能同1。
3.拖放pdf文件到快捷方式上,则对该pdf文件(含子文件夹中同名文件)进行加密检查,其它功能同1。
4.移除密码后的文件名加添_Password_Removed标识,与原文件放置于同一文件夹,故需对该文件夹有读定权限。
5.脚本运行期间不得使用剪贴板,即不能有“剪切”、“复制”、“粘贴”(含对应的快捷方式)操作!!否则结果将不可预知!!!
6.脚本将忽略含特殊字符(如^、&、!、%、^等)的文件及路径, 这类文件(路径)不符合脚本批量处置的要求,请在DOS窗口使用命令行方式直接处置。
7.密码列表文件为open_passwd_list.txt,每行1个密码(这个要感谢网友“澹台无古”的有助)。
8.建议qpdf.bat、qpdf.exe、open_passwd_list.txt放在同一文件夹中,如果不是,qpdf.exe可将放置于“环境变量”%path%中。

小技巧:
把qpdf.bat快捷方式复制shell:sendto目录中(一般为C:\Users\用户名\AppData\Roaming\Microsoft\Windows\SendTo),右击目标后使用“发送到(N)”的操作最方便。


qpdf.bat文件列表如下:
::把以下文本内容复制到纯文本文件后,另存为qpdf.bat即可(如果在Win10中,请注重要保存为"ANSI"格式)
@echo off
setlocal
setlocal enableextensions enabledelayedexpansion
set start_time=%time:~0,8%
set "path0=%~dp0"
set "path0=%path0:"=%"
set "path0=%path0:~0,-1%"
set pt="%0"
set "pt=%pt:"=%"
call :Dir_split "%pt%" Dir_d Dir_p Dir_n Dir_x Dir_a Dir_f Dir_z Dir_t
set "work_path=%Dir_d%%Dir_p%"
set "work_path=%work_path:~0,-1%"
cd /d "%work_path%"
if "%work_path%"=="%path0%" set "path0="
set /a "n0=0"
set /a "n1=0"
set /a "n2=0"
set /a "n3=0"
set /a "n4=0"
set /a "n5=0"
set /a "n5e=0"
set /a "n6=0"
set /a "n6e=0"
set /a "n7=0"
set /a "n8=0"
set /a "n9=0"
set /a "n10=0"
set "Clip_Script=add-type -as System.Windows.Forms; ::GetText()"
set "path1=%HOMEDRIVE%%HOMEPATH%\Documents"
call :setDocumentsShellFolder DocumentsShellFolder
if defined DocumentsShellFolder (set "path1=%DocumentsShellFolder%")
set pt=%1
set pt="%pt%"
set "pt=%pt:"=%"
if not "%pt%" == "" goto next2
:next1
echo;
set /p pt= 请指定待解密的pdf文件(夹)(如:“%path1%\待解密文件.pdf”):
set pt="%pt%"
set "pt=%pt:"=%"
if "%pt%" == "" set "pt=%path1%"
:next2
set pt="%pt%"
set "pt=%pt:"=%"
call :Dir_split "%pt%" Dir_d Dir_p Dir_n Dir_x Dir_a Dir_f Dir_z Dir_t
if not defined Dir_a echo;&&echo;指定待解密的pdf文件"%pt%"不存在(或含本脚本不支持的字符,如^&、^^!、%%、^^^^等特殊字符)&&echo;请按任意键退出脚本&&goto next3
set "path1=%Dir_d%%Dir_p%"
if /i "%Dir_a:~0,1%"=="d" (set "path1=%Dir_f%")
if /i "%path1:~-1,1%"=="\" set "path1=%path1:~0,-1%"
set "pdfDir=%path1%"
if /i "%pdfDir:~-1,1%"==":" set "pdfDir=%pdfDir%\"
if not "%Dir_n%"=="" set Dir_n=%Dir_n:_Password_Removed=%
if /i "%Dir_a:~0,1%" == "d" (
set "pdfList=%Dir_f%\*.pdf"
set "pdfFilesName=*.pdf"
)
if /i not "%Dir_a:~0,1%"=="d" (
for %%i in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do call set Dir_x=!!Dir_x:%%i=%%i!!
if /i "!Dir_x!"==".pdf" (
set "pdfList=!Dir_d!!Dir_p!!Dir_n!!Dir_x!"
set "pdfFilesName=!Dir_n!.pdf"
)
if /i not "!Dir_x!"==".pdf" (
set "pdfList=!Dir_d!!Dir_p!*.pdf"
set "pdfFilesName=*.pdf"
)
)
if not exist "%pdfDir%" echo;&echo;指定的文件夹"%pdfDir%"不存在&echo;请按任意键退出脚本&goto next3
if /i "%Dir_x%"==".pdf" (
if not exist "%pdfList%" echo;&echo;指定的pdf文件"%pdfList%"不存在&echo;请按任意键退出脚本&goto next3
)
if defined path0 (set "Dir_i=%path0%\qpdf.exe") else (set "Check_T=0")
if defined path0 call :Check_File "%Dir_i%" Check_T
if %Check_T%==0 set "Dir_i=%path1%\qpdf.exe"
if %Check_T%==0 call :Check_File "%Dir_i%" Check_T
if %Check_T%==0 set "Dir_i=%work_path%\qpdf.exe"
if %Check_T%==0 call :Check_File "%Dir_i%" Check_T
if %Check_T%==0 set "Dir_i=%windir%\system32\qpdf.exe"
if %Check_T%==0 call :Check_File "%Dir_i%" Check_T
if %Check_T%==1 goto qpdf_check_Done
where qpdf.exe /Q
if /i not "%errorlevel%"=="0" echo “qpdf.exe”指令文件(应用程序)不在"%work_path%"目录及PATH环境变量指定的路径中,请先安装“qpdf.exe”应用程序后再试用( 详见 https://sourceforge.net/projects/qpdf/files/qpdf/ )&&echo;请按任意键退出脚本&&goto next3
set "Dir_i="
for /f "usebackq tokens=*" %%i in (`where qpdf.exe`) do (if not defined Dir_i set "Dir_i=%%i")
if defined Dir_i set "Check_T=1"
:qpdf_check_Done
set "qpdf_path=%Dir_i%"
if %Check_T%==0 echo;&&echo;解锁指令“qpdf.exe”不存在(或其路径含本脚本不支持的字符)&&echo;请按任意键退出脚本&&goto next3
if /i "%pdfDir:~-1,1%"=="\" (
set R_Su=%pdfDir%Success.log
set R_Fa=%pdfDir%Fail.log
) else (
set R_Su=%pdfDir%\Success.log
set R_Fa=%pdfDir%\Fail.log
)
echo 解锁指令:"%qpdf_path%" >"!R_Su!"
echo 解锁指令:"%qpdf_path%" >"!R_Fa!"
echo 工作目录:"%pdfDir%" >>"!R_Su!"
echo 工作目录:"%pdfDir%" >>"!R_Fa!"
set /a "passwd_list_file=0"
if defined path0 (set "Dir_i=%path0%\open_passwd_list.txt") else (set "Check_T=0")
if defined path0 call :Check_File "%Dir_i%" Check_T
if %Check_T%==0 set "Dir_i=%path1%\open_passwd_list.txt"
if %Check_T%==0 call :Check_File "%Dir_i%" Check_T
if %Check_T%==0 set "Dir_i=%work_path%\open_passwd_list.txt"
if %Check_T%==0 call :Check_File "%Dir_i%" Check_T
if %Check_T%==0 call :Dir_split "%qpdf_path%" Dir_d Dir_p Dir_n Dir_x Dir_a Dir_f Dir_z Dir_t
if %Check_T%==0 set "Dir_i=%Dir_d%%Dir_p%\open_passwd_list.txt"
if %Check_T%==0 call :Check_File "%Dir_i%" Check_T
set "passwd_file=%Dir_i%"
if %Check_T%==0 goto No_passwd_list_file
set /a "passwd_list_file=1"
set /A i=0
for /F "usebackq delims=" %%y in ("%passwd_file%") do (
      set /A i+=1
      ::call echo %%i%%
      call set u[%%i%%]=%%y
      call set nnn=%%i%%
)
:No_passwd_list_file
if %passwd_list_file% equ 1 (
echo 密码列表:"%passwd_file%">>"%R_Su%"
echo 密码列表:"%passwd_file%">>"%R_Fa%"
) else (
echo 不存密码列表文件:open_passwd_list.txt>>"%R_Su%"
echo 不存密码列表文件:open_passwd_list.txt>>"%R_Fa%"
)
echo 开始时间:%start_time% >>"%R_Su%"
echo 开始时间:%start_time% >>"%R_Fa%"
echo 成功移动编辑或打印限制密码的文件:>>"%R_Su%"
echo 密码移除失败的文件:>>"%R_Fa%"
echo;
echo;!注意!
echo;1.脚本运行期间不得使用剪贴板,
echo;即不能有“剪切”、“复制”、“粘贴”(含对应的快捷方式)操作!!
echo;否则结果将不可预知!!!
echo;
echo;2.脚本将忽略含特殊字符(如^&、^^!、%%、^^^^等)的文件(夹),
echo;这类文件不符合脚本批量处置的要求,请在DOS窗口使用命令行方式直接处置。
echo;
for /r "%pdfDir%" %%a in ("%pdfFilesName%") do (
set "p1=0"
set "error00=0"
set "error01=1"
set fpi="%%~fa"
set fpo="%%~da%%~pa%%~na_Password_Removed%%~xa"
if /i "!error00!"=="0" (
echo "%%~fa"|find.exe /i "&">Nul && ( set "error00=1"&&set /a "n6=!n6!+1" ) || ( set "error01=0" )
)
if /i "!error00!"=="0" (
echo "%%~fa"|find.exe /i "!">Nul && ( set "error00=1"&&set /a "n6=!n6!+1" ) || ( set "error01=0" )
)
if /i "!error00!"=="0" (
echo "%%~fa"|find.exe /i "%">Nul && ( set "error00=1"&&set /a "n6=!n6!+1" ) || ( set "error01=0" )
)
if /i "!error00!"=="0" (
echo "%%~fa"|find.exe /i "^">Nul && ( set "error00=1"&&set /a "n6=!n6!+1" ) || ( set "error01=0" )
)
if !n6! gtr !n6e! (set /a "n6e = !n6!" &&echo; 冲突:!fpi!&&echo;&&echo; 冲突:!fpi!>>"%R_Fa%")
if /i "!error00!"=="0" (
echo;"%%~fa"|find.exe /i "\Recovery\">Nul && ( set "error00=1"&&set /a "n5=!n5!+1" ) || ( set "error01=0" )
)
if /i "!error00!"=="0" (
echo;"%%~fa"|find.exe /i "\$Recycle.Bin\">Nul && ( set "error00=1"&&set /a "n5=!n5!+1" ) || ( set "error01=0" )
)
if /i "!error00!"=="0" (
echo;"%%~fa"|find.exe /i "_Password_Removed">Nul && ( set "error00=1"&&set /a "n5=!n5!+1" ) || ( set "error01=0" )
)
if !n5! gtr !n5e! (set /a "n5e = !n5!" &&echo; 忽略:!fpi!&&echo;&&echo; 忽略:!fpi!>>"%R_Fa%")
if /i "!error00!"=="0" (
set "fpi=!fpi:"=!"
set "fpo=!fpo:"=!"
)
if /i "!error00!"=="0" (
if not exist "!fpi!" (
set "error00=1"
set /a "n0=!n0!+1"
) else (
set /a "n9=!n9!+1"
echo 第 !n9! 个文件
echo 正在对 "!fpi!" 进行处置)
)
if /i "!error00!"=="0" (
call :Dir_split "!fpi!" Dir_err Dir_err Dir_err Dir_err Dir_a Dir_err Dir_err Dir_err
if /i "!Dir_a!"=="" set "error00=1"&&set /a "n5=!n5!+1"
)
if /i "!error00!"=="0" (
"%qpdf_path%" --show-encryption "!fpi!" 2>&1 |clip.exe
)
if /i "!error00!"=="0" (
powershell -sta "%Clip_Script%"|find.exe /i "No such file or directory">Nul && ( set "error00=1"&&set /a "n0=!n0!+1"&&set "p1=No such file or directory" ) || ( set "error01=0" )
)
if /i "!error00!"=="0" (
powershell -sta "%Clip_Script%"|find.exe /i "File is not encrypted">Nul && ( echo;       "!fpi!" 无密码。&&echo;&&set "error00=1"&&set /a "n1=!n1!+1"&&set "p1=File is not encrypted" ) || ( set "error01=0" )
)
if /i "!error00!"=="0" (
powershell -sta "%Clip_Script%"|find.exe /i "file is damaged">Nul && ( echo;       "!fpi!" 文件故障或损坏。&&echo;&&set "error00=1"&&set /a "n2=!n2!+1"&&set "p1=file is damaged" &&echo; 故障:"!fpi!">>"%R_Fa%") || ( set "error01=0" )
)
if /i "!error00!"=="0" (
powershell -sta "%Clip_Script%"|find.exe /i "invalid password">Nul && ( set "error00=0"&&set /a "n3=!n3!+1"&&set "p1=invalid password" ) || ( set "error01=0" )
)
if /i "!error00!"=="0" (
powershell -sta "%Clip_Script%"|find.exe /i "print high resolution">Nul && ( set "error00=0"&&set /a "n4=!n4!+1"&&set "p1=print high resolution" ) || ( set "error01=0" )
)
if /i "!p1!"=="invalid password" (
      if %passwd_list_file% equ 1 (
      set /a "po = 0"
      call set "Disp="
      for /L %%z in (1,1,%nnn%) do if "!po!" == "0" (
                call set ps=%%u[%%z]%%
                if not defined Disp (call set "Disp=1"&call echo;正尝试 "%passwd_file%" 给定的密码表,请耐心等候...)
                "%qpdf_path%" --password="!ps!" --decrypt "!fpi!" "!fpo!" >nul 2>&1
                if !errorlevel! equ 0 (set /a "po = 1")
      )
      if !errorlevel! equ 0 (set /a "n8=!n8!+1"&echo;经测试 "!fpi!" 的打开密码为:"!ps!",解密成功&echo;&echo "!fpi!" 的打开密码为:"!ps!">>"%R_Su%") else (set /a "n7=!n7!+1"&echo;       "!fpi!" 解密失败???&echo;&echo 需打开密码:"!fpi!">>"%R_Fa%")
      ) else (
      set /p ps= 请指定 "!fpi!" 打开密码: <nul
      echo;
      "%qpdf_path%" --password="!ps!" --decrypt "!fpi!" "!fpo!" >nul 2>&1
      if !errorlevel! equ 0 (set /a "n8=!n8!+1"&echo;       "!fpi!" 的打开密码为:"!ps!",解密成功&echo;&echo "!fpi!" 的打开密码为:"!ps!">>"%R_Su%") else (set /a "n7=!n7!+1"&echo;       "!fpi!" 解密失败???&echo;&echo 需打开密码:"!fpi!">>"%R_Fa%")))
if /i "!p1!"=="print high resolution" (
      "%qpdf_path%" --decrypt "!fpi!" "!fpo!"
      if !errorlevel! equ 0 (set /a "n8=!n8!+1"&echo;       "!fpi!" 解密成功&echo;&echo "!fpi!">>"%R_Su%") else (set /a "n7=!n7!+1"&echo;       "!fpi!" 解密失败???&echo;&echo "!fpi!">>"%R_Fa%"))
)
set /a "n10=%n9%+%n5%+%n6%"
echo;
echo;扫描有效文件数:%n9%
echo;
echo;成功解密文件数:%n8%
echo;
echo;带打开密码文件数:%n3%
echo;
echo;只限制编辑或打印文件数:%n4%
echo;
echo;解密操作失败文件数:%n7%
echo;
echo;解密检测时出现故障(或损坏)文件数:%n2%
echo;
echo;未加密文件数:%n1%
echo;
echo;被忽略(或无效或不存在)文件数:%n5%
echo;
echo;文件名与脚本特定字符(如^&、^^!、%%、^^^^等)冲突的文件数:%n6%
echo;
echo;不存在的文件(可能是“For”指令本身特性及脚本其它未知项引发而产生不存在文件名):%n0%
echo;
echo;总检测文件数(可能存在):%n10%
echo;
echo; >>"%R_Su%"
echo; >>"%R_Fa%"
echo;共扫描了%n9%个有效文件(可能共有%n10%个pdf文件) >>"%R_Su%"
echo;共扫描了%n9%个有效文件(可能共有%n10%个pdf文件) >>"%R_Fa%"
set /a startS=%start_time:~6,2%
set /a startM=%start_time:~3,2%
set /a startH=%start_time:~0,2%
set /a totalSs=%startS%+%startM%*60+%startH%*60*60
set end_time=%time:~0,8%
set /a endS=%end_time:~6,2%
set /a endM=%end_time:~3,2%
set /a endH=%end_time:~0,2%
set /a totalSe=%endS%+%endM%*60+%endH%*60*60
set /a diff_total_S=%totalSe%-%totalSs%
if %diff_total_S% lss 0 (set /a diff_total_S=24*60*60+%totalSe%-%totalSs%)
set /a diffH_=%diff_total_S% / 3600
set /a diffM_=%diff_total_S% %% 3600
set /a diffS_=%diffM_% %% 60
set /a diffM_=%diffM_% / 60
echo 开始时间:%start_time%
echo 完成时间:%end_time%
echo 耗时:%diffH_%小时 %diffM_%分钟 %diffS_%秒
echo 完成时间:%end_time% >>"%R_Su%"
echo 耗时:%diffH_%小时 %diffM_%分钟 %diffS_%秒 >>"%R_Su%"
echo 完成时间:%end_time% >>"%R_Fa%"
echo 耗时:%diffH_%小时 %diffM_%分钟 %diffS_%秒 >>"%R_Fa%"
echo;
endlocal
echo 执行完成,按任意键(建议按"空格键")退出......
pause>nul
exit /b
:next3
endlocal
pause>nul
exit /b
:Check_File %Dir_i% Check_T
setlocal ENABLEEXTENSIONS
set Dir_a=%~a1
if not defined Dir_a (set "a=0") else (if "%Dir_a:~0,1%"=="d" (set "a=0") else (set "a=1"))
endlocal&set %2=%a%&goto :EOF
:Dir_split %Dir_i% Dir_d Dir_p Dir_n Dir_x Dir_a Dir_fDir_z Dir_t
setlocal ENABLEEXTENSIONS
endlocal&set %2=%~d1&set %3=%~p1&set %4=%~n1&set %5=%~x1&set %6=%~a1&set %7=%~f1&set %8=%~z1&set %9=%~t1&goto :EOF
:setDocumentsShellFolder DocumentsShellFolder
setlocal EnableExtensions DisableDelayedExpansion
set "Reg32=%SystemRoot%\System32\reg.exe"
if defined ProgramFiles(x86) set "Reg32=%SystemRoot%\SysWOW64\reg.exe"
set "DocumentsShellFolder="
for /F "skip=1 tokens=1,2*" %%T in ('%Reg32% query "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" /v "Personal" 2^>nul') do (
    if /I "%%T" == "Personal" (
      set "DocumentsShellFolder=%%V"
    )
)
endlocal&set %1=%DocumentsShellFolder%&goto :EOF
endlocal
@echo on
exit /b
页: [1]
查看完整版本: (完善后重发)用脚本实现qpdf批量查找并解除pdf文件密码