PowerShell V4.0 では DSC があることに言及してきました。
さて、このDSCですが標準で各種リソースに対して処理が可能です。その中には zip解凍処理処理も含まれています。
Built-In Windows PowerShell Desired State Configuration Resources
Provider | Description |
---|---|
Archive Resource | Unpacks archive (.zip) files at specific paths on target nodes. |
Environment Resource | Manages system environment variables on target nodes. |
File Resource | Manages files and directories on target nodes. |
Group Resource | Manages local groups on target nodes. |
Log Resource | Logs configuration messages. |
Package Resource | Installs and manages packages, such as Windows Installer and setup.exe packages, on target nodes. |
Process Resource | Configures Windows processes on target nodes. |
Registry Resource | Manages registry keys and values on target nodes. |
Role Resource | Adds or removes Windows features and roles on target nodes. |
Script Resource | Runs Windows PowerShell script blocks on target nodes. |
Service Resource | Manages services on target nodes. |
User Resource | Manages local user accounts on target nodes. |
これ以外のカスタムリソースの構築に関しては後日記事にします。
Build Custom Windows PowerShell Desired State Configuration Resources
今回は、zip処理に関して、DSCを使わない場合と使った場合での違いを見てみましょう。
目次
DSCを使わない zip処理
いくつかあります。
特に、comを使った処理
と、ZipFile クラス を使った処理
が有名かと思います。*1*2
なお、comを使った処理は、もはやバッドノウハウなので使う理由がありませんしここではあげません。
ZipFileクラスを利用する
.NET 4.5から利用できます。が、ご存じのとおり、 Windows PowerShell は V3.0/4.0 共に .NET4.0ベースなのでこのままでは使えません。
PS D:\> $PSVersionTable Name Value ---- ----- PSVersion 4.0 WSManStackVersion 3.0 SerializationVersion 1.1.0.1 CLRVersion 4.0.30319.33440 BuildVersion 6.3.9600.16384 PSCompatibleVersions {1.0, 2.0, 3.0, 4.0} PSRemotingProtocolVersion 2.2
そこで、みんな大好き Add-Type
を利用します。
Add-Type -AssemblyName "System.IO.Compression.FileSystem"
あとは、C#コードと同様の処理をPowerShellで記述するだけです。
Zip圧縮
利用しやすいように function にしました。
function New-ZipCompression{ [CmdletBinding()] param( [parameter( mandatory, position = 0, valuefrompipeline, valuefrompipelinebypropertyname)] [string] $source, [parameter( mandatory, position = 1, valuefrompipeline, valuefrompipelinebypropertyname)] [string] $destination, [parameter( mandatory = 0, position = 2)] [switch] $quiet ) $zipExtension = ".zip" try { Add-Type -AssemblyName "System.IO.Compression.FileSystem" } catch { } if (-not($destination.EndsWith($zipExtension))) { throw ("destination parameter value [{0}] not end with extension {1}" -f $destination, $zipExtension) } try { $destzip = [System.IO.Compression.Zipfile]::Open($destination,"Update") $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal $files = Get-ChildItem -Path $source -Recurse | where {-not($_.PSISContiner)} foreach ($file in $files) { $file2 = $file.name if ($quiet) { [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($destzip,$file.fullname,$file2,$compressionLevel) > $null $? } else { [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($destzip,$file.fullname,$file2,$compressionLevel) } } $destzip.Dispose() } catch { Write-Error $_ } }
圧縮する時はこのようにします。
d:\testを hoge.zipにzipする場合は次のようにします。
New-ZipCompression -source D:\test -destination d:\hoge.zip
また、-quiet
スイッチで出力結果がホスト表示されません。
New-ZipCompression -source D:\test -destination d:\hoge.zip -quiet
Zip解凍
こちらも利用しやすいように function にしました。
function New-ZipExtract{ [CmdletBinding()] param( [parameter( mandatory, position = 0, valuefrompipeline, valuefrompipelinebypropertyname)] [string] $source, [parameter( mandatory, position = 1, valuefrompipeline, valuefrompipelinebypropertyname)] [string] $destination, [parameter( mandatory = 0, position = 2)] [switch] $quiet ) $zipExtension = ".zip" try { Add-Type -AssemblyName "System.IO.Compression.FileSystem" } catch { } if (-not($source.EndsWith($zipExtension))) { throw ("source parameter value [{0}] not end with extension {1}" -f $source, $zipExtension) } try { $sourcezip = [System.IO.Compression.Zipfile]::Open($source,"Update") $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal if ($quiet) { [System.IO.Compression.ZipFileExtensions]::ExtractToDirectory($sourcezip,$destination) > $null $? } else { [System.IO.Compression.ZipFileExtensions]::ExtractToDirectory($sourcezip,$destination) } $sourcezip.Dispose() } catch { Write-Error $_ } }
解凍する時はこのようにします。
d:\hoge.zipを d:\hogehogeにzip解凍する場合は次のようにします。
New-ZipExtract -source d:\hoge.zip -destination d:\hogehoge
また、-quiet
スイッチで出力結果がホスト表示されません。
New-ZipExtract -source d:\hoge.zip -destination d:\hogehoge -quiet
GitHub
コードを置いておきます。
リモートマシンでのzip処理
DSCを使わないZip処理の場合、valentiaを利用するならリモートマシンでの処理も簡単ですが、valentiaのない環境では.....面倒ですね。
しかし、PowerShell V4.0ならDSCを利用することでZip解凍が簡単になります。
DSCを使った zip解凍処理
DSCの基本は、 configurationキーワードで、ノードとリソースを指定して状態などを宣言することです。
あとは、configurationで実行する内容をmofファイルに吐き出して、Start-DscConfiguration
コマンドレットで実行するだけです。
これは Zip解凍でも変わりません。対象ノードに対して、リソースが Archiveで、対象pathが存在する(Present)を前提にDestinationへの解凍を宣言します。
configuration宣言
実際に処理を見てみましょう。
先ほど文章で示した内容をconfiguration
を使って宣言するだけです。
configuration UnZipFile { param ( [Parameter(mandatory)] [string[]]$ComputerName, [string]$Path, [string]$Destination ) node $ComputerName { archive ZipFile { Path = $Path Destination = $Destination Ensure = 'Present' } } }
configurationを実行してmofを生成する
対象pathとdestinationに対応した .mofを出力します。
mofファイルは、-OutputPath
を指定しないと、現在のパスにconfigurationで宣言した名称(この場合は、UnZipFile)としてフォルダが生成されます。
では、 localostに対して、d:\hoge.zipがあった場合に d:\hogehogeへ解凍する操作とします。
UnZipFile -ComputerName localhost -Path D:\hoge.zip -Destination d:\hogehoge -Verbose
Directory: D:\hoge\UnZipFile Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 2013/10/07 8:24 1140 localhost.mof
mofの実行
mofは出力したフォルダを指定して実行します。 mofファイル自体を実行するわけではないことに注意してください。
こうすることで、対象フォルダに生成されたノード分の処理がまとめて実行されるわけです。
Start-DscConfiguration -Path .\UnZipFile -Wait -Force -Verbose
コマンドに加えた -Wait
スイッチと -Verbose
スイッチで処理内容が見えます。特に-Verbose
スイッチは、定型処理でない限りぜひ付けて実行することを推奨します。
hogehoge.zipファイルがない場合は、処理が失敗します。
VERBOSE: Perform operation 'Invoke CimMethod' with following parameters, ''methodName' = SendConfigurationApply,'className' = MSFT_DSCLocalConfigurationManager,'namespaceName' = root/Microsoft/Windows/DesiredStateConfiguration'. VERBOSE: An LCM method call arrived from computer WINDOWS81X64 with user sid S-1-5-21-3867976201-3469415403-658829222-1001. VERBOSE: [WINDOWS81X64]: LCM: [ Start Set ] VERBOSE: [WINDOWS81X64]: LCM: [ Start Resource ] [[Archive]ZipFile] VERBOSE: [WINDOWS81X64]: LCM: [ Start Test ] [[Archive]ZipFile] VERBOSE: [WINDOWS81X64]: LCM: [ End Test ] [[Archive]ZipFile] in 0.1860 seconds. PowerShell provider MSFT_ArchiveResource failed to execute Test-TargetResource functionality with error message: The specified source file D:\hoge.zip does not exist or is not a file Parameter name: Path + CategoryInfo : InvalidOperation: (:) [], CimException + FullyQualifiedErrorId : ProviderOperationExecutionFailure + PSComputerName : localhost VERBOSE: [WINDOWS81X64]: LCM: [ End Set ] LCM failed to move one or more resources to their desired state. + CategoryInfo : NotSpecified: (root/Microsoft/...gurationManager:String) [], CimException + FullyQualifiedErrorId : MI RESULT 1 + PSComputerName : localhost VERBOSE: Operation 'Invoke CimMethod' complete. VERBOSE: Time taken for configuration job to complete is 0.667 seconds
hogehoge.zipファイルがあれば、処理が実行されます。
VERBOSE: Perform operation 'Invoke CimMethod' with following parameters, ''methodName' = SendConfigurationApply,'className' = MSFT_DSCLocalConfigurationManager,'namespaceName' = root/Microsoft/Windows/DesiredStateConfiguration'. VERBOSE: An LCM method call arrived from computer WINDOWS81X64 with user sid S-1-5-21-3867976201-3469415403-658829222-1001. VERBOSE: [WINDOWS81X64]: LCM: [ Start Set ] VERBOSE: [WINDOWS81X64]: LCM: [ Start Resource ] [[Archive]ZipFile] VERBOSE: [WINDOWS81X64]: LCM: [ Start Test ] [[Archive]ZipFile] VERBOSE: [WINDOWS81X64]: [[Archive]ZipFile] The destination file d:\hogehoge\hogehoge.wav was missing or was not a file VERBOSE: [WINDOWS81X64]: LCM: [ End Test ] [[Archive]ZipFile] in 0.2860 seconds. VERBOSE: [WINDOWS81X64]: LCM: [ Start Set ] [[Archive]ZipFile] VERBOSE: [WINDOWS81X64]: [[Archive]ZipFile] The configuration of MSFT_ArchiveResource is starting VERBOSE: [WINDOWS81X64]: [[Archive]ZipFile] The archive at D:\hoge.zip was unpacked to destination d:\hogehoge VERBOSE: [WINDOWS81X64]: [[Archive]ZipFile] The configuration of MSFT_ArchiveResource has completed VERBOSE: [WINDOWS81X64]: LCM: [ End Set ] [[Archive]ZipFile] in 0.6880 seconds. VERBOSE: [WINDOWS81X64]: LCM: [ End Resource ] [[Archive]ZipFile] VERBOSE: [WINDOWS81X64]: LCM: [ End Set ] VERBOSE: [WINDOWS81X64]: LCM: [ End Set ] in 1.0440 seconds. VERBOSE: Operation 'Invoke CimMethod' complete. VERBOSE: Time taken for configuration job to complete is 1.085 seconds
どうでしょうか。このように DSCを使うことで、Zip解凍のための処理をfunctionで書くことなく宣言するだけで実行できています。
DSCに望むのは、まさにこのあたりの リモートマシン(ノード)に対する処理が宣言で済み、繰り返し実行しても結果が変わらないことです。
Windows 8.1と Windows Server 2012のリリースが間近です。DSC楽しみですね。