批量给未加密的word、Excel、rar、zip、pdf文件加密
前阵子对接的某个厂家被甲方的红队攻破了,底裤给都掀了。并且还波及到我们了,因为有一份我们系统的接入规范文件(word)在被攻破的服务器上,然后顺着文档里面写的几个ip地址继续渗透了。
我有些焦虑,想着把工作相关的文档文件都给加密上。
2025年06月24日更新:找到更全面的方式来确认docx、xlsx文档是否加密了,同时更新一下关于日志输出的逻辑
加密word
仅限于windows平台,并且必须要有office环境,wps不行。
<# 该脚本的一些细节只适合我的工作电脑,我的工作电脑只能正常安装使用office 2010,但是PowerShell不能正确的创建Word.Application对象,然后我安装了office 2019(但是只能安装,无法正常使用); 所以,我实际上在使用office 2019的DLL对象来生成能正常在office 2010中使用的docx文档。 #> # 指定目录 $root_path = "D:\temp" $word = New-Object -ComObject Word.Application $word.Visible =$false # 指定密码 #$password = 'Scsgcc12#$56_wordDocx' # 特殊字符$不可以使用 $password = 'ScsgccDocx1@3$5' #目前测试出,密码长度要小于16位,否则加密文档无论如何都打不开 # 日志 $date_now = Get-Date -Format 'yyyy年MM月dd日' $log_dir_path = Join-Path $root_path $date_now New-Item -Path $log_dir_path -ItemType Directory -Force > $null $log_out_file = Join-Path $log_dir_path 'word文档加密_日志信息.txt' $log_info="" # 计数 $file_num=0 $word_files=Get-ChildItem -LiteralPath $root_path -Recurse -Filter *.doc? try{ $word_files|ForEach-Object{ $file_num+=1 if($file_num % 1000 -eq 0){ $log_info >> $log_out_file $log_info="" } $log_info+="信息:$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - 正在处理 $($_.FullName) 文档。`n" $document=$null if($_.Extension -eq '.doc'){ try{ # 保存三个时间值 $CreationTime=$_.CreationTime $LastWriteTime=$_.LastWriteTime $LastAccessTime=$_.LastAccessTime # 转换为docx并加密,然后删除doc文件 $document = $word.Documents.Open($_.FullName,$false,$true) # $document = $word.Documents.Open($_.FullName,$false,$true,$false,$null,$null,$false,$null,$null,$null,$null,$null,$true) # 更改后缀 $out_path = [System.IO.Path]::ChangeExtension($_.FullName, "docx") $document.SaveAs($out_path, 16, $null,$password) $document.Close() Remove-Item -LiteralPath $_.FullName -Force -Recurse #更新时间值 $new_word_file_obj = Get-ChildItem -LiteralPath $out_path $new_word_file_obj.CreationTime = $CreationTime $new_word_file_obj.LastWriteTime = $LastWriteTime $new_word_file_obj.LastAccessTime = $LastAccessTime $log_info+="信息:$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - 已将 $($_.FullName) 转换为 $out_path 并加密。`n" } catch{ if($document){ $document.Close() } New-Item -Path $path -ItemType Directory -Force > $null $log_info+="错误:$(Get-Date -Format "yyyy-MM-dd HH:mm:ss")`n" $log_info >> $log_out_file $log_info="" $_ >> $log_out_file } finally{ # 释放 COM 对象 if ($document) { [System.Runtime.InteropServices.Marshal]::ReleaseComObject($document) | Out-Null $document = $null } } } elseif($_.Extension -eq '.docx'){ # 检查其是否加密,若是加密,则忽略,若是未加密,则加密 try{ $is_encrypt_1 = Select-String -LiteralPath $_.FullName -Quiet -SimpleMatch -Pattern 'http://schemas.microsoft.com/office/2006/keyEncryptor/password' $is_encrypt_2 = Select-String -Pattern "M.i.c.r.o.s.o.f.t. .E.n.h.a.n.c.e.d. .R.S.A. .a.n.d. .A.E.S. .C.r.y.p.t.o.g.r.a.p.h.i.c. .P.r.o.v.i.d.e.r" -Path $_.FullName -Quiet $is_encrypt = $is_encrypt_1 -or $is_encrypt_2 if(-not $is_encrypt){ # 保存三个时间值 $CreationTime=$_.CreationTime $LastWriteTime=$_.LastWriteTime $LastAccessTime=$_.LastAccessTime # 加密 $document = $word.Documents.Open($_.FullName,$false,$true
) $out_path = $_.FullName + 'x' $document.SaveAs($out_path, 16, $null, $password) $document.Close($false) Remove-Item -LiteralPath $_.FullName -Force Rename-Item -LiteralPath $out_path -NewName $_.FullName #更新时间值 $new_word_file_obj = Get-ChildItem -LiteralPath $_.FullName $new_word_file_obj.CreationTime = $CreationTime $new_word_file_obj.LastWriteTime = $LastWriteTime $new_word_file_obj.LastAccessTime = $LastAccessTime $log_info+="信息:$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - 已将 $($_.FullName) 加密。`n" } } catch{ if($document){ $document.Close($false) } $log_info+="错误:$(Get-Date -Format "yyyy-MM-dd HH:mm:ss")`n" $log_info >> $log_out_file $log_info="" $_ >> $log_out_file } finally{ # 释放 COM 对象 if ($document) { [System.Runtime.InteropServices.Marshal]::ReleaseComObject($document) | Out-Null $document = $null } } } } } catch{ $log_info+="错误:$(Get-Date -Format "yyyy-MM-dd HH:mm:ss")`n" $log_info >> $log_out_file $log_info="" $_ >> $log_out_file } finally{ if($word){ $word.Quit() [System.Runtime.InteropServices.Marshal]::ReleaseComObject($word) | Out-Null } [System.GC]::Collect() [System.GC]::WaitForPendingFinalizers() $log_info+="信息:$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - 已完成将 $root_path 目录下的word文档加密。`n" $log_info>> $log_out_file }
然后借助任务计划程序,可以实现每天自动执行。
加密Excel
仅限于windows平台,并且必须要有office环境,wps不行。
<# 该脚本的一些细节只适合我的工作电脑,我的工作电脑只能正常安装使用office 2010,但是PowerShell不能正确的创建Word.Application对象,然后我安装了office 2019(但是只能安装,无法正常使用); 所以,我实际上在使用office 2019的DLL对象来生成能正常在office 2010中使用的docx文档。 #> # 指定目录 $root_path = "D:\temp" # 指定秘密 $excel_password = 'Scsgcc!2#4%Xlsx' # Excel 加密密码 $excel_files = Get-ChildItem $root_path -Recurse -Filter *.xls? # 日志 $date_now = Get-Date -Format 'yyyy年MM月dd日' $log_dir_path = Join-Path $root_path $date_now New-Item -Path $log_dir_path -ItemType Directory -Force > $null $log_out_file = Join-Path $log_dir_path 'excel文档加密_日志信息.txt' $log_info="" # 计数 $file_num=0 try { # 创建 Excel COM 对象 $excel = New-Object -ComObject Excel.Application $excel.Visible = $false $excel.DisplayAlerts = $false # 禁用警告弹窗 $excel_files | ForEach-Object { $file_num+=1 if($file_num % 1000 -eq 0){ $log_info >> $log_out_file $log_info="" } $workbook = $null $excel_file_path = $_.FullName $log_info+="信息:$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - 正在处理 $($_.FullName) 文档。`n" try { if ($_.Extension -eq '.xls') { # 处理旧版 .xls 文件(转换为 .xlsx 并加密) $CreationTime = $_.CreationTime $LastWriteTime = $_.LastWriteTime $LastAccessTime = $_.LastAccessTime $workbook = $excel.Workbooks.Open($_.FullName) $out_path = [System.IO.Path]::ChangeExtension($_.FullName, "xlsx") $workbook.SaveAs($out_path, 51, $excel_password) # 51 = xlsx 格式 $workbook.Close($false) # 恢复时间属性并删除原文件 $newFile = Get-Item -LiteralPath $out_path $newFile.CreationTime = $CreationTime $newFile.LastWriteTime = $LastWriteTime $newFile.LastAccessTime = $LastAccessTime Remove-Item -LiteralPath $_.FullName -Force $log_info+="信息:$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - 已将 $($_.FullName) 转换为 $out_path 并加密。`n" } elseif ($_.Extension -eq '.xlsx') { # 检查是否已加密 $is_encrypt_1 = Select-String -LiteralPath $_.FullName -Quiet -SimpleMatch -Pattern 'http://schemas.microsoft.com/office/2006/keyEncryptor/password' $is_encrypt_2 = Select-String -Pattern "M.i.c.r.o.s.o.f.t. .E.n.h.a.n.c.e.d. .R.S.A. .a.n.d. .A.E.S. .C.r.y.p.t.o.g.r.a.p.h.i.c. .P.r.o.v.i.d.e.r" -Path $_.FullName -Quiet $is_encrypt = $is_encrypt_1 -or $is_encrypt_2 if (-not $is_encrypt) { # 加密现有 .xlsx 文件 $CreationTime = $_.CreationTime $LastWriteTime = $_.LastWriteTime $LastAccessTime = $_.LastAccessTime $workbook = $excel.Workbooks.Open($_.FullName) $temp_path = [System.IO.Path]::GetTempFileName() + ".xlsx" $workbook.SaveAs($temp_path, 51, $excel_password) # 51 = xlsx 格式 $workbook.Close($false) # 替换原文件并恢复时间属性 Remove-Item -LiteralPath $_.FullName -Force Move-Item -LiteralPath $temp_path -Destination $_.FullName -Force $newFile = Get-Item -LiteralPath $_.FullName $newFile.CreationTime = $CreationTime $newFile.LastWriteTime = $LastWriteTime $newFile.LastAccessTime = $LastAccessTime $log_info+="信息:$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - 已将 $($_.FullName) 加密。`n" } } } catch { if ($workbook) { $workbook.Close($false) } $log_info+="错误:$(Get-Date -Format "yyyy-MM-dd HH:mm:ss")`n" $log_info>> $log_out_file $log_info="" $_ >> $log_out_file } finally { if ($workbook) { [System.Runtime.InteropServices.Marshal]::ReleaseComObject($workbook) | Out-Null $workbook = $null } } } } catch { $log_info+="错误:$(Get-Date -Format "yyyy-MM-dd HH:mm:ss")`n" $log_info>> $log_out_file $log_info="" $_ >> $log_out_file } finally { if ($excel) { $excel.Quit() [System.Runtime.InteropServices.Marshal]::ReleaseComObject($excel) | Out-Null $excel = $null } [System.GC]::Collect() [System.GC]::WaitForPendingFinalizers() $log_info >> $log_out_file "信息:$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - 已完成将 $root_path 目录下的Excel文档加密。" >> $log_out_file }
加密PDF
由于没有原生的pdf dll,所以这里使用了Python来实现。
1 # 需先安装 Python 和 PyPDF2:pip install PyPDF2 2 from PyPDF2 import PdfWriter, PdfReader 3 import os,sys,win32file,pywintypes,ctypes 4 def is_pdf_encrypted(file_path:str)->bool: 5 ''' 6 检查是否加密 7 ''' 8 try: 9 with open(file_path, "rb") as f: 10 reader = PdfReader(f) 11 # 如果加密,尝试用空密码解密(不会修改文件) 12 if reader.is_encrypted: 13 return True 14 return False 15 except Exception as e: 16 print(f"检测失败: {e}") 17 return False 18 19 def 设置打开密码并替换文件(file_path:str,pw:str): 20 writer = PdfWriter() 21 reader = PdfReader(file_path) 22 for page in reader.pages: 23 writer.add_page(page) 24 writer.encrypt(pw) 25 new_pdf_path = os.path.join(os.path.dirname(file_path),os.path.basename(file_path))+'.tmp' 26 with open(new_pdf_path, "wb") as f: 27 writer.write(f) 28 # 获取时间 29 st = os.stat(file_path) 30 # 修改时间 (Last Modified Time) 31 mtime = st.st_mtime 32 # 访问时间 (Last Access Time) 33 atime = st.st_atime 34 # 创建时间 (Creation Time,仅Windows有效) 35 if os.name == 'nt': 36 ctime = st.st_ctime 37 else: 38 ctime = None # Linux/Mac 无创建时间概念 39 # 修改时间 40 os.utime(new_pdf_path, (atime, mtime)) 41 #将时间戳转换为 Windows 的 FILETIME 格式 42 ft = pywintypes.Time(ctime) 43 handle = win32file.CreateFile( 44 new_pdf_path, 45 win32file.GENERIC_WRITE, 46 0, None, 47 win32file.OPEN_EXISTING, 48 0, None 49 ) 50 win32file.SetFileTime(handle, ft, None, None) 51 handle.Close() 52 # 清理文件的特殊属性,比如只读,删除只读文件会被拒绝 53 SetFileAttributes = ctypes.windll.kernel32.SetFileAttributesW 54 FILE_ATTRIBUTE_NORMAL = 0x80 55 SetFileAttributes(file_path, FILE_ATTRIBUTE_NORMAL) 56 #删除源文件 57 os.remove(file_path) 58 # 重命名加密之后的pdf文件 59 while True: 60 try: 61 os.rename(new_pdf_path,file_path) 62 break 63 except Exception as e: 64 time.sleep(1) 65 pass; 66 def process_pdfs_in_directory(root_dir): 67 # 遍历目录及子目录 68 pdf_list=[] 69 for root, dirs, files in os.walk(root_dir): 70 for file in files: 71 if file.lower().endswith('.pdf'): 72 file_path = os.path.join(root, file) 73 pdf_list.append(file_path) 74 return pdf_list; 75 def main(root_path:str,pw:str): 76 pdf_list=process_pdfs_in_directory(root_path) 77 for pdf_path in pdf_list: 78 if(not is_pdf_encrypted(pdf_path)): 79 print(f'开始加密:【{pdf_path}】。') 80 设置打开密码并替换文件(pdf_path,pw); 81 if __name__ == "__main__": 82 root_path = r'D:\temp' 83 pw='1234567890' 84 main(root_path,pw)
加密rar、zip文件
强依赖WinRAR软件,原则上这份代码稍加修改就可以匹配更多类型的压缩文件。
1 # 根路径 2 $root_path="D:\temp" 3 # 密码 4 $password = '1234567890' 5 6 $winrarPath = "C:\Program Files (x86)\WinRAR\WinRAR.exe" 7 $rar_zip_files = Get-ChildItem -Path $root_path -Include *.rar, *.zip -File -Recurse # 不能使用LiteralPath参数 8 foreach($file in $rar_zip_files){ 9 #$dst_dir=Join-Path $file.DirectoryName -ChildPath $file.BaseName 10 $dst_dir=Join-Path $env:TEMP -ChildPath $file.BaseName 11 New-Item -ItemType Directory -Path $dst_dir -Force > $null 12 13 # Start-Process -FilePath "$env:comspec" -ArgumentList "/c","dir","`"%SystemDrive%\Program Files`"" 14 # WinRAR.exe x $file (Join-Path $dst_dir '\') -p111 -Y 15 $t=Join-Path $dst_dir '\' 16 $ArgumentList = "x `"$file`" `"$t`" -p111 -Y" 17 $p=Start-Process -FilePath $winrarPath -ArgumentList $ArgumentList -Wait -PassThru 18 $source_file_obj_CreationTime=$file.CreationTime 19 $source_file_obj_LastAccessTime=$file.LastAccessTime 20 $source_file_obj_LastWriteTime=$file.LastWriteTime 21 if($p.ExitCode -eq 1 -or $p.ExitCode -eq 0){ 22 # 解压缩成功,说明没有设置密码" 23 "解压缩:【$($file.FullName)】到【$t】成功。" 24 25 # 检查目录是否嵌套了 26 $嵌套_路径 = Join-Path $dst_dir -ChildPath $file.BaseName 27 $tt = Get-ChildItem $嵌套_路径 2>&1 $null 28 if($?){ 29 # 存在嵌套目录,需要移动并覆盖 30 Move-Item -Path ($嵌套_路径+'/*') -Destination $dst_dir -Force 31 "移动文件【$嵌套_路径】到【$dst_dir】" 32 Remove-Item $嵌套_路径 -Force -ErrorAction SilentlyContinue -Recurse 33 "删除空文件夹【$嵌套_路径】。" 34 } 35 $source_file_obj = $file 36 $hp = '-hp' + $password 37 <# 原先是直接在当前路径操作的,后续改为了在$temp目录操作,就不需要这个判定了 38 if($source_file_obj.fullname -eq $source_file_obj.FullName){ 39 Remove-Item -LiteralPath $source_file_obj.FullName -Force -Recurse 40 "删除路径:【$($source_file_obj.FullName)】。" 41 } 42 #> 43 Remove-Item -LiteralPath $source_file_obj.FullName -Force -Recurse 44 "删除路径:【$($source_file_obj.FullName)】。" 45 # 控制台 RAR 不能创建 ZIP 压缩文件。 46 $rar_path = [System.IO.Path]::ChangeExtension($source_file_obj.FullName, "rar") 47 $ArgumentList = "a `"$rar_path`" `"$dst_dir`" -ep1 -df $hp" 48 $p=Start-Process -FilePath $winrarPath -ArgumentList $ArgumentList -Wait -PassThru 49 if($p.ExitCode -eq 1 -or $p.ExitCode -eq 0){ 50 "压缩:【$dst_dir】成功。" 51 $new_rar_file_obj = Get-ChildItem $rar_path 52 #恢复时间属性 53 $new_rar_file_obj.CreationTime = $source_file_obj_CreationTime 54 $new_rar_file_obj.LastAccessTime = $source_file_obj_LastAccessTime 55 $new_rar_file_obj.LastWriteTime = $source_file_obj_LastWriteTime 56 # 移动文件到原来的位置 57 if($new_rar_file_obj.FullName -ne $file.FullName){ 58 Move-Item -LiteralPath $new_rar_file_obj.FullName -Destination $file.FullName -Force 59 "移动文件:$($new_rar_file_obj.FullName) 到 $($file.FullName) 。" 60 } 61 } 62 } 63 elseif($p.ExitCode -eq 11){ 64 Get-ChildItem -Path $dst_dir 2> $null 65 if($?){ 66 # 目标目录存在,需要删除 67 Remove-Item -Path $dst_dir -Force -Recurse 68 "删除目录:【$dst_dir】。" 69 } 70 } 71 "" 72 }
没有实时检测的方案,实时的就需要人有这样的意识。
浙公网安备 33010602011771号