Bar

PowerShell とタスク スケジュールを使ってExcelファイルの自動処理・印刷を行う方法

先日「Access 2013 コマンドライン スイッチを使って帳票を自動印刷する方法~起動後のマクロ実行」という記事を書きましたが、Excelを使った場合はどうすればいいか試行錯誤しましたが、何とか実現できました。
今回は、PowerShellとタスク スケジュールを使って、Excelファイルの自動処理や自動印刷を行う方法をメモ。

注意事項:記事を説明する前に

毎度のお約束になります。
Accessと異なり、Excelは標準のコマンドライン スイッチに自動実行用スイッチがありません。
標準で用意していない=今回のような処理はマイクロソフトは想定していないと考えられます。
創意工夫の内容ではありますが、本内容は全て自己責任の下で作業してくださいm(_ _)m
2014.05.08、2014.05.28 追記
本内容は、マイクロソフトが推奨しない・サポートしない内容になります。
必ず、下記Webページの熟読をお願い致します。
なお、代替え案が提案されています。

今回の環境

今回の環境は下記を使用します。
あらゆる企業の環境でも簡単に実践できるはずです。
  1. Windows 7 32bit(SP1なし)
  2. Excel 2003 32bit SP3
  3. PowerShell 2.0
  4. 常にログオフ状態である
マクロの自動実行や終了処理はExcelだけでは出来ない※ため、基本処理はExcel、自動実行はPowerShellでコントロールします。
※やり方を知らないだけかもしれませんが・・・

流れ

  1. Excel VBA(Visual Basic for Application)を使った業務アプリケーションを開発
    自動実行させるマクロ関数を記述。
    マクロ関数の参照レベルはPublic、標準モジュール等に配置。
  2. PowerShellからExcelファイルを呼び出し、自動実行用マクロ関数を実行するスクリプト ファイル(.ps1)を作成
    PowerShellのサンプルは後程。
  3. タスク スケジュールにスクリプト ファイル(.ps1)を登録、実行
    任意の時間に実行させます。
基本的な流れは上記3点になりますが、後述する注意点は非常に重要です。

注意点

今回Excelファイルの自動処理を行うため、調べ上げるのに時間がかかった箇所(注意点)と嵌りそうな点をメモしておきます。
1.PowerShellの実行ポリシーに注意!
よくありがちな話ですが、PowerShellの標準実行ポリシーはRestrictedになっており、ps1ファイルの実行は出来ません。
必ずRemoteSigned等に変更しましょう。
PowerShellの基本 スクリプトの実行ポリシーを変更~ps1ファイル実行時のエラー
2.PowerShellからExcelのマクロ関数を実行するには?
PowerShellからExcelファイルを操作するには、ExcelのCOMコンポーネントを利用します。
Microsoft.Office.Interop.Excel 名前空間
Workbooks.Open メソッド
ApplicationClass メンバ
PowerShellを使ったInternet Explererのオートメーションを行った経験があるためか、比較的簡単にPowerShellを記述できました。
問題となる「自動実行用マクロ関数を実行する」には、Runメソッドを利用します。
ApplicationClass.Run メソッド
PowerShellのサンプルは下記の通りです。
# オブジェクト作成
$xls = New-Object -ComObject Excel.Application
# Excel表示&ファイル起動
$xls.Visible = $True
$wb = $xls.workbooks.open("D:\hoge.xls")
# マクロ実行
$xls.Run("自動実行用マクロ関数名")
# 保存
$wb.Save()
# Excelを閉じる
$xls.Quit()
# オブジェクト解放
$wb = $null
$xls = $null
[GC]::Collect()
最後の3行は特に大事です。
$xls.Quit()を実行すると見た目はウィンドウが消えていますが、プロセスは残ります。
サーバ等無停止運用の場合、実行するたびにメモリを消費し最後にはメモリがひっ迫するはずです。
そこで、実行後にオブジェクトを解放をする必要があります。
ガベージ・コレクトを強制する前にCOMオブジェクトを$nullを代入しておくと即時解放する可能性が高まるそうです。
$nullの代入を行ってからガベージ・コレクトを強制実行したところ、即プロセスがなくなりました。
Office オートメーションで割り当てたオブジェクトを解放する – Part2
Devの方にとっては当たり前の話なんでしょうね。まだまだ修行が足りませんな・・・

トラブルシューティング

タスク スケジューラの実行が失敗する Part1
タスク スケジューラの登録する際、[プログラム/スクリプト]に
%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
を登録し、スクリプト ファイル(.ps1)は[引数の追加(オプション)]に
xxx.ps1 [オプション]
を登録します。
タスク スケジューラの実行が失敗する Part2
タスク スケジュールにPowerShell スクリプト ファイル(.ps1)を登録しタスクを実行すると全く反応しませんでした。
調べてみるとExcelのオートメーション時によくはまる内容のようで、下記に示すフォルダを作成することで解決しました。
  • x86 - C:\Windows\System32\config\systemprofile\Desktop
  • x64 - C:\Windows\SysWOW64\config\systemprofile\Desktop
今回の処理を行うには[仮想デスクトップフォルダの存在が不可欠]だそうです。
Desktopフォルダのチェックおよび作成するPowerShellは下記になります。
$x86Desktop = "C:\Windows\System32\config\systemprofile"
$x64Desktop = "C:\Windows\SysWOW64\config\systemprofile"
$createFolder = "Desktop"
#32-bit
if(-not $(test-path("$x86Desktop\$createFolder")))
{
    Set-Location $x86Desktop
    New-Item $createFolder -ItemType Directory
}
#64-bit
$OsArch = Get-WmiObject Win32_OperatingSystem | Select-Object OSArchitecture
if($OsArch.OSArchitecture -eq "64 ビット"){
    if(-not $(test-path("$x64Desktop\$createFolder")))
    {
        Set-Location $x64Desktop
        New-Item $createFolder -ItemType Directory
    }
}
タスク スケジューラが失敗する Part3
こちらもよくある話でしょう。
タスク スケジュールに登録したタスクの権限等です。
タスクを登録する際、下記2点の設定を行わないとタスク実行が失敗します。
  • 「ユーザがログオンしているかどうかにかかわらず実行する」を選択
    ※「パスワードに保存しない」にはチェックしない
  • 「最上位の特権で実行する」にチェック
image
更新履歴

  • 2014.05.08
    注意点に追記しました。
  • 2014.05.28
    注意点に追記しました。
  • 2017.05.12
    PowerShell サンプル スクリプトを修正しました