Powershell编辑多个受密码保护的Word文件

时间:2018-06-28 13:10:15

标签: powershell ms-word

我找到了下面的Powershell代码,该代码非常适合编辑多个Word文档,但是当文档受密码保护时,它会失败。

  1. 我知道密码(所有文件的密码都一样)。

  2. 我修改了第86行以传递密码变量(从用户请求 在脚本的前面)。

    086函数processDoc($ pass){

  3. 第87行然后使用我理解的变量(可能是错误的)将其用作correct format

    087 $ doc = $ word.Documents.Open($ _。FullName,$ null,$ false,$ null,$ pass,$ null,$ null,$ pass)

  4. 我调用传递密码变量的第96行。

    096 $ countr = processDoc($ passwd)

它不起作用,我也不知道为什么。我不是程序员,所以可能会做一些愚蠢的事情。

有人可以建议吗?我期待着屈尊的评论:-)

001 # Find and replace in multiple word docs
002 # Usage: Open in ISE, update the $folderPath, change the find/replace fields in the $textToReplace array, click the run button.
003 
004 $folderPath = "C:\Users\tim.handy\Desktop\testchangecontentsword\STANDARD  DATA - Copy\CHEMICAL\ANALYSIS\01 Pre-treatment incl strippers\*" # multi-folders: "C:\fso1*", "C:\fso2*"
005 $fileType = "*.doc"           # *.doc will take all .doc* files, i.e .docx also
006 $passwd = Read-Host("Type in the password:")
007 
008 $textToReplace = @{
009 # "TextToFind" = "TextToReplaceWith" and it's case sensitive.
010 "Bath 01800" = "yay"
011 }
012 
013 $word = New-Object -ComObject Word.Application
014 $word.Visible = $false
015 
016 #region Find/Replace parameters
017 $matchCase = $true
018 $matchWholeWord = $true
019 $matchWildcards = $false
020 $matchSoundsLike = $false
021 $matchAllWordForms = $false
022 $forward = $true
023 $findWrap = [Microsoft.Office.Interop.Word.WdFindWrap]::wdFindContinue
024 $format = $false
025 $replace = [Microsoft.Office.Interop.Word.WdReplace]::wdReplaceOne
026 #endregion
027 
028 $countf = 0 #count files
029 $countr = 0 #count replacements per file
030 $counta = 0 #count all replacements
031 
032 Function findAndReplace($objFind, $FindText, $ReplaceWith) {
033     #simple Find and Replace to execute on a Find object
034     #we let the function return (True/False) to count the replacements
035     $objFind.Execute($FindText, $matchCase, $matchWholeWord, $matchWildCards, $matchSoundsLike, $matchAllWordForms, $forward, $findWrap, $format, $ReplaceWith, $replace) #> $null
036 }
037 
038 Function findAndReplaceAll($objFind, $FindText, $ReplaceWith) {
039     #make sure we replace all occurrences (while we find a match)
040     $count = 0
041     $count += findAndReplace $objFind $FindText $ReplaceWith
042     While ($objFind.Found) {
043         $count += findAndReplace $objFind $FindText $ReplaceWith
044     }
045     return $count
046 }
047 
048 Function findAndReplaceMultiple($objFind, $lookupTable) {
049     #apply multiple Find and Replace on the same Find object
050     $count = 0
051     $lookupTable.GetEnumerator() | ForEach-Object {
052         $count += findAndReplaceAll $objFind $_.Key $_.Value
053     }
054     return $count
055 }
056 
057 Function findAndReplaceWholeDoc($Document, $lookupTable) {
058     $count = 0
059     # Loop through each StoryRange
060     ForEach ($storyRge in $Document.StoryRanges) {
061         Do {
062             $count += findAndReplaceMultiple $storyRge.Find $lookupTable
063             #check for linked Ranges
064             $storyRge = $storyRge.NextStoryRange
065         } Until (!$storyRge) #null is False
066 
067     }
068     #region Loop through Shapes within Headers and Footers
069     # https://msdn.microsoft.com/en-us/vba/word-vba/articles/shapes-object-word
070     # "The Count property for this collection in a document returns the number of items in the main story only.
071     #  To count the shapes in all the headers and footers, use the Shapes collection with any HeaderFooter object."
072     # Hence the .Sections.Item(1).Headers.Item(1) which should be able to collect all Shapes, without the need
073     # for looping through each Section.
074     #endregion
075     $shapes = $Document.Sections.Item(1).Headers.Item(1).Shapes
076     If ($shapes.Count) {
077         #ForEach ($shape in $shapes | Where {$_.TextFrame.HasText -eq -1}) {
078         ForEach ($shape in $shapes | Where {[bool]$_.TextFrame.HasText}) {
079             #Write-Host $($shape.TextFrame.HasText)
080             $count += findAndReplaceMultiple $shape.TextFrame.TextRange.Find $lookupTable
081         }
082     }
083     return $count
084 }
085 
086 Function processDoc ($pass) {
087     $doc = $word.Documents.Open($_.FullName, $null, $false, $null, $pass, $null, $null, $pass)
088     $count = findAndReplaceWholeDoc $doc $textToReplace
089     $doc.Close([ref]$true)
090     return $count
091 }
092 
093 $sw = [Diagnostics.Stopwatch]::StartNew()
094 Get-ChildItem -Path $folderPath -Recurse -Filter $fileType | ForEach-Object { 
095   Write-Host "Processing \`"$($_.Name)\`"..."
096   $countr = processDoc($passwd)
097   Write-Host "$countr replacements made."
098   $counta += $countr
099   $countf++
100 }
101 $sw.Stop()
102 $elapsed = $sw.Elapsed.toString()
103 Write-Host "`nDone. $countf files processed in $elapsed"
104 Write-Host "$counta replacements made in total."
105 
106 $word.Quit()
107 $word = $null
108 [gc]::collect() 
109 [gc]::WaitForPendingFinalizers()

1 个答案:

答案 0 :(得分:0)

这就是解决方案...

Function processDoc {
$doc = $word.Documents.Open($_.FullName)

# I added this bit
# https://msdn.microsoft.com/en-us/vba/word-vba/articles/document-unprotect-method-word
# Check for file protection
If ($doc.ProtectionType -and ($doc.ProtectionType -ne 'wdNoProtection') ) {
    # Unprotect file with password
    if ($doc.Unprotect) {
        $doc.Unprotect($FilePassword)
    } 
} 

$count = findAndReplaceWholeDoc $doc $textToReplace

# I added this bit
# Reprotect file with 'wdAllowOnlyReading'
# https://msdn.microsoft.com/en-us/vba/word-vba/articles/wdprotectiontype-enumeration-word
$doc.Protect(3, $null, $FilePassword)

$doc.Close([ref]$true)
return $count

}

感谢@cindymeister