検証環境やリリース環境、アドホックなデモ環境用、そのほか様々な環境用に構成ファイルやコンフィグファイルを準備するのは大変ですよね。そこで、変更部分のみを編集する処理を、AntやNAntのようなxmlベースのタスクを記述し、構成ファイルの編集や、コピーを行うプロトタイプ実装をしてみました。

簡単なことしかできませんが、PowerShell はシェルスクリプトなので、機能の追加や、変更を紹介する実装例を元に簡単にできると思います。

1. コンフィグレーションファイルの例

最初に、今回実装するPowerShell版Ant簡易実装 (psant)  で使用するxmlで記述するタスクのサンプルを掲載します。taskset が処理セットの単位で、replace や copy などtaskset がタスクの1単位です。

pant では、tasksetの個ノードを順番に処理します。

<?xml version="1.0"?>
<configuration>
  <!-- 商用環境準備 -->
  <taskset name="task1">
    <!-- ファイルの内容を置換する -->
    <replace from="C:\temp\psant\Target\Web.config" to="C:\temp\psant\Result\Web.config">
      <pattern old="debug=true" new="debug=false" />
      <pattern old="test.domain.local" new="test.domain.com" />
      <pattern old="TEST_SERVER" new="PRODUCT_SERVER" />
    </replace>
    <!-- ファイルをコピーする -->
    <copy from="C:\temp\psant\Target\Config.csv" to="C:\temp\psant\Result\Config.csv" />
  </taskset>
  <!-- デモ用環境 -->
  <taskset name="task2">
    <move from="C:\temp\psant\Demo\Web.config" to="C:\temp\psant\Demo\Web.config.bak" />
    <copy from="C:\temp\psant\Result\Web.config" to="C:\temp\psant\Demo\Web.config" />
  </taskset>
</configuration>

2. psant.ps1 の実装

次のタスクを行えるようにしています。psant.ps1を実装しています。

タスク 説明
replace ファイル内の特定文字列を置き換えます。
copy ファイルをコピーします。
move ファイルを移動します。

スクリプトpsant.ps1の内容は次の通りです。中を見てみればわかるとおり非常に簡単なスクリプトです。PowerShellのxml処理機能やコマンドレットが協力だからなんですが。タスクを動的にプラグインできるような仕組みを作ったほうがよいのでしょうが、方法などしっかり調査していません。簡易実装ということで簡便ください。

# copy 命令を処理する関数
function Copy-Task([System.Xml.XmlElement] $opnode)
{
	Write-Output "Copy-Taskを開始します"

	$from = $opnode.from
	$to  =  $opnode.to

	Write-Output "$from から $to にコピーします"
	Copy-Item $from $to

}
# move 命令を処理する関数
function Move-Task([System.Xml.XmlElement] $opnode)
{
	Write-Output "Move-Taskを開始します"

	$from =$opnode.from
	$to = $opnode.to

	Write-Output "$from から $to に移動します"
	Move-Item $from $to
}

# replace 命令を処理する関数
function Replace-Task([System.Xml.XmlElement] $opnode)
{
	Write-Output "Replace-Task を開始します"

	# 文字コード設定
	$from_enc = "UTF8"
	$to_enc = "UTF8"
	if($opnode.from_encoding -ne $null){
		$from_enc = $opnode.from_encoding
	}
	if($opnode.to_encoding -ne $null){
		$to_enc = $opnode.to_encoding
	}
	# ファイル読み込み
	$content = Get-Content $opnode.from -encoding $from_enc

	$expression = '$content'
	$replaceTemplate = ' | %{{ $_ -replace "{0}","{1}" }} '

	# 置換文字列解析
	for($i=0; $i -lt $opnode.psbase.ChildNodes.Count; $i++){
		$pattern = $opnode.psbase.ChildNodes.psbase.Item($i)
		if($pattern.psbase.NodeType -eq "Element"){
			$expression += ($replaceTemplate -f $pattern.old,$pattern.new)
		}
	}
	Write-Output "作成された置換命令"
	Write-Output $expression	
	# Invoke-Expression を呼び出す
	$result = Invoke-Expression $expression
	
	# 変更を保存
	Out-File $opnode.to -encoding $to_enc -inputObject $result
}

# 命令に従って適切な処理関数を呼び出す関数
function Invoke-Task([System.Xml.XmlElement] $opnode)
{
	switch ($opnode.psbase.Name) 
	{
		"copy"		{ Copy-Task $opnode; break; }
		"replace"	{ Replace-Task $opnode; break; }
		"move"		{ Move-Task $opnode; break; }
		default { Write-Output "認識されないオペコード $_" }
	}
}
function Main($config, $name)
{
	$root = [xml] (Get-Content $config)
	$query = "/configuration/taskset[@name=""$name""]";

	$nodes = $root.SelectNodes($query)

	if($nodes.Count -ne 1){
		Write-Output "対象tasksetは1つである必要が有ります"
		Write-Output "ノードが{0}つ見つかりました" -F $nodes.Count
	}
	$deployset = [System.Xml.XmlElement] $nodes.psbase.Item(0)

	for($i=0; $i -lt $deployset.psbase.ChildNodes.Count; $i++){
		$op = $deployset.psbase.ChildNodes.psbase.Item($i)
		if($op.psbase.NodeType -eq "Element"){
			Invoke-Task $op
		}
	}
}

Main メソッドが処理のエントリです。使用する場合はpowershellのコンソールを起動し、以下のコードのように . .\psant.ps1 で読み込みを行い、 "Main  コンフィグのパス  タスクセット名" を指定してタスクを実行します。

PS C:\temp\psant> . .\psant.ps1
PS C:\temp\psant> Main "C:\temp\psant\config.xml" "task1"
Replace-Task を開始します
作成された置換命令
$content | %{ $_ -replace "debug=true","debug=false" }  | %{ $_ -replace "test.domain.local","test.domain.com" }  |
$_ -replace "TEST_SERVER","PRODUCT_SERVER" }
Copy-Taskを開始します
C:\temp\psant\Target\Config.csv から C:\temp\psant\Result\Config.csv にコピーします

3. まとめ

今回の説明は以上です。誤り、指摘点やこうしたほうがよいなどあればご連絡ください。