2017/01/15

PowerShell で Excel に設定したフォルダを作成する方法


この記事では、PowerShell のスクリプトを使用して Excel を読み込み、Excel で設定された内容にしたがってフォルダを作成する方法をご紹介します。

ソースを一気に掲載してもよいのですが、それだとはまりどころが分からないので部分的にですが先に解説をしておきます。

なお、Excel の設定は以下のように、ドライブ-フォルダ-サブフォルダ…となります。サンプルプログラムでは行数、フォルダ階層を自由に設定できるようになっています。

pic01

まずは、処理を実行するか確認するメッセージを表示します。Y が入力された場合のみ処理を実行します。画面には以下のように表示されます。

処理を実行しますか?
[はい(Y)] [いいえ(N)] 既定(N):

この部分のソースは以下のようになります。ユーザーの入力を行うサンプルとして考えることができます。

Write-Host "処理を実行しますか?"
$confirm = Read-Host "[はい(Y)] [いいえ(N)] 既定(N)"

if ($confirm -ne "Y") {
  exit
}

次にスクリプトのカレントフォルダにあるファイルパスの取得方法です。PowerShell はなぜか相対パスのファイルを読み込めないので絶対パスに変更する必要があります。なお、Convert-Path で相対パスから絶対パスを取得できるのですが、ファイル名を変数にするとうまく動作しなかったため下記のような処理を行っています。

# Excel ファイル名を指定
$fileName = "test.xlsx"

$filePath = Split-Path $MyInvocation.MyCommand.Path -Parent

#カレントフォルダとファイル名を結合する
$filePath = Join-Path $filePath $fileName

Excel は COM 参照を行っているのですがクセがあり、書籍に載っている方法ではうまく Excel を解放してくれませんでした。いろいろ試したところ、以下のようにワークシート、Excelファイル、Excel という順番に COM オブジェクトを解放するとうまくいったので参考にしてみてください。

# COM 参照を解放する
[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($ws)
[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($wb)
[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($xl)

さて、全部の処理のソースコードは以下のようになります。

#
# Excel ファイルの指定からフォルダを作成するスクリプト
#

#処理実行前に確認を行う
Write-Host "処理を実行しますか?"
$confirm = Read-Host "[はい(Y)] [いいえ(N)] 既定(N)"

if ($confirm -ne "Y") {
  exit
}

# Excel ファイル名を指定
$fileName = "test.xlsx"

#スクリプトのパスからフォルダパスを取得
$filePath = Split-Path $MyInvocation.MyCommand.Path -Parent

#カレントフォルダとファイル名を結合する
$filePath = Join-Path $filePath $fileName

# Excel ファイルの存在チェック
if (!(Test-Path $filePath)) {
  Write-Host "$fileName が存在しません。"
  exit
}

#Excel COM 呼び出し
$xl = New-Object -ComObject Excel.Application

# Excel ファイルを開く
$wb = $xl.Workbooks.Open($filePath)

# Sheet1 を選択
$ws = $wb.WorkSheets.Item("Sheet1")

#変数初期化
$i = 1
$j = 1
$path = $null


while ($true) {
  #ドライブだけ先に取得する
  $path = $ws.Cells.Item($i, $j).Text
  $j++

  #ディレクトリの指定がなくなるまでパスを取得
  while ($true) {
   if ($ws.Cells.Item($i, $j).Text -eq "") {
    break
   } else {
    $path = Join-Path $path $ws.Cells.Item($i, $j).Text
    $j++ 
   }
  }

  #行がブランクか判定する
  if ($ws.Cells.Item($i, 1).Text -eq "") {
   #ブランクの場合は処理を終了する
   break

  } else {

   #パスが存在しない場合のみフォルダを作成する
   if (!(Test-Path $path)) {
    #フォルダを作成する
    # mkdir の処理結果が表示されないように Out-Null を指定している
    mkdir $path | Out-Null
   }

   #一行進む、変数初期化
   $i++
   $j = 1
  }

}

# Excel ファイルを閉じる
$wb.Close()

# Excel を終了する
$xl.Quit()

# COM 参照を解放する
[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($ws)
[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($wb)
[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($xl)

#終了メッセージを表示する
Write-Host "処理が終了しました。"
Pause

企業内の環境では PowerShell の実行ポリシーの関係で外部スクリプトを実行できないようになっているかもしれません。その場合は下記記事を参考にしてください。


スポンサーリンク


このエントリーをはてなブックマークに追加



Twitter ではブログにはない、いろんな情報を発信しています。


コメント

コメントを書く



プロフィール

  • 名前:fnya
    経歴:
    SE としての経験は15年以上。様々な言語と環境で業務系システム開発を行い、セキュリティ対策などもしていました。現在は趣味SE。

    Twitter では、ブログでは取り上げない情報も公開しています。


    ブログについて

    このブログは、IT、スマートフォン、タブレット、システム開発などに関するさまざまな話題を取り上げたり、雑感などをつづっています。

    >>ブログ詳細
    >>自作ツール
    >>運営サイト
    >>Windows 10 まとめ

    Twitter のフォローはこちらから Facebook ページはこちら Google+ページはこちら RSSフィードのご登録はこちらから