[解決方法]パスを定義したConfigファイルをConvertFrom-StringDataに渡すとエラー

2023/10/03に公開

概要

Configファイルから定数データを読み取るロジックを含んでいるPowerShellスクリプトを作成してデバッグした結果、
ConvertFrom-StringData: Invalid pattern '"D:\Program Files\Tesseract-OCR\tesseract.exe"' at offset 5. Unrecognized escape sequence \\P.
というようなエラーが発生しました。

原因はConfigファイル内にバックスラッシュ(\、U+005C)を含むファイルやフォルダーのパスを定義しており、
そのままConvertFrom-StringDataにデータを渡すと発生してしまうエラーでした。

このエラーに対して調査した内容と対処方法を紹介します。

この記事のターゲット

  • 同じ事象 や 類似事象 でお悩みの方
  • 詳しい原因を知りたい方
  • 対処方法(解決方法)を知りたい方

環境

PS C:\WINDOWS\system32> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.3.7
PSEdition                      Core
GitCommitId                    7.3.7
OS                             Microsoft Windows 10.0.19045
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

PS C:\WINDOWS\system32> 

エラー

Get-ContentConvertFrom-StringDataの組合せで設定ファイル(setup.ini)を読み込ませようとしましたが、
ConvertFrom-StringDataでエラーが発生となってしまう。

デバッグ時のエラー
[DBG]: PS D:\PowerShell_ResizeImageTool> Get-Content "Configファイルのフルパス" -Raw -Encoding UTF8 | ConvertFrom-StringData

ConvertFrom-StringData: Invalid pattern '"D:\Program Files\Tesseract-OCR\tesseract.exe"' at offset 5. Unrecognized escape sequence \\P.
[DBG]: PS D:\PowerShell_ResizeImageTool>

💡 英語の直訳

「Invalid pattern」:無効なパターン
「Unrecognized escape sequence」:認識できないエスケープシーケンス

ソースコード

setup.ini
#################################################################################
# 内容  |setup.ini
# 機能  |ResizeImageToolで使用する設定ファイル
#--------------------------------------------------------------------------------
#     |-
#################################################################################
# Tesseract-OCRのインストール場所
ocr_exe_path="D:\Program Files\Tesseract-OCR\tesseract.exe"         # 💡 値にバックスラッシュあり
# Tesseract-OCRの一時ファイル作成場所
ocr_temp_path="D:\Downlodas"                                        # 💡 値にバックスラッシュあり
# Tesseract-OCRの一時ファイル作成場所
ocr_check_keyword="sapporo,maruko,sapo,maru,001-0013,北海道,札幌"
# 自動実行モードの設定(true:自動実行、false:対話式実行)
auto_mode=false
# 対象フォルダーのパス
input_folder=""
# リサイズ後の画像サイズ(px指定)
resize_width="800"
resize_height=""
# 元画像が指定サイズ以下の場合の拡大有無(true:拡大する、false:拡大しない)
small_image_resize=false
# WebP変換の有無
webp_convert=true
# 自動生成されるアウトプット用のフォルダー名
output_foldername="To-Resize_"
Main.ps1を抜粋(メイン処理があるスクリプトファイルの一部を抜粋)
#################################################################################
# 処理名 |RemoveDoubleQuotes
# 機能  |先頭桁と最終桁にあるダブルクォーテーションを削除
#--------------------------------------------------------------------------------
# 戻り値 |String(削除後の文字列)
# 引数  |target_str: 対象文字列
#################################################################################
Function RemoveDoubleQuotes {
    Param (
        [System.String]$target_str
    )
    [System.String]$removed_str = $target_str
    
    If ($target_str.Length -ge 2) {
        if (($target_str.Substring(0, 1) -eq '"') -and
            ($target_str.Substring($target_str.Length - 1, 1) -eq '"')) {
            # 先頭桁と最終桁のダブルクォーテーション削除
            $removed_str = $target_str.Substring(1, $target_str.Length - 2)
        }
    }

    return $removed_str
}
#################################################################################
# 処理名 |メイン処理
# 機能  |同上
#--------------------------------------------------------------------------------
#     |-
#################################################################################
# メッセージコードの設定
Add-Type -TypeDefinition @"
    public enum MESSAGECODE {
        Successful = 0,
        Abend,
        Info_LoadedSettingfile,
        Confirm_ExecutionTool,
        Confirm_ResizeImages,
        Error_NotCore,
        Error_NotSupportedVersion,
        Error_NotWindows,
        Error_LoadingSettingfile,
        Error_NotExistsTargetpath,
        Error_EmptyTargetfolder,
        Error_ExecutionTool
    }
"@

# モジュール内の共通変数を定義
[MESSAGECODE]$result = [MESSAGECODE]::Successful
[System.String]$prompt_message = ''
[System.String]$result_message = ''
[System.String]$append_message = ''
[System.Text.StringBuilder]$sbtemp=New-Object System.Text.StringBuilder

## 設定ファイル読み込み処理
[System.String]$config_fullpath = 'D:\PowerShell_ResizeImageTool\source\powershell\setup.ini'
try {
    # 💡 エラーが発生する場所
    [System.Collections.Hashtable]$config = Get-Content $config_fullpath -Raw -Encoding UTF8 | ConvertFrom-StringData
    # 対象ファイル
    [System.String]$CONFIG_OCR_EXE_PATH=RemoveDoubleQuotes($config.ocr_exe_path)
    [System.String]$CONFIG_OCR_TEMP_PATH=RemoveDoubleQuotes($config.ocr_temp_path)
    [System.String[]]$CONFIG_OCR_CHECK_KEYWORD=(RemoveDoubleQuotes($config.ocr_temp_path)).split(',')
    [System.Boolean]$CONFIG_AUTO_MODE=[System.Convert]::ToBoolean((RemoveDoubleQuotes($config.auto_mode)))
    [System.String]$CONFIG_INPUT_FOLDER=RemoveDoubleQuotes($config.input_folder)
    [System.String]$CONFIG_RESIZE_WIDTH=RemoveDoubleQuotes($config.resize_width)
    [System.String]$CONFIG_RESIZE_HEIGHT=RemoveDoubleQuotes($config.resize_height)
    [System.Boolean]$CONFIG_SMALL_IMAGE_RESIZE=[System.Convert]::ToBoolean((RemoveDoubleQuotes($config.small_image_resize)))
    [System.Boolean]$CONFIG_WEBP_CONVERT=[System.Convert]::ToBoolean((RemoveDoubleQuotes($config.webp_convert)))
    [System.String]$CONFIG_OUTPUT_FOLDERNAME=RemoveDoubleQuotes($config.output_foldername)

    $sbtemp=New-Object System.Text.StringBuilder
    @("`r`n",`
      "対象ファイル: [${config_fullpath}]`r`n")|
    ForEach-Object{[void]$sbtemp.Append($_)}
    $append_message = $sbtemp.ToString()
    $prompt_message = RetrieveMessage ([MESSAGECODE]::Info_LoadedSettingfile) $append_message
    Write-Host $prompt_message
}
catch {
    $result = [MESSAGECODE]::Error_LoadingSettingfile
    $sbtemp=New-Object System.Text.StringBuilder
    @("`r`n",`
      "エラーの詳細: [${config_fullpath}$($_.Exception.Message)]`r`n")|
    ForEach-Object{[void]$sbtemp.Append($_)}
    $append_message = $sbtemp.ToString()
    $result_message = RetrieveMessage ([MESSAGECODE]::Error_LoadingSettingfile) $append_message
}

原因

ConvertFrom-StriingDataでは、パスなどに含まれるバックスラッシュ(\、U+005C)の値をそのまま渡すと、
処理できずに「認識できないエスケープシーケンス(Unrecognized escape sequence)」となりエラーが発生。

対応方法

推奨する対応方法

ConvertFrom-StriingDataに渡す前に \\\ に変換し正しいエスケープシーケンスに置き換えるように変更。
変更によりエラーが発生しなくなり期待通りの動きとなった

Main.ps1のコードを修正
-[System.Collections.Hashtable]$config = Get-Content $config_fullpath -Raw -Encoding UTF8 | ConvertFrom-StringData
+[System.Collections.Hashtable]$config = (Get-Content $config_fullpath -Raw -Encoding UTF8).Replace('\','\\') | ConvertFrom-StringData

推奨しない対応方法

他の対応方法としてConfigファイルに定義しているパスそのものを \ から \\ で定義する事で、
Get-ContentConvertFrom-StringData を組み合わせたコマンドは、そのままの状態で動作するが、
Configファイルを編集するツールの利用者の事を考えるとこの方法は良くない(非推奨)。

setup.iniを抜粋(定義内容を変更する方法)【非推奨】
#################################################################################
# 内容  |setup.ini
# 機能  |ResizeImageToolで使用する設定ファイル
#--------------------------------------------------------------------------------
#     |-
#################################################################################
# Tesseract-OCRのインストール場所
-ocr_exe_path="D:\Program Files\Tesseract-OCR\tesseract.exe"
+ocr_exe_path="D:\\Program Files\\Tesseract-OCR\\tesseract.exe"
# Tesseract-OCRの一時ファイル作成場所
-ocr_temp_path="D:\Downlodas"
+ocr_temp_path="D:\\Downlodas"

参考情報

https://stackoverflow.com/questions/24142436/powershell-parsing-a-properties-file-that-contains-colons
https://itsakura.com/powershell-replace
https://coffeekemuri.blogspot.com/2018/05/powershell-convertfrom.html

まとめ

  • 原因
    ConfigファイルをハッシュテーブルにするConvertFrom-StringDataでは、パスに含まれるバックスラッシュ(\、U+005C)をそのまま渡すと“無効なパターン”や“認識できないエスケープシーケンス”としてエラーが発生する
  • 対処方法1
    ConvertFrom-StringDataに渡す前に、パスに含まれるバックスラッシュ(\、U+005C)を「 \\ 」に置換する事で対応可能
  • 対処補法2(非推奨)
    Configファイルに定義しているパスの区切りを \ から \\ で定義するよう変更

関連記事

https://haretokidoki-blog.com/pasocon_powershell-startup/
https://zenn.dev/haretokidoki/articles/7e6924ff0cc960

GitHubで編集を提案

Discussion