我找到了下面的Powershell代码,该代码非常适合编辑多个Word文档,但是当文档受密码保护时,它会失败。
我知道密码(所有文件的密码都一样)。
我修改了第86行以传递密码变量(从用户请求 在脚本的前面)。
086函数processDoc($ pass){
第87行然后使用我理解的变量(可能是错误的)将其用作correct format。
087 $ doc = $ word.Documents.Open($ _。FullName,$ null,$ false,$ null,$ pass,$ null,$ null,$ pass)
我调用传递密码变量的第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()
答案 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