2012年10月11日木曜日

◆ShowUIモジュールでWPFウインドウを使ってみる

CodePlexでShowUIというモジュールが提供されている。
ShowUI: Write-UI -in PowerShell

Powershellでのフォーム(ウインドウ)表示をサポートするモジュールの様である。

確かに、ちょっとしたウインドウが簡単に表示できたら便利。

という事でモジュールをダウンロードしてサンプルを実行してみた。

ダウンロードしたモジュールは「$env:psmodulepath」で定義されている場所に置けば良さそうなので、「ドキュメント\WindowsPowerShell\Modules」に置いた。

あとは以下のようなサンプルが掲載されているのでそのまま実行してみる。

Import-Module ShowUI
$getEventInput = StackPanel -ControlName 'Event Logs Since' {
  New-Label -VisualStyle 'MediumText' "Log Name"
  New-ComboBox -IsEditable:$false -SelectedIndex 0 -Name LogName @("Application", "Security", "System")
  New-Label -VisualStyle 'MediumText' "Get Event Logs Since..."
  Select-Date -Name After
  New-Button "Get Events" -On_Click {
  Get-ParentControl | Set-UIValue -passThru | Close-Control
  }
} -show
$getEventInput.remove("togglebutton")
Get-EventLog @getEventInput

すると以下のようなウィンドウが表示されて選択したイベントログが表示されるという寸法だ。
image

さすがはWPF、画面を広げるとカレンダーも増えてくれる。
image

暇ができたらもう少し遊んでみたい。

ちなみに、初回実行すると「Documents\WindowsPowerShell\Modules\ShowUI\StyleSystem」に「Styles」フォルダが無い、っと怒られるので作ってあげる。

すると今度は、その中に「Current.style」ファイルが無い、っと怒られる。
このファイル自体は「Documents\WindowsPowerShell\Modules\ShowUI\StyleSystem」に存在しているのでコピーしてあげる。

2012年10月10日水曜日

◆プロパティ名を纏めて変更する

プロパティ名を変更するには「算出プロパティ」(集計プロパティ)を使えば良い。

「算出プロパティ」はハッシュテーブルの形式で指定するので項目が多いとちょっと面倒だ。

そこで名称を単純に配列で指定できるようにしようというTipsがあったのでメモしておく。

PowerShell Tips
改行箇所を調整しているが基本的にそのまま転載。

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019

$data = @(tasklist /V /FO CSV | ConvertFrom-Csv)

$columns = $data[0].PSObject.Properties |
 
 
Where-Object { $_.MemberType -eq 'NoteProperty' } |
 
 
Select-Object -ExpandProperty Name

$columnNames =
 
 
'Name', 'ID', 'Session', 'SessionID', 'Memory',
 
 
'Status', 'Owner', 'CPU', 'Title'

$customProperties = $columns | %{$i=0
}{ 
    @{
     Name 
= $columnNames[$i]
     Expression=[ScriptBlock]::Create(('$_.''{0}''' -f $columns[$i]
))
   }
  
$i++
 
}


$data | Select-Object -Property $customProperties

若干判り辛いので説明を書いておく。

1行目で「tasklist」コマンドでプロセスの一覧を取得している。
「Get-Process」を使っていないのは今回の例で言えば特に理由は無いが、そのまま使用している。
結果は、そのままだと以下のように表示される。
image

ここで、 19行目を「算出プロパティ」で直接書くと以下のようになる。

$data |
  Select-Object @{name="Name";expression={$_.$($columns[0])}},
                @{name="SessionName";expression={$_.セッション名}},
                @{name="Memory";expression={$_.$($columns[4])}}

image

3項目しか記載していないが、全項目書くとなると確かに煩雑。

そこで、7行目で出力プロパティをテーブルで指定して、11行目でハッシュテーブルをロジカルに作り出している。
肝は[ScriptBlock]クラスの「Create」メソッド。
変数値を解決しつつブロックを作り出している。

この例では日本語から英語に変えているが、英語の項目名を纏めて日本語にするなんて時には使えそうなTipsではなかろうか。

2012年10月5日金曜日

◆Excel無しにExcelファイルを作る4(EPPlusバージョン)

前回EPPlusというパッケージの情報があったのでこれを使ってみる。

EPPlus-Create advanced Excel 2007 spreadsheets on the server

名前からしてもExcelPackeageのPlusなので、こちらの方が偉そうだ。

最終更新日が2007年のExcelPackeageに比べ、こちらは2012年9月と今でも開発が継続されていそうなので機能・品質ともに期待できる。

ちょこちょこ調べながら使ってみたが、あまり悩むことも無く簡単に使えた。
書式も結構自由に設定できるのでサーバーでちょっとしたレポートを作るには十分といった感じ。

品質的にも日本仕様でちょっとうまくいかない(金額の$編集は出来るが\編集ができない)ことが有ったが、ExcelPackeageよりはかなり良さげ。

難しくないのでサンプルソースだけUPしておく。

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056

#Excelモジュールロード
$scriptPath = Split-Path $myInvocation.MyCommand.path 
$dllPath = Join-Path $scriptPath "dll\EPPlus" |
 
 
Join-Path -ChildPath EPPlus.dll 
[Reflection.Assembly]::LoadFrom($dllPath) | Out-Null

#Excelシート作成
$filePath = join-path ([Environment]::GetFolderPath("desktop")) "test.xlsx"
if(test-path $filepath){del $filePath}
$excel = New-Object OfficeOpenXml.ExcelPackage -ArgumentList 
$filePath
$sheet
 = $excel.Workbook.Worksheets.Add("テストシート1")

$sheet.Cells["A1"].Value = "NO"
$sheet.Cells["A1"].Style.Font.Bold = 
$true

$cell
 = $sheet.Cells.Item(1,2) 
$sheet.Cells.Item(1,2).Value = "名前"
$sheet.Cells.Item(1,2).Style.Font.Size = 18
$cell.Style.Font.Name = "メイリオ"
$cell.Style.Font.Color.SetColor("red")
$cell.Style.Fill.PatternType = [OfficeOpenXml.Style.ExcelFillStyle]::Solid
$cell.Style.Fill.BackgroundColor.SetColor([Drawing.Color]::Green)
$cell.Style.Border.BorderAround([OfficeOpenXml.Style.ExcelBorderStyle]::Thick)

$sheet.Cells["C1"].Value = "住所"
$sheet.Cells.Item(2,1).Value = 1
$sheet.Cells.Item(2,2).Value = "原辰則"
$sheet.Cells.Item(2,3).Value = "田園調布"
$sheet.Cells.Item(3,1).Value = 2
$sheet.Cells.Item(3,2).Value = "中畑清"
$sheet.Cells.Item(3,3).Value = "所沢"

$sheet.Cells["D1"].Value = "年棒"
$sheet.Cells["D2"].Value = 1200000
$sheet.Cells["D2"].Style.Numberformat.Format = "#,##0"
$sheet.Cells["D2"].Style.Font.Name = "メイリオ"
$sheet.Cells["D3"].Value = 4200000
$sheet.Cells["D3"].Style.Numberformat.Format = "#,##0"

$sheet.Cells["A4"].Formula = "SUM(A2:A3)"
$sheet.Cells["B4"].Formula = "A2+A3"

$sheet.Cells["A1:D1"].Style.HorizontalAlignment =
 
 
[OfficeOpenXml.Style.ExcelHorizontalAlignment]::Center

$sheet.Cells["A2:C3"].Style.Border.Left.Style =
 
 
[OfficeOpenXml.Style.ExcelBorderStyle]::Dotted
$sheet.Cells["A2:C3"].Style.Border.Top.Style =
 
 
[OfficeOpenXml.Style.ExcelBorderStyle]::Dotted
$sheet.Cells["A2:C3"].Style.Border.Right.Style =
 
 
[OfficeOpenXml.Style.ExcelBorderStyle]::Dotted
$sheet.Cells["A2:C3"].Style.Border.Bottom.Style =
 
 
[OfficeOpenXml.Style.ExcelBorderStyle]::
Dotted
 

$excel.Save()
$excel.Dispose()

結果は、こんな感じのExcelが出来上がる。

image

いい感じ。

なぜか、Windows8では依存関係ファイルが見つからないといってDLLがロードできなかったが(C#ではOK)、サーバー側は当面2012にはならないので良しとした。

また、ExcelPackeageではテンプレートファイルを使ってExcelを作るケースが多かったのでEPPlusでも試してみたのだが、ExcelPackeageと同様の指定ではうまくいかなかった。

コンストラクタの定義を見ると、出力ファイル・テンプレートファイルともに「FileInfo」型をサポートしていたので、ファイルパスの文字列では無く、ちゃんと「FileInfo」オブジェクトを作ってアサインするとうまくいった。

#FileInfo作成(出力ファイル、テンプレートファイル)
$templateInfo = New-Object System.IO.FileInfo($templatePath)
$fileInfo = New-Object System.IO.FileInfo($filePath)

$excel = New-Object OfficeOpenXml.ExcelPackage -ArgumentList $fileInfo,$templateInfo
#$sheet = $excel.Workbook.Worksheets.Add("テストシート1")
$sheet = $excel.Workbook.Worksheets["sheet1"]

2012年10月4日木曜日

◆Excel無しにExcelファイルを作る3

PowerShell: ◆Excel無しにExcelファイルを作る2の続き

なんだかんだ言って、このExcelPackageの使用頻度は非常に高い。
自分で見るだけなら良いのだが、人に見せる場合はExcelでとなるケースが多い。

非常に便利に使えてはいるのだが、品質的には若干怪しい部分も多い。

今回も躓いた部分をメモしておく。

<IPアドレスが苦手>

セルにIPアドレスを設定するケースがあったのだが、出来上がったExcelファイルを開くと、
image

といったエラーメッセージが表示される。

一応「はい」を応答すると開けるようになるだが、これでは何ともいただけない。

色々試してみたのだが、どうも数字と複数のピリオドの組み合わせがダメっぽい。
全くの想像だが、本来数字と複数のピリオドは文字列属性の指定をするべきところ誤って数値属性を指定しているといった感じではなかろうか。

なので、ピリオドと数字以外の文字を付加してあげてExcelPackeageが文字列と判断するよう手助けしてあげれば良い。

元のIPアドレスに影響を与え無いようにするためには、頭にスペースを付加してあげると良さそうだ。
すると、うまい具合にエラーも回避されるしExcelとして開いたときに付加したスペースも消えてくれる。

<複数シートのテンプレートが苦手>

テンプレートに、実際データを表示するシートの他にルックアップテーブル等の為に固定的なシートが必要なケースがあった。

しかし、このテンプレートを使ってExcelファイルを作ると
image

といったエラーになってしまう。
ググってみると以下の情報が見つかり、やっぱりバグでソース修正が必要だとか。
ベトさんの記録簿: ExcelPackage

自分でソースは修正できないので、運用的な回避先を探ってみる。
エラーメッセージからすると要はヌル参照なので、固定シートに対して何もしていないのが良くないのでは?と想像できる。

そこで、意味もなく適当なセルをスペースとかで更新してあげる。

ビンゴ

たまたまかもしれないが良しとする。

 

上記サイトの中で気になる記述があった。
image

ん~、これは使ってみなくては。

2012年10月3日水曜日

◆別の資格情報で管理者として実行する

別のユーザーとしてアプリケーションを実行するには、そのアプリケーションを「Shift + 右クリック」で表示される「別のユーザーとして実行」を選択すればよい。
image

頻繁に使用する場合は面倒なのでスクリプトにしておきたいところだ。

まずは、パスワードを保存しておく。

ConvertFrom-SecureString (Get-Credential).Password | Set-Content myPass

これを読み込んで資格情報を作る。

$password = ConvertTo-SecureString (gc myPass)
$cred =
  New-Object System.Management.Automation.PsCredential "usr",$password

あとは「Start-Process」コマンドレットでこの資格情報を使ってアプリケーションを起動してあげれば良い。

Start-Process -FilePath notepad -Credential $cred

 

ちなみに、アプリケーションを「管理者として実行」するにはこんな感じ。

Start-Process -FilePath dsac -Verb runas

しかし、別の資格情報でなおかつ「管理者として実行」しようとすると、うまくいってくれない。

Start-Process -FilePath dsac -Verb runas -Credential $cred

image

同時には指定できないという事なのだろうか・・・。

仕方がないのでとりあえずこんな形にしてみた。

Start-Process -FilePath powershell.exe -Credential $cred `
  -ArgumentList "dsac.exe -Verb runAs"

もう少し、スマートな方法が有りそうにも思う・・・。

あれー、このアプリケーション、直接実行する時(自ユーザー)は「管理者として実行」が必要ない。

でも、メモ帳はOKなのだが、

Start-Process -FilePath "notepad.exe" -Credential $cred

これはダメ。

Start-Process -FilePath "dsac.exe" -Credential $cred

image

 

試してみたら、これはOK。

Start-Process -FilePath powershell.exe -Credential $cred `
  -ArgumentList "dsac.exe"

ん~・・・。

--

PowerShell: ◆別の資格情報で管理者として実行する2