【PowerShell】PowerShellからINIファイルの設定値を取得するには②

この記事では、PowerShellからINIファイルの設定値を取得する方法についてご説明します。

今回は「kernel32」を読み込んでGetPrivateProfileStringのAPI関数を使い、INIファイルの設定値を取得しています。

【動画】PowerShellからINIファイルの設定値を取得する実際の動き

本題に入る前に、まずは次の動画をご覧ください。


INIファイルを参照・値の取得はGetPrivateProfileString関数を使います。

GetPrivateProfileString関数はINIファイルから文字列を読み取ることができるAPI関数です。

取得したい値に該当するセクション名とキー名を引数に指定することで、対応する値を取得しています。

シート上にセクション名とキー名を入力するセルが用意されており、その値をマクロが取得してGetPrivateProfileString関数に渡して実行し、セクション名とキー名に該当する値をセルに出力しています。

なお、GetPrivateProfileString関数を使うには「kernel32」というdllファイルを読み込む必要があります。

マクロ作成の流れ

STEP.1
「kernel32」というdllファイルを読み込む
「kernel32」というdllファイルを読み込みます。
「kernel32」は、GetPrivateProfileString関数を実行するのに必要なdllファイルです。
STEP.1
GetPrivateProfileString関数にセクション名、キー名、INIファイルのフルパスを渡して実行する
GetPrivateProfileString関数にセクション名、キー名、INIファイルのフルパスを渡して実行します。
STEP.2
GetPrivateProfileString関数の戻り値から、セクション名とキー名に該当する値を取得する
GetPrivateProfileString関数の戻り値から、セクション名とキー名に該当する値を取得します。

INIファイルの例

今回は下のINIファイルを用意しました。

コードを実行すると、セクション名とキー名に該当する値がコンソール上に出力されます。

セクション名に「connVal」、キー名に「comVal」を指定しているので、「vb1」の値がコンソール上に出力されています。

コードの例

# Add-Type -TypeDefinitionを使ってC#のコードを実行する
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
using System.Text;

// IniFileという名前の公開クラスを定義する
public class IniFile {

    // INIファイルから情報を取得するGetPrivateProfileStringというAPI関数を呼び出すため、DllImport属性を使って「kernel32.dll」という名前のDLLをインポートする
    // DllImport属性とは、API関数を呼び出すことができるようにするための属性
    // 関数がUnicode文字列を正しく処理できるよう、CharSetにUnicodeを指定する
    [DllImport("kernel32", CharSet = CharSet.Unicode)]

    // 初期化ファイル(今回はINIファイル)にあるセクションから文字列を取得するGetPrivateProfileString関数の宣言
    public static extern int GetPrivateProfileString(
        string lpApplicationName,           // セクション名
        string lpKeyName,                   // キー名
        string lpDefault,                   // 指定されたセクション名とキー名の組み合わせがINIファイル内に存在しない場合に返されるデフォルト値
        StringBuilder lpReturnedString ,    // 読み取った値を格納するためのバッファ(文字列変数)
        int nSize ,                         // lpReturnedStringバッファのサイズ(文字数)
        string lpFileName);                 // INIファイルのフルパス
}
"@

# セクション名を指定する
$sectionName = "connVal"

# キー名を指定する
$keyName = "comVal"

# INIファイルのフルパスを指定する
$iniFilePath = "C:\work\10_勉強\18_PowerShell\0028\info.ini"

# 指定されたセクション名とキー名の組み合わせがINIファイル内に存在しない場合に返されるデフォルト値を取得する
$default = ""

# GetPrivateProfileString関数を実行する前は戻り値のサイズが不明なため、
# 一旦戻り値を格納するためのバッファを設定しておく(ここでは256文字までとしています)
$returnValue = New-Object System.Text.StringBuilder 256

# IniFileクラスのGetPrivateProfileString関数を呼び出す
[IniFile]::GetPrivateProfileString(
    $sectionName,             # セクション名
    $keyName,                 # キー名
    $default,                 # 指定されたセクション名とキー名の組み合わせがINIファイル内に存在しない場合に返されるデフォルト値
    $returnValue,             # 読み取った値を格納するためのバッファ(文字列変数)
    $returnValue.Capacity,    # returnValueのバッファのサイズ(文字数)
    $iniFilePath              # INIファイルのフルパス
) | Out-Null

# INIファイルから取得した値を出力する
Write-Output $returnValue.ToString()

注目すべきコード①

最初に見て頂きたいのは2行目です。

# Add-Type -TypeDefinitionを使ってC#のコードを実行する
Add-Type -TypeDefinition @"

コードの説明

以上のコードは、PowerShellでC#を実行するためにAdd-Typeコマンドレットを実行するコードです。

今回は、INIファイルの情報を取得するのに、INIファイルの情報を取得してくれるGetPrivateProfileString関数を実行します。

ただし、PowerShellにGetPrivateProfileString関数は存在しないので、GetPrivateProfileString関数を実行することはできません。

ではどうやったらGetPrivateProfileString関数が実行するのかというと、PowerShell上でC#のコードが使えるようにし、その中でGetPrivateProfileString関数を実行します。

PowerShell上でC#のコードが使えるようにするのがAdd-Typeコマンドレットです。

Add-Typeコマンドレットの後に「-TypeDefinition」パラメータを指定することで、直接PowerShellのコード中にC#の型定義を含めることができます。

C#のコードの定義は、C#のコードを@で囲んで記述します。

注目すべきコード②

次に見て頂きたいのは3行目から23行目です。

using System;
using System.Runtime.InteropServices;
using System.Text;

// IniFileという名前の公開クラスを定義する
public class IniFile {

    // INIファイルから情報を取得するGetPrivateProfileStringというAPI関数を呼び出すため、DllImport属性を使って「kernel32.dll」という名前のDLLをインポートする
    // DllImport属性とは、API関数を呼び出すことができるようにするための属性
    // 関数がUnicode文字列を正しく処理できるよう、CharSetにUnicodeを指定する
    [DllImport("kernel32", CharSet = CharSet.Unicode)]

    // 初期化ファイル(今回はINIファイル)にあるセクションから文字列を取得するGetPrivateProfileString関数の宣言
    public static extern int GetPrivateProfileString(
        string lpApplicationName,           // セクション名
        string lpKeyName,                   // キー名
        string lpDefault,                   // 指定されたセクション名とキー名の組み合わせがINIファイル内に存在しない場合に返されるデフォルト値
        StringBuilder lpReturnedString ,    // 読み取った値を格納するためのバッファ(文字列変数)
        int nSize ,                         // lpReturnedStringバッファのサイズ(文字数)
        string lpFileName);                 // INIファイルのフルパス
}

コードの説明

以上のコードは、C#のコードをPowerShellに組み込んだコードです。

GetPrivateProfileString関数を実行するために以上のC#のコードを組み込んでいます。

コードの詳細

3行目のコードは、.NET Frameworkの基本的なクラスやメソッドにアクセスできるようにする名前空間を使用することを宣言するコードです。

4行目のコードは、Windows API間の相互運用をサポートするクラスやインターフェイスを提供する名前空間を使用することを宣言するコードです。

5行目のコードは、文字エンコーディングや文字列操作に関連するクラスを提供する名前空間を使用することを宣言するコードです。

8行目のコードは、IniFileという名前の公開クラスを定義するコードです。

なお、GetPrivateProfileStringを呼び出すのに、このIniFileという名前のクラス名を以下の43行目のコードで参照するので、クラス名に相違が無いよう気をつけましょう。

[IniFile]::GetPrivateProfileString(

13行目のコードは、DllImport属性を使って「kernel32.dll」という名前の DLLをインポートする処理のコードです。

今回INIファイルから情報を取得するのにGetPrivateProfileStringというAPI関数を使います。

GetPrivateProfileStringというAPI関数を使うには、「kernel32.dll」というdllファイルを読み込む必要があるため、DllImport属性を使って「kernel32.dll」という名前の DLLをインポートします。

16行目から23行目のコードは、INIファイルから文字列を読み取るGetPrivateProfileString関数の宣言のコードです。

GetPrivateProfileString関数はAPI関数であり、C#でGetPrivateProfileString関数を実行する場合は16行目から23行目のように宣言する必要があります。

なおGetPrivateProfileString関数の各引数については次の通りです。

lpApplicationName

lpApplicationNameには、INIファイル内のセクション名を指定します。

lpKeyName

lpKeyNameには、キーの名前を指定します。

lpDefault

lpDefaultには、指定されたセクション名とキー名の組み合わせがINIファイル内に存在しない場合に返されるデフォルト値を指定します。

lpApplicationNameに存在しないセクション名、またはlpKeyNameに存在しないキー名を指定された場合、lpDefaultに指定した値が引数lpReturnedStringに返されます。

例えばlpApplicationNameに存在しないセクション名、またはlpKeyNameに存在しないキー名を指定された場合、lpDefaultに「abc」と指定していたら、引数lpReturnedStringに「abc」の文字列が返されます。

lpReturnedString

lpReturnedStringは、読み取った値を格納するためのバッファ(文字列変数)を指定します。

このlpReturnedStringにセクション名とキー名に該当する値が返されます。

ただし、GetPrivateProfileString関数が返すデータのサイズが実行時に異なる可能性があり、バッファオーバーフローの可能性もあるので、その対策としてバッファは事前に十分な大きさに設定しておく必要があるため、以下のとおり40行目で256文字のバッファをlpReturnedStringの引数に設定しています。

# GetPrivateProfileString関数を実行する前は戻り値のサイズが不明なため、
# 一旦戻り値を格納するためのバッファを設定しておく(ここでは256文字までとしています)
$returnValue = New-Object System.Text.StringBuilder 256

nSize

nSizeは、lpReturnedStringバッファのサイズ(文字数)を指定します。

以下のとおり40行目で256文字のバッファをlpReturnedStringの引数に設定しているので、その文字数をLen関数で取得してnSizeの引数に指定します。

# GetPrivateProfileString関数を実行する前は戻り値のサイズが不明なため、
# 一旦戻り値を格納するためのバッファを設定しておく(ここでは256文字までとしています)
$returnValue = New-Object System.Text.StringBuilder 256

lpFileName

lpFileNameには、INIファイルのフルパスを指定します。

注目すべきコード③

次に見て頂きたいのは27行目から33行目です。

# セクション名を指定する
$sectionName = "connVal"

# キー名を指定する
$keyName = "comVal"

# INIファイルのフルパスを指定する
$iniFilePath = "C:\work\10_勉強\18_PowerShell\0028\info.ini"

コードの説明

以上のコードは、セクション名とキー名、INIファイルのフルパスを取得するコードです。

注目すべきコード④

次に見て頂きたいのは36行目です。

# 指定されたセクション名とキー名の組み合わせがINIファイル内に存在しない場合に返されるデフォルト値を取得する
$default = ""

コードの説明

以上のコードは、指定されたセクション名とキー名の組み合わせがINIファイル内に存在しない場合に返されるデフォルト値を取得するコードです。

今回はブランクを返して欲しいため、変数default に「””」を設定しています。

注目すべきコード⑤

次に見て頂きたいのは40行目です。

# GetPrivateProfileString関数を実行する前は戻り値のサイズが不明なため、
# 一旦戻り値を格納するためのバッファを設定しておく(ここでは256文字までとしています)
$returnValue = New-Object System.Text.StringBuilder 256

コードの説明

以上のコードは、セクション名とキー名に該当する値を格納する変数returnValueに256文字のバッファを格納するコードです。

GetPrivateProfileString関数はセクション名とキー名に該当する値をlpReturnedStringの引数に返しますが、その返すデータのサイズが実行時に異なる可能性があり、バッファオーバーフローの可能性もあるので、その対策としてバッファは事前に十分な大きさに設定しておく必要があります。

そのため、256文字のバッファをlpReturnedStringの引数に設定するため、変数returnValueに256文字のバッファを格納しています。

注目すべきコード⑥

次に見て頂きたいのは43行目から50行目です。

# IniFileクラスのGetPrivateProfileString関数を呼び出す
[IniFile]::GetPrivateProfileString(
    $sectionName,             # セクション名
    $keyName,                 # キー名
    $default,                 # 指定されたセクション名とキー名の組み合わせがINIファイル内に存在しない場合に返されるデフォルト値
    $returnValue,             # 読み取った値を格納するためのバッファ(文字列変数)
    $returnValue.Capacity,    # returnValueのバッファのサイズ(文字数)
    $iniFilePath              # INIファイルのフルパス
) | Out-Null

コードの説明

以上のコードは、GetPrivateProfileString関数を実行するコードです。

GetPrivateProfileString関数はIniFileクラス内で宣言しているので、GetPrivateProfileString関数の前に「[IniFile]::」を結合させています。

以上のコードで引数に指定している値は下のとおりです。

第1引数

第1引数はGetPrivateProfileString関数の「lpApplicationName」に渡る値を指定しています。

「lpApplicationName」にはINIファイル内のセクション名を指定するので、セクション名が格納されている変数secNMを指定しています。

第2引数

第2引数はGetPrivateProfileString関数の「lpKeyName」に渡る値を指定しています。

「lpKeyName」にはINIファイル内のキー名を指定するので、キー名が格納されている変数keyNMを指定しています。

第3引数

第3引数はGetPrivateProfileString関数の「lpDefault」に渡る値を指定しています。

「lpDefault」には指定されたセクション名とキー名の組み合わせがINIファイル内に存在しない場合に返されるデフォルト値を指定するので、今回はブランクを返して欲しいため「””」を指定しています。

第4引数

第4引数はGetPrivateProfileString関数の「lpReturnedString」に渡る値を指定しています。

「lpReturnedString」には読み取った値を格納するためのバッファ(文字列変数)を指定するので、バッファが格納された変数resultを指定しています。

第5引数

第5引数はGetPrivateProfileString関数の「nSize」に渡る値を指定しています。

「nSize」にはlpReturnedStringバッファのサイズ(文字数)を指定するので、255の値を指定しています。

第6引数

第6引数はGetPrivateProfileString関数の「lpFileName」に渡る値を指定しています。

「lpFileName」にはINIファイルのフルパスを指定するので、INIファイルのフルパスが格納されている変数iniFilePathを指定しています。

なお、GetPrivateProfileString関数の引数については、「注目すべきコード②」で詳しく説明しているのでそちらもご覧ください。

注目すべきコード⑦

次に見て頂きたいのは53行目です。

# INIファイルから取得した値を出力する
Write-Output $returnValue.ToString()

コードの説明

以上のコードは、INIファイルから取得した値を出力するコードです。

動作確認

INIファイルとExcelファイルの例」をご覧ください。

最後に

この記事では、マクロからINIファイルの設定値を取得する方法についてご説明しました。

マクロからINIファイルの設定値を取得するには、GetPrivateProfileStringというAPI関数を使います。

GetPrivateProfileStringというAPI関数を使うことでマクロからINIファイルの設定値が取得することができるので、本記事を参考にして頂けたら幸いです。

プログラミングのスキルを習得するなら

プログラミングのスキルを習得したい、今のスキルをもっと高めたい、そう考えているなら「プログラミングスクール」がおすすめです。

プログラミングのスキルの基礎を身につけるなら「TechAcademy」で1週間の無料体験があるので、これで「プログラミングの基礎」を学ぶのにおすすめですよ。

→ TechAcademyの「1週間 無料体験」はこちら