【PowerShell】Excel_Word_文字置換プログラム作成_Replace

Excel

ad2

【PowerShell】Excel_Word_文字置換プログラム作成_Replace

多数のExcelやWordで文字置換したい

業務で帳票類やエビデンス、社内情報のExcelファイルが大量にある中で、会社名が変更されるとか名称が変更されるなどのタイミングで全部のExcelファイルを変更しなければならない業務が降ってきます。

一つ一つファイルを開いて、文字変更して、保存して閉じる。

の繰り返し作業を延々とやり続けなければなりません。

「文字列を一括で変更できないか。」

それでは、PowerShellで作成してみようと思い、作成しましたので、ご紹介します。

ご自由に参考にしてくれれば、幸いです。

Powershell実行ファイルps1

では、早速ですが、ソースコードを載せます。

<# Excel_Word_Replace.ps1  対象フォルダ名  [検索文字列]  [置換文字列]#>
param([String]$Dir,
      [String]$OldStr = "あいうABC123",
      [String]$NewStr = "日本Japan!!★"
)

#-----------Function-------------
Function Replace {
    [CmdletBinding(PositionalBinding=$False)]
    param([parameter(Position=0)][String]$Dir,
          [parameter(Position=1)][String]$OldStr,
          [parameter(Position=2)][String]$NewStr,
          [Alias("s")][String]$sheet  = "*",  #シートの名前。全シートを対象とする場合は "*"
          [Alias("r")][String]$range  = "*",  #セルの範囲("A1:C4"など).全セルを対象とする場合は "*"
          [Alias("a")][Int]$LookAt    = 2,    #セル内容が完全に同一であるものを検索  1:する 2:しない
          [Alias("c")][Int]$MatchCase = 0,    #大文字と小文字の区別  0:しない 1:する
          [Alias("b")][Int]$MatchByte = 0     #半角と全角の区別      0:しない 1:する
    )

    if (-not $Dir) { 
        Write-Host "対象フォルダが指定されていません。処理を終了します。" -Fore Red
        return
    } 

    if (-not (Test-Path -LiteralPath $Dir -PathType Container)) { 
        Write-Host "対象フォルダがありません。処理を終了します。" -Fore Red
        return
    } 

    $srcdir = Convert-Path -LiteralPath $Dir
    $dstdir = $srcdir + "_new"

    if (Test-Path -LiteralPath $dstdir) {
        Write-Host "$($dstdir)が上書きされます。続行しますか。y/n [n]:" -Fore Yellow -NoNewline
        $answer = ""
        try { $answer = (Read-Host).Trim().ToUpper() } catch {}
        switch ($answer) {
            "y" { Remove-Item -LiteralPath $dstdir -Recurse -Force }
            default { Write-Host "処理を終了します。" -Fore Red; return }
        }
    }
    New-Item $dstdir -ItemType Directory | Out-Null

    Add-Type -AssemblyName Microsoft.Office.Interop.Excel

    Write-Host "Excelファイル処理を開始します。"

    try {
        $excel = New-Object -ComObject Excel.Application
        $excel.Visible = $false
        $excel.DisplayAlerts = $false
        $xlFomulas = [Microsoft.Office.Interop.Excel.XlFindLookIn]::xlFormulas
        #$xlValues  = [Microsoft.Office.Interop.Excel.XlFindLookIn]::xlValues
        $default = [Type]::Missing
        $num_files = 0
        #$shape = [Microsoft.Office.Interop.Excel.Shape]::shape

        #フィルターした全てのファイルに対して1ファイルずつ
        Get-ChildItem -LiteralPath $srcdir -Filter "*.xls*" -Recurse | % {
            $srcfile = $_.FullName
            Write-Host "$srcfile : " -NoNewline
            $workbook = $excel.Workbooks.Open($srcfile)
            $found = $false

            #ExceSheet 1シートずつ
            $workbook.Sheets | % {
                $worksheet = $_
                if ($sheet -ne "*" -and $sheet -ne $worksheet.Name) { Return }
                if ($range -eq "*") { 
                    $range1 = $worksheet.Cells
                    $shape1 = $worksheet.Shapes
                    $pagesetup1 = $worksheet.pageSetup
                } else {
                    $range1 = $worksheet.Range($range)
                }
                
                #セル全体検索Find
                $result = $range1.Find($OldStr,     # What
                                       $default,    # After
                                       $xlFomulas,  # LookIn
                                       $LookAt,     # LookAt
                                       $default,    # SearthOrder
                                       $default,    # SearchDirection
                                       $matchCase,  # MatchCase
                                       $matchByte,  # MatchByte
                                       $default     # SearchFormat
                                      )

                if ($result) {
                    $found = $true
                    #セル全体置換Replace
                    $range1.Replace($OldStr,     # What
                                    $NewStr,     # Replacement
                                    $LookAt,     # LookAt
                                    $default,    # SearthOrder
                                    $matchCase,  # MatchCase
                                    $matchByte,  # MatchByte
                                    $default,    # SearchFormat
                                    $default     # ReplaceFormat
                                   ) | Out-Null
                }
                #テキストボックス内の置換
                if ($shape1.Count -gt 0) {
                    $found = $true
                    Foreach($shapeitem in $shape1) {
                        if ($shapeitem.TextFrame2.HasText) {
                            $shapeText = $shapeitem.TextFrame2.TextRange.Text
                            if ($shapeText.Contains($OldStr)) {
                                $resultstr = $shapeText.Replace($OldStr, $NewStr)
                                $shapeitem.TextFrame2.TextRange.Text = "$resultstr"
                            }
                        }
                    }
                }
                #センターフッター置換
                if ($pagesetup1.CenterFooter -ne "*") {
                    $found = $true
                    $centerfooterText = $pagesetup1.CenterFooter
                    if ($centerfooterText.Contains($OldStr)) {
                        $resultstr = $centerfooterText.Replace($OldStr, $NewStr)
                        $pagesetup1.CenterFooter = "$resultstr" 
                    }
                }
                #センターヘッダー置換
                if ($pagesetup1.CenterHeader -ne "*") {
                    $found = $true
                    $centerheaderText = $pagesetup1.CenterHeader
                    if ($centerheaderText.Contains($OldStr)) {
                        $resultstr = $centerheaderText.Replace($OldStr, $NewStr)
                        $pagesetup1.CenterHeader = "$resultstr" 
                    }
                }
                #左フッター置換
                if ($pagesetup1.LeftFooter -ne "*") {
                    $found = $true
                    $leftfooterText = $pagesetup1.LeftFooter
                    if ($leftfooterText.Contains($OldStr)) {
                        $resultstr = $leftfooterText.Replace($OldStr, $NewStr)
                        $pagesetup1.LeftFooter = "$resultstr" 
                    }
                }
                #左ヘッダー置換
                if ($pagesetup1.LeftHeader -ne "*") {
                    $found = $true
                    $leftheaderText = $pagesetup1.LeftHeader
                    if ($leftheaderText.Contains($OldStr)) {
                        $resultstr = $leftheaderText.Replace($OldStr, $NewStr)
                        $pagesetup1.LeftHeader = "$resultstr" 
                    }
                }
                #右フッター置換
                if ($pagesetup1.RightFooter -ne "*") {
                    $found = $true
                    $rightfooterText = $pagesetup1.RightFooter
                    if ($rightfooterText.Contains($OldStr)) {
                        $resultstr = $rightfooterText.Replace($OldStr, $NewStr)
                        $pagesetup1.RightFooter = "$resultstr" 
                    }
                }
                #右ヘッダー置換
                if ($pagesetup1.RightHeader -ne "*") {
                    $found = $true
                    $rightheaderText = $pagesetup1.RightHeader
                    if ($rightheaderText.Contains($OldStr)) {
                        $resultstr = $rightheaderText.Replace($OldStr, $NewStr)
                        $pagesetup1.RightHeader = "$resultstr"
                    }
                }
            }
            #新しいファイルパス名に置換
            $newfile = $srcfile.Replace($srcdir,$dstdir)
            if ($found -and $srcfile -ne $newfile) {
                $num_files++
                Write-Host "置換あり" -Fore Green
                $dstsubdir = Split-Path $newfile -Parent
                if (-not (Test-Path -LiteralPath $dstsubdir -PathType Container)) {
                    New-Item $dstsubdir -ItemType Directory | Out-Null
                }
                #名前を付けて保存
                $workbook.SaveAs($newfile)
            }
            else{
                Write-Host "置換なし"
            }
                
            $workbook.Close()
        }
        Write-Host "Excelファイル処理が終了しました。"
        Write-Host "$num_files ファイルの置換を行ないました。"
    } catch {
        Write-Host $Error[0].ToString() $Error[0].InvocationInfo.PositionMessage
    } finally {
        if ($excel) { $excel.Quit() }
        $result,$range1,$shape1,$pagesetup1,$worksheet,$workbook,$excel | % { try{[Runtime.Interopservices.Marshal]::ReleaseComObject($_)}catch{}; $_ = $Null } | Out-Null
        [GC]::Collect()
    }


    #------------------【Word】-----------------------
    #---WdFindWrap定数---
    #wdFindStop	0	検索範囲の先頭または末尾まで検索したら、検索を終了します。
    $wdFindContinue = 1 #検索範囲の先頭または末尾まで検索しさらに検索を続ける
    #wdFindAsk	2	選択範囲または指定範囲を検索し、文書の残りの部分も検索するかどうかをたずねるメッセージを表示します。
    #wdFindContinue	1	検索範囲の先頭または末尾まで検索し、さらに検索を続けます。
    
    #---WdReplace定数--- 
    #$wdReplaceNone = 0 # 置換を行わない 
    #$wdReplaceOne = 1 #最初に一致したものを置換する
    $wdReplaceAll = 2 #すべて置換する    
    
    # パラメーター
    $findText = [parameter(Position=1)][String]$OldStr        #検索する文字列
    $matchCase = $false         #大文字小文字の区別する
    $matchWholeWord = $false    #完全に一致する単語だけを検索する
    $matchWildcards = $false    #ワイルドカードを使用する
    $matchSoundsLike = $false   #あいまい検索
    $matchAllWordForms = $false #すべての単語の活用形を検索する
    $forward = $true            #検索方向(Trueで末尾へ)
    $wrap = $wdFindContinue     #検索が文書の末尾に達した場合にどうするか(WdFindWrap定数)
    $format = $false            #書式を検索する場合
    $replaceWith = [parameter(Position=2)][String]$NewStr   #置換文字列
    $replace = $wdReplaceAll    #置換する文字列の個数(Wdreplace 定数)その他 : wdReplaceNone 置換しない wdReplaceOne 最初のみ置換 
    $matchKashida = $false      
    $matchdiacritics = $false   
    $matchalefhamza = $false    
    $matchControl = $true      

    Add-Type -AssemblyName Microsoft.Office.Interop.Word

    Write-Host "Wordファイル処理を開始します。"

    try {
        $word = New-Object -ComObject Word.Application # アプリ起動
        $word.Visible = $false  # 画面非表示
        #$word.DisplayAlerts = $false # 画面アラート無効
        $default = [Type]::Missing
        $num_files = 0

        #フィルターした全てのファイルに対して1ファイルずつ
        Get-ChildItem -LiteralPath $srcdir -Filter "*.doc*" -Recurse | % {
            $srcfile = $_.FullName
            Write-Host "$srcfile : " -NoNewline
            $doc = $word.Documents.Open($srcfile)
            $shape1 = $doc.Shapes

            $found = $false

            $findObject = $word.Selection.Find  
            
            #検索書式クリア
            $findObject.ClearFormatting()
            $findObject.Replacement.ClearFormatting()

            $resultreplace = $false
            
            #置換処理実行
            $resultreplace = $findObject.Execute($findText,
                                $matchCase,
                                $matchWholeWord,
                                $matchWildcards,
                                $matchSoundsLike,
                                $matchAllWordForms,
                                $forward,
                                $wrap,
                                $format,
                                $replaceWith,
                                $replace,
                                $matchKashida,
                                $matchdiacritics,
                                $matchalefhamza,
                                $matchControl)

            if ($resultreplace){
                $found=$true
            }

            #テキストボックス内の置換
            if ($shape1.Count -gt 0) {
                $found = $true
                Foreach($shapeitem in $shape1) {
                    if ($shapeitem.TextFrame.HasText) {
                        $shapeText = $shapeitem.TextFrame.TextRange.Text
                        if ($shapeText.Contains($OldStr)) {
                            $resultstr = $shapeText.Replace($OldStr, $NewStr) 
                            $shapeitem.TextFrame.TextRange.Text = "$resultstr"
                        }
                    }
                }
            }
            
            #ヘッダーフッターの文字置換
            ForEach($sec In $doc.Sections) { #セクションの数だけループ処理
                #ヘッダー置換
                ForEach($hdr In $sec.Headers){
                    if ($hdr.Range.Text -ne "*") { #ヘッダーに何か文字がある場合
                        $found = $true
                        $headerText = $hdr.Range.Text
                        if ($headerText.Contains($OldStr)) {
                            $resultstr = $headerText.Replace($OldStr, $NewStr) 
                            $hdr.Range.Text = "$resultstr" 
                        }
                    }
                }
                 #フッター置換
                ForEach($ftr In $sec.Footers){
                    if ($ftr.Range.Text -ne "*") { #フッターに何か文字がある場合
                        $found = $true
                        $footerText = $ftr.Range.Text
                        if ($footerText.Contains($OldStr)) {
                            $resultstr = $footerText.Replace($OldStr, $NewStr) 
                            $ftr.Range.Text = "$resultstr" 
                        }
                    }
                }
            }

            #新ファイル名に置換
            $newfile = $srcfile.Replace($srcdir,$dstdir)
            
            #置換文字がある場合
            if ($found -and $srcfile -ne $newfile) {
                $num_files++
                Write-Host "置換あり" -Fore Green
                $dstsubdir = Split-Path $newfile -Parent
                if (-not (Test-Path -LiteralPath $dstsubdir -PathType Container)) {
                    New-Item $dstsubdir -ItemType Directory | Out-Null
                }
                $doc.SaveAs($newfile)
            } else {
                Write-Host "置換なし"
            }
            $doc.Close()
        
        }
        Write-Host "Wordファイル処理が終了しました。"
        Write-Host "$num_files ファイルの置換を行ないました。"
    } catch {
        Write-Host $Error[0].ToString() $Error[0].InvocationInfo.PositionMessage
    } finally {
        if ($word) { $word.Quit() }
        $shape1,$doc,$word | % { try{[Runtime.Interopservices.Marshal]::ReleaseComObject($_)}catch{}; $_ = $Null } | Out-Null
        [GC]::Collect()
    }


}

##----------------------------------
##----------メイン処理---------------
$TimeSpan = Measure-Command{
    Replace $Dir $OldStr $NewStr
}
##----------------------------------
##----------------------------------

Write-Host "処理時間: "$TimeSpan.TotalSeconds"sec"  #処理時間を表示
Write-Host "終了するには何かキーを押してください . . ."
$Host.UI.RawUI.FlushInputBuffer()
$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") | Out-Null


##----------------------------------
##ps1ファイルのショートカットファイルを作成してプロパティのリンク先の先頭に以下の文を入れると、ファイルをドラッグ&ドロップできるようになる。
##C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy RemoteSigned -File <元の文字列>
##----------------------------------

PowerShell実行

ショートカットからドラッグアンドドロップ

PowerShellの実行ファイルである、「ps1ファイル」のショートカット作成しておきます。

ショートカット作成することで、フォルダをドラッグアンドドロップして置換を実行できるようになるので、効率的です。

powershell_draganddrop

ショートカット作成したら、プロパティ画面を開いて、リンク先の先頭に

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy RemoteSigned -File

を書き足します。

そうすることで、ファイルをドラッグアンドドロップできるようになります。

powershell_shortcut

コンソール画面からコマンド

ショートカット作成しないで、コンソールから実行したい場合は、

ps1ファイルのディレクトリまで移動して、<ps1ファイル名> <置換したいフォルダ> <検索文字列> <置換文字列>

で実行できます。検索文字列と、置換文字列は、ps1ファイル内でも指定できます。

powershell_console powershell_execute_after

フォルダ前後

実行後、置換したファイルを保存したNewフォルダが作成されますので、

置換前のフォルダと置換後のフォルダを分けることができ、置換前と比べることもできます。

replace_beforeafter_folder

ps1ファイル内から置換文字指定

powershell_old_new_str

ps1ファイルの先頭の方に、文字列指定するパラメーター設定を設けています。

$OldStr=”検索文字列”

$NewStr=”置換文字列”

文字を置換したいExcelWord

Excel 置換前

excel_before

 

Excel  置換後

excel_after

Word 置換前

word_before

Word  置換後

word_after

Point

  • Excelファイルでは、複数シート対応
  • 拡張子(.xls .xlsx .doc .docx)対応
  • フォルダ階層は深くてもOK
  • テキストボックス内の置換可能
  • ヘッダーheader、フッターfooterの置換可能

全角半角、大文字小文字に対応したソースコード

コメントで頂いた、全角半角、大文字小文字の判別を引数の$FlgStr=”1″(有効),”0″(無効)で指定できるようにしました。

 
<# Excel_Word_Replace.bat 対象フォルダ名 [検索文字列] [置換文字列]#>
param([String]$Dir,
[String]$OldStr = "ABC",
[String]$NewStr = "日本Japan★",
[String]$FlgStr = "1"
)

#-----------Function-------------
Function Replace {
[CmdletBinding(PositionalBinding=$False)]
param([parameter(Position=0)][String]$Dir,
[parameter(Position=1)][String]$OldStr,
[parameter(Position=2)][String]$NewStr,
[parameter(Position=3)][String]$FlgStr,
[Alias("s")][String]$sheet = "*", #シートの名前。全シートを対象とする場合は "*"
[Alias("r")][String]$range = "*", #セルの範囲("A1:C4"など).全セルを対象とする場合は "*"
[Alias("a")][Int]$LookAt = 2, #セル内容が完全に同一であるものを検索 1:する 2:しない
[Alias("c")][Int]$MatchCase = 0, #大文字と小文字の区別 0:しない 1:する
[Alias("b")][Int]$MatchByte = 0 #半角と全角の区別 0:しない 1:する
)

if (-not $Dir) {
Write-Host "対象フォルダが指定されていません。処理を終了します。" -Fore Red
return
}

if (-not (Test-Path -LiteralPath $Dir -PathType Container)) {
Write-Host "対象フォルダがありません。処理を終了します。" -Fore Red
return
}

$srcdir = Convert-Path -LiteralPath $Dir
$dstdir = $srcdir + "_new"

if (Test-Path -LiteralPath $dstdir) {
Write-Host "$($dstdir)が上書きされます。続行しますか。y/n [n]:" -Fore Yellow -NoNewline
$answer = ""
try { $answer = (Read-Host).Trim().ToUpper() } catch {}
switch ($answer) {
"y" { Remove-Item -LiteralPath $dstdir -Recurse -Force }
default { Write-Host "処理を終了します。" -Fore Red; return }
}
}
New-Item $dstdir -ItemType Directory | Out-Null

Add-Type -AssemblyName Microsoft.Office.Interop.Excel

Write-Host "Excelファイル処理を開始します。"

try {
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false
$excel.DisplayAlerts = $false
$xlFomulas = [Microsoft.Office.Interop.Excel.XlFindLookIn]::xlFormulas
#$xlValues = [Microsoft.Office.Interop.Excel.XlFindLookIn]::xlValues
$default = [Type]::Missing
$num_files = 0
#$shape = [Microsoft.Office.Interop.Excel.Shape]::shape

#フィルターした全てのファイルに対して1ファイルずつ
Get-ChildItem -LiteralPath $srcdir -Filter "*.xls*" -Recurse | % {
$srcfile = $_.FullName
Write-Host "$srcfile : " -NoNewline
$workbook = $excel.Workbooks.Open($srcfile)
$found = $false

#ExceSheet 1シートずつ
$workbook.Sheets | % {
$worksheet = $_
if ($sheet -ne "*" -and $sheet -ne $worksheet.Name) { Return }
if ($range -eq "*") {
$range1 = $worksheet.Cells
$shape1 = $worksheet.Shapes
$pagesetup1 = $worksheet.pageSetup
} else {
$range1 = $worksheet.Range($range)
}

#セル全体検索Find
$result = $range1.Find($OldStr, # What
$default, # After
$xlFomulas, # LookIn
$LookAt, # LookAt
$default, # SearthOrder
$default, # SearchDirection
$matchCase, # MatchCase
$matchByte, # MatchByte
$default # SearchFormat
)

if ($result) {
$found = $true
#セル全体置換Replace
$range1.Replace($OldStr, # What
$NewStr, # Replacement
$LookAt, # LookAt
$default, # SearthOrder
$matchCase, # MatchCase
$matchByte, # MatchByte
$default, # SearchFormat
$default # ReplaceFormat
) | Out-Null
}
#テキストボックス内の置換
if ($shape1.Count -gt 0) {
$found = $true
Foreach($shapeitem in $shape1) {
if ($shapeitem.TextFrame2.HasText) {
$shapeText = $shapeitem.TextFrame2.TextRange.Text
if ($shapeText.Contains($OldStr)) {
if ($FlgStr = "1") {
$resultstr = $shapeText -creplace $OldStr, $NewStr
}
else {
$resultstr = $shapeText.Replace($OldStr, $NewStr)
}
$shapeitem.TextFrame2.TextRange.Text = "$resultstr"

}
}
}
}
#センターフッター置換
if ($pagesetup1.CenterFooter -ne "*") {
$found = $true
$centerfooterText = $pagesetup1.CenterFooter
if ($centerfooterText.Contains($OldStr)) {
if ($FlgStr = "1") {
$resultstr = $centerfooterText -creplace $OldStr, $NewStr
}
else {
$resultstr = $centerfooterText.Replace($OldStr, $NewStr)
}
$pagesetup1.CenterFooter = "$resultstr"
}
}
#センターヘッダー置換
if ($pagesetup1.CenterHeader -ne "*") {
$found = $true
$centerheaderText = $pagesetup1.CenterHeader
if ($centerheaderText.Contains($OldStr)) {
if ($FlgStr = "1") {
$resultstr = $centerheaderText -creplace $OldStr, $NewStr
}
else {
$resultstr = $centerheaderText.Replace($OldStr, $NewStr)
}
$pagesetup1.CenterHeader = "$resultstr"
}
}
#左フッター置換
if ($pagesetup1.LeftFooter -ne "*") {
$found = $true
$leftfooterText = $pagesetup1.LeftFooter
if ($leftfooterText.Contains($OldStr)) {
if ($FlgStr = "1") {
$resultstr = $leftfooterText -creplace $OldStr, $NewStr
}
else {
$resultstr = $leftfooterText.Replace($OldStr, $NewStr)
}
$pagesetup1.LeftFooter = "$resultstr"
}
}
#左ヘッダー置換
if ($pagesetup1.LeftHeader -ne "*") {
$found = $true
$leftheaderText = $pagesetup1.LeftHeader
if ($leftheaderText.Contains($OldStr)) {
if ($FlgStr = "1") {
$resultstr = $leftheaderText -creplace $OldStr, $NewStr
}
else {
$resultstr = $leftheaderText.Replace($OldStr, $NewStr)
}
$pagesetup1.LeftHeader = "$resultstr"
}
}
#右フッター置換
if ($pagesetup1.RightFooter -ne "*") {
$found = $true
$rightfooterText = $pagesetup1.RightFooter
if ($rightfooterText.Contains($OldStr)) {
if ($FlgStr = "1") {
$resultstr = $rightfooterText -creplace $OldStr, $NewStr
}
else {
$resultstr = $rightfooterText.Replace($OldStr, $NewStr)
}
$pagesetup1.RightFooter = "$resultstr"
}
}
#右ヘッダー置換
if ($pagesetup1.RightHeader -ne "*") {
$found = $true
$rightheaderText = $pagesetup1.RightHeader
if ($rightheaderText.Contains($OldStr)) {
if ($FlgStr = "1") {
$resultstr = $rightheaderText -creplace $OldStr, $NewStr
}
else {
$resultstr = $rightheaderText.Replace($OldStr, $NewStr)
}
$pagesetup1.RightHeader = "$resultstr"
}
}
}
#新しいファイルパス名に置換
$newfile = $srcfile.Replace($srcdir,$dstdir)
if ($found -and $srcfile -ne $newfile) {
$num_files++
Write-Host "置換あり" -Fore Green
$dstsubdir = Split-Path $newfile -Parent
if (-not (Test-Path -LiteralPath $dstsubdir -PathType Container)) {
New-Item $dstsubdir -ItemType Directory | Out-Null
}
#名前を付けて保存
$workbook.SaveAs($newfile)
}
else{
Write-Host "置換なし"
}

$workbook.Close()
}
Write-Host "Excelファイル処理が終了しました。"
Write-Host "$num_files ファイルの置換を行ないました。"
} catch {
Write-Host $Error[0].ToString() $Error[0].InvocationInfo.PositionMessage
} finally {
if ($excel) { $excel.Quit() }
$result,$range1,$shape1,$pagesetup1,$worksheet,$workbook,$excel | % { try{[Runtime.Interopservices.Marshal]::ReleaseComObject($_)}catch{}; $_ = $Null } | Out-Null
[GC]::Collect()
}

#------------------【Word】-----------------------
#---WdFindWrap定数---
#wdFindStop 0 検索範囲の先頭または末尾まで検索したら、検索を終了します。
$wdFindContinue = 1 #検索範囲の先頭または末尾まで検索しさらに検索を続ける
#wdFindAsk 2 選択範囲または指定範囲を検索し、文書の残りの部分も検索するかどうかをたずねるメッセージを表示します。
#wdFindContinue 1 検索範囲の先頭または末尾まで検索し、さらに検索を続けます。

#---WdReplace定数---
#$wdReplaceNone = 0 # 置換を行わない
#$wdReplaceOne = 1 #最初に一致したものを置換する
$wdReplaceAll = 2 #すべて置換する

# パラメーター
$findText = [parameter(Position=1)][String]$OldStr #検索する文字列
$matchCase = $true #大文字小文字の区別する
$matchWholeWord = $true #完全に一致する単語だけを検索する
$matchWildcards = $false #ワイルドカードを使用する
$matchSoundsLike = $false #あいまい検索
$matchAllWordForms = $false #すべての単語の活用形を検索する
$forward = $true #検索方向(Trueで末尾へ)
$wrap = $wdFindContinue #検索が文書の末尾に達した場合にどうするか(WdFindWrap定数)
$format = $false #書式を検索する場合
$replaceWith = [parameter(Position=2)][String]$NewStr #置換文字列
$replace = $wdReplaceAll #置換する文字列の個数(Wdreplace 定数)その他 : wdReplaceNone 置換しない wdReplaceOne 最初のみ置換
$matchKashida = $false
$matchdiacritics = $false
$matchalefhamza = $false
$matchControl = $true

Add-Type -AssemblyName Microsoft.Office.Interop.Word

Write-Host "Wordファイル処理を開始します。"

try {
$word = New-Object -ComObject Word.Application # アプリ起動
$word.Visible = $false # 画面非表示
#$word.DisplayAlerts = $false # 画面アラート無効
$default = [Type]::Missing
$num_files = 0

#フィルターした全てのファイルに対して1ファイルずつ
Get-ChildItem -LiteralPath $srcdir -Filter "*.doc*" -Recurse | % {
$srcfile = $_.FullName
Write-Host "$srcfile : " -NoNewline
$doc = $word.Documents.Open($srcfile)
$shape1 = $doc.Shapes

$found = $false

$findObject = $word.Selection.Find

#検索書式クリア
$findObject.ClearFormatting()
$findObject.Replacement.ClearFormatting()

$resultreplace = $false

#置換処理実行
$resultreplace = $findObject.Execute($findText,
$matchCase,
$matchWholeWord,
$matchWildcards,
$matchSoundsLike,
$matchAllWordForms,
$forward,
$wrap,
$format,
$replaceWith,
$replace,
$matchKashida,
$matchdiacritics,
$matchalefhamza,
$matchControl)

if ($resultreplace){
$found=$true
}

#テキストボックス内の置換
if ($shape1.Count -gt 0) {
$found = $true
Foreach($shapeitem in $shape1) {
if ($shapeitem.TextFrame.HasText) {
$shapeText = $shapeitem.TextFrame.TextRange.Text
if ($shapeText.Contains($OldStr)) {
if ($FlgStr = "1") {
$resultstr = $shapeText -creplace $OldStr, $NewStr
}
else {
$resultstr = $shapeText.Replace($OldStr, $NewStr)
}
$shapeitem.TextFrame.TextRange.Text = "$resultstr"
}
}
}
}

#ヘッダーフッターの文字置換
ForEach($sec In $doc.Sections) { #セクションの数だけループ処理
#ヘッダー置換
ForEach($hdr In $sec.Headers){
if ($hdr.Range.Text -ne "*") { #ヘッダーに何か文字がある場合
$found = $true
$headerText = $hdr.Range.Text
if ($headerText.Contains($OldStr)) {
if ($FlgStr = "1") {
$resultstr = $headerText -creplace $OldStr, $NewStr
}
else {
$resultstr = $headerText.Replace($OldStr, $NewStr)
}
$hdr.Range.Text = "$resultstr"
}
}
}
#フッター置換
ForEach($ftr In $sec.Footers){
if ($ftr.Range.Text -ne "*") { #フッターに何か文字がある場合
$found = $true
$footerText = $ftr.Range.Text
if ($footerText.Contains($OldStr)) {
if ($FlgStr = "1") {
$resultstr = $footerText -creplace $OldStr, $NewStr
}
else {
$resultstr = $footerText.Replace($OldStr, $NewStr)
}
$ftr.Range.Text = "$resultstr"
}
}
}
}

#新ファイル名に置換
$newfile = $srcfile.Replace($srcdir,$dstdir)

#置換文字がある場合
if ($found -and $srcfile -ne $newfile) {
$num_files++
Write-Host "置換あり" -Fore Green
$dstsubdir = Split-Path $newfile -Parent
if (-not (Test-Path -LiteralPath $dstsubdir -PathType Container)) {
New-Item $dstsubdir -ItemType Directory | Out-Null
}
$doc.SaveAs($newfile)
} else {
Write-Host "置換なし"
}
$doc.Close()

}
Write-Host "Wordファイル処理が終了しました。"
Write-Host "$num_files ファイルの置換を行ないました。"
} catch {
Write-Host $Error[0].ToString() $Error[0].InvocationInfo.PositionMessage
} finally {
if ($word) { $word.Quit() }
$shape1,$doc,$word | % { try{[Runtime.Interopservices.Marshal]::ReleaseComObject($_)}catch{}; $_ = $Null } | Out-Null
[GC]::Collect()
}

}

##----------------------------------
##----------メイン処理---------------
$TimeSpan = Measure-Command{
Replace $Dir $OldStr $NewStr $FlgStr
}
##----------------------------------
##----------------------------------

Write-Host "処理時間: "$TimeSpan.TotalSeconds"sec" #処理時間を表示
Write-Host "終了するには何かキーを押してください . . ."
$Host.UI.RawUI.FlushInputBuffer()
$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") | Out-Null

##----------------------------------
##ps1ファイルのショートカットファイルを作成してプロパティのリンク先の先頭に以下の文を入れると、ファイルをドラッグ&ドロップできるようになる。
##C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy RemoteSigned -File <元の文字列>
##----------------------------------