2013年12月1日日曜日

PowerShellでシンプルなテンプレートエンジンを作成する

概要

テスト環境や本番環境のアプリリリースにて一部(IPアドレス等)以外、リリース手順が同じ場合
また、メール送信ファイル作成にてユーザ情報以外同一の場合など
毎回、記述するのが面倒なのでシンプルなテンプレートエンジンを作成する

テンプレートファイルと入力データよりファイルを出力する
・テンプレートファイルが存在しない場合はメッセージを出力してなにもしない
・テンプレートの変換は「Hashtable」を使う( @{キー名 = 値; キー名 = 値; ....... })
「Hashtable」の「キー名」にテンプレートに記述した値を設定、「値」に変更する入力データを設定
文字コードのデフォルトは「UTF8」(テンプレートファイル、出力ファイル)

関数


実行例

・テンプレートファイル(Mail_Template.txt)

{LAST_NAME} {FIRST_NAME} 様
ご購入ありがとうございます。

~省略~
・powershell実行
# メールテンプレート指定
$MailTemplateFile = "C:\template\Mail_Template.txt"
# ユーザ情報セット
$User = @{"{LAST_NAME}"="山田"; "{FIRST_NAME}"="太郎"}
# 出力ファイル指定
$MailFile = "C:\Temp\Mail_001.txt"
# 実行
Render-Template -TemplateFilePath $MailTemplateFile -Data $User -OutPutFilePath $MailFile

2013年11月14日木曜日

URLエンコード、URLデコードをする

関数



実行例

# 実行
PS > Get-URLEncode -VALUE "あいうえお" -ENCODING "utf-8"
%e3%81%82%e3%81%84%e3%81%86%e3%81%88%e3%81%8a
# 実行
PS > Get-URLDecode-VALUE "%e3%81%82%e3%81%84%e3%81%86%e3%81%88%e3%81%8a" -ENCODING "utf-8"
あいうえお

メモ

文字コードの指定「Encoding.GetEncoding」


2013年11月3日日曜日

ファイル名を置換する

関数


実行例

$FolderPath = "C:\sample"
$Include = "*.xls"
$Befor = "\["
$After = "【"
Get-ChildItem $FolderPath -Recurse -Include $Include |
ForEach-Object{
  Replace-FileName -FilePath $_.FullName -Befor $Befor -After $After
}

2013年10月30日水曜日

Linux上でH2 Databaseが起動しない

概要

Linux上でH2 Databaseが起動しない
理由はホスト名が/etc/hostsに記述されていないためエラーが発生

詳細

実行

/h2-1.3.173.jar org.h2.tools.Server

エラー内容

Exception in thread "main" org.h2.jdbc.JdbcSQLException: 入出力例外: "java.net.UnknownHostException:
 XXXXXXX.local: XXXXXXX.local: 名前またはサービスが不明です"
IO Exception: "java.net.UnknownHostException: XXXXXXX.local: XXXXXXX.local: 名前またはサービスが不明です" [90028-173]
 at org.h2.message.DbException.getJdbcSQLException(DbException.java:331)
 at org.h2.message.DbException.get(DbException.java:160)
 at org.h2.message.DbException.convert(DbException.java:275)
 at org.h2.util.NetUtils.getLocalAddress(NetUtils.java:263)
 at org.h2.server.web.WebServer.updateURL(WebServer.java:328)
 at org.h2.server.web.WebServer.init(WebServer.java:317)
 at org.h2.tools.Server.<init>(Server.java:51)
 at org.h2.tools.Server.createWebServer(Server.java:413)
 at org.h2.tools.Server.runTool(Server.java:306)
 at org.h2.tools.Server.main(Server.java:117)
Caused by: java.net.UnknownHostException: XXXXXXX.local: XXXXXXX.local: 名前またはサービスが不明です
 at java.net.InetAddress.getLocalHost(InetAddress.java:1466)
 at org.h2.util.NetUtils.getLocalAddress(NetUtils.java:261)
 ... 6 more
Caused by: java.net.UnknownHostException: XXXXXXX.local: 名前またはサービスが不明です
 at java.net.Inet6AddressImpl.lookupAllHostAddr(Native Method)
 at java.net.InetAddress$1.lookupAllHostAddr(InetAddress.java:894)
 at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1286)
 at java.net.InetAddress.getLocalHost(InetAddress.java:1462)
 ... 7 more

解決方法

/etc/hostsに記述することで解決

hostsの確認

$ hostname
XXXXXXX.local
$ cat /etc/hosts
127.0.0.1 localhost

hostsの修正

$ vi /etc/hosts
127.0.0.1  XXXXXXX.local localhost

2013年10月24日木曜日

フォルダ配下のファイル名を作成日時順に連番を付ける

関数


メモ

DateTime型をソートする場合、キャスト(変換)しないといけない
Sort-Object {$_.CreationTime -as [DateTime]} 

2013年10月22日火曜日

配列から重複を削除

概要

HashSetを使用して配列の値を一意にする。
プリミティブ型の場合、そのまま使えないのでオブジェクトにラップして一意にする。

メソッド


2013年10月14日月曜日

2つのCSVファイルから項目に一致した行を出力

概要

2つのCSVファイル(顧客マスタ、商品マスタ)から、顧客マスタに商品マスタ.商品コードが存在するものをPowerShellを使ってCSV出力する

メモ

CSVファイル

■商品マスタ(items.csv)

ITEM_ID,ITEM_NAME
10000,AAAAAA
10001,BBBBBB
10002,CCCCCC
・・・・
・・・・
■顧客マスタ(customers.csv)
CUSTOMER_ID,ITEM_ID,CUSTOMER_NAME,QUANTITY
8000,10000,aaaaa,100
8000,10002,bbbbb,50
8001,10005,ccccc,1000
・・・・
・・・・

SQL文だと以下のような感じ

■SQL

SELECT CUSTOMERS.* FROM CUSTOMERS, ITEMS 
WHERE CUSTOMERS.ITEM_ID = ITEMS.ITEM_ID

PowerShell その1

$result = Import-Csv c:\items.csv | Select-Object ITEM_ID 
Import-Csv c:\customers.csv | Where-Object {$result -match $_.ITEM_ID} | Export-Csv c:\output.csv -NoType
customers.csvが10万件、items.csvが1万件で約数十分ぐらいかかる(※スペックによるがとにかく遅い!!)

PowerShell その2

その1の場合、シンプルだが遅いので
items.csvをHashTableにセット(ITEM_IDに重複がないこと)する方法で解決した(約20秒ぐらいで終わる)

$hash = @{}
Import-Csv c:\items.csv | ForEach-Object {$hash.Add($_.ITEM_ID, $_)}
Import-Csv c:\customers.csv | ForEach-Object {if($hash.Get_Item($_.ITEM_ID)){$_}} | Export-Csv c:\output.csv -NoType

2013年10月6日日曜日

音楽ファイルのタグ情報を取得する

概要

フォルダ配下の音楽ファイルのタグ情報を取得する。

・タグ情報を取得するため「taglib-sharp.dll」を使用する。
以下のサイトより取得後、任意の場所に解凍する。
http://download.banshee.fm/taglib-sharp/2.1.0.0/
ファイル名:taglib-sharp-2.1.0.0-windows.zip

関数


実行例

 Get-MusicTagData -MusicFolderPath "C:\develop\flac\MR.BIG\Big, Bigger, Biggest"

メモ

タグ情報/プロパティ情報をすべて取得(※taglib-sharp.dllから取得できるすべて)

$TagLib = "C:\develop\lib\taglib-sharp.dll"
# ライブラリ読み込み
[System.Reflection.Assembly]::LoadFile($TagLib)
# タグ情報を取得するファイル名を指定
$audiofile = [TagLib.File]::Create("C:\develop\flac\MR.BIG\Big, Bigger, Biggest\01 Addicted to that rush.flac")
# タグ情報を取得
$audiofile.Tag
# プロパティ情報を取得
$audiofile.Properties

2013年9月18日水曜日

CentOSにH2 Databaseをインストール

概要

H2 Databaseをインストールすることがメインなので、今回はパーミッション、アクセス権限は考えない

メモ

Javaをインストール


H2 DataBaseをインストール


H2 DataBaseに接続

# H2 DataBaseに起動
/usr/local/java/latest/bin/java -cp /opt/database/h2/bin/*.jar org.h2.tools.Server

Welcome to H2 Shell 1.3.173 (2013-07-28)
Exit with Ctrl+C
[Enter]   jdbc:h2:~/test
URL
[Enter]   org.h2.Driver
Driver
[Enter]   sa
User
[Enter]   Hide
Password
Password
Connected
Commands are case insensitive; SQL statements end with ';'
help or ?      Display this help
list           Toggle result list / stack trace mode
maxwidth       Set maximum column width (default is 100)
autocommit     Enable or disable autocommit
history        Show the last 20 statements
quit or exit   Close the connection and exit

sql> SELECT * FROM INFORMATION_SCHEMA.CATALOGS ;
CATALOG_NAME
TEST
(1 row, 7 ms)
sql> exit;
Connection closed

2013年9月9日月曜日

xmlからログ設定を取得

概要

ログ出力する設定をXMLから取得する関数を作成する。

・初期設定はpsに記述する
・XMLにアペンダを記述して選べるようにする

関数


XML設定


実行例

# XML読込
Set-LogSetting -XMLFilePath "C:\log4ps.xml" -Appender "unit"
# ログ出力
Write-DebugLog -VALUE "デバッグ"
Write-InfoLog -VALUE "情報"
Write-WarnLog -VALUE "警告"
Write-ErrorLog -VALUE "エラー" 

2013年9月7日土曜日

ファイルサイズでファイルをローテーションする

概要

ログを出し続けるとファイルサイズが大きくなりすぎて、処理が遅くなったり、ログの移動・参照もたいへんなので
ファイルサイズよりローテーションを行う関数を作成

・指定したファイルサイズ以上になったらローテーションを行う
・ローテーションする回数も指定する
・ローテーションしたファイル名は「ログファイル名」+「.」+「回数」

関数


日付でファイルをローテーションする

概要

日付よりローテーションを行う関数を作成

・ファイルの作成日が現在の日付でない場合にローテーションを行う
・ローテーションしたファイル名は「ログファイル名」+「.」+「日付フォーマット」

関数


2013年9月3日火曜日

ファイル名に角括弧[]がついてるとRename-Itemで失敗する

概要

ファイル名に角括弧[]がついてるとRename-Itemで失敗するので、Move-Itemを代用する

関数

# ------------------------------------------------------------------
# ファイル名をリネームする
# 関数名:Rename-File
# 引数  :FilePath 名前を変更するファイルパス
#       :NewFileName 新しいファイル名前
# 戻り値:なし
# ------------------------------------------------------------------
function Rename-File([String]$FilePath, [String]$NewFileName){
  if(Test-Path -LiteralPath $FilePath -PathType Leaf){
    $newFilePath = Join-Path -Path (Split-Path $FilePath -Parent) -ChildPath $NewFileName
    Move-Item -LiteralPath $FilePath -Destination $newFilePath
  }else{
    Write-Host "ファイルが存在しません。ファイル名[ $FilePath ]"
  }
}
 
# ------------------------------------------------------------------
# フォルダ名をリネームする
# 関数名:Rename-Folder
# 引数  :FolderPath 名前を変更するフォルダパス
#       :NewFolderName 新しいフォルダ名前
# 戻り値:なし
# ------------------------------------------------------------------
function Rename-Folder([String]$FolderPath, [String]$NewFolderName){
  if(Test-Path -LiteralPath $FolderPath -PathType Container){
    $newFolderPath = Join-Path -Path (Split-Path $FolderPath -Parent) -ChildPath $NewFolderName
    if(Test-Path -LiteralPath $FolderPath -PathType Container){
      Write-Host "既に存在するフォルダを作成することはできません。フォルダー名[ $FolderPath ]"
    }else{
      Move-Item -LiteralPath $FolderPath -Destination $newFolderPath
    }
  }else{
    Write-Host "フォルダが存在しません。フォルダ名[ $FolderPath ]"
  }
}

実行例

Rename-File -FilePath "C:\[20130903]新規要件定義\[20130903]Webログイン.xls" -NewFileName "Webログイン.xls"
Rename-Folder -FolderPath "C:\[20130903]新規要件定義" -NewFolderName "[20130903]要件定義"

2013年8月29日木曜日

ログレベルによって出力するログを制御する

概要

開発環境・本番環境等でログに出すログレベルが違うので制御できるように関数を作成する

・ログ出力は「Out-LogFile」関数を使用する。なのでログレベルはそれに合わせる。
・引数は出力する文字列のみとする。それ以外の「Out-LogFile」関数に必要な引数を先に指定する。

関数


実行例

### 最初に設定を指定
# ログファイル出力先を指定
[String]$LogFilePath ="C:\common.log"
# ログエンコードを指定
[String]$LogEncoding="UTF8"
# ログレベルを指定する(0:デバック,1:情報,2:警告,3:エラー)
[Int]$LogLevel=1

# 実行例
for ($i = 0; $i -lt 100; $i++) {
  Write-DebugLog -VALUE "デバッグ"
  Write-InfoLog -VALUE "情報"
  Write-WarnLog -VALUE "警告"
  Write-ErrorLog -VALUE "エラー" 
}

2013年8月27日火曜日

ファイル名、フォルダ名をリネームする

概要

何度もフォルダを右クリックして名前変更していくのが大変なので関数化する

変更するファイル名、フォルダ名とリネームする名前を指定して実行
・指定した「ファイル名」「フォルダ名」が存在しない場合はメッセージ出力してなにもしない

関数



実行例

PS > Rename-File -FilePath "C:\新規テキスト ドキュメント.txt" -NewFileName "test.txt"
PS > Rename-Folder -FolderPath "C:\新しいフォルダ" -NewFolderName "sample"

メモ

フォルダ・ファイル存在チェック「Test-Path」

・ファイル存在チェック

PS > Test-Path -LiteralPath <<ファイル名(フルパス)>> -PathType Leaf

・フォルダ存在チェック

PS > Test-Path -LiteralPath <<フォルダ名(フルパス)>> -PathType Container

フォルダ・ファイル名の変更「Rename-Item」

PS > Rename-Item <<ファイル名・フォルダ名(フルパス)>> -newName <<新規ファイル・フォルダ名>>

PowerShellでログ出力

概要

PowerShellでログ出力ができるように関数を作成する

ログ出力するファイルパスと出力内容、ログレベル、文字コードを指定して実行
・ログレベルは「デバック(0)」「情報(1)」「警告(2)」「エラー(3)」のみ
・ログメッセージの形式は「ログ出力時刻 [ログレベル] : ログ内容」
・ログ出力時刻のフォーマットは「yyyy/MM/dd HH:mm:ss.fff」

関数


実行例

for ($i = 0; $i -lt 100; $i++) {
  Out-LogFile -LogFilePath "C:\app.log" -Value "デバックログを出力します。" -LogType 0
  Out-LogFile -LogFilePath "C:\app.log" -Value "情報ログを出力します。" -LogType 1
  Out-LogFile -LogFilePath "C:\app.log" -Value "警告ログを出力します。" -LogType 2
  Out-LogFile -LogFilePath "C:\app.log" -Value "エラーログを出力します。" -LogType 3
  Out-LogFile -LogFilePath "C:\app.log" -Value "ログの種類を指定しない場合、情報ログを出力します。"
}

「Out-File」と「Set-Content」の違い

別プロセスからの読み込み/書き込み

・「Out-File」の場合、ファイルを読み込むことは可能だが書き込むことはできない
・「Set-Content」の場合、ファイルを読み込むことも書き込むこともできない

2013年8月16日金曜日

Windowsでファイル名に使用できない禁止文字を全角に変換する

概要

mp3ファイルのタグ情報からファイル名にしようとするとき、ファイル名に使用できない禁止文字「\/:*?`"><|」が存在するため
全角「¥/:*?`”><|」に変換して対応する

関数


実行例

# 実行
PS > ConvertTo-UsedFileName -FileName "6/2*(1+2)=?.txt"

2013年8月14日水曜日

Excelをシート単位で検索する

概要

Excelで書かれた設計書から修正対象となる項目をいちいち開いて検索するのはめんどうなので、
指定したExcelファイルからシート単位で検索できるようにする
(行列まで調べるようにしたらやたら遅いのでやめた)


検索対象となるExcelファイルと検索する対象項目を指定して実行
・Excelファイルかどうかの判定は行わない
・検索対象が存在する場合は検索結果に「Excelファイル名(フルパス)」「ワークシート名」を返すようにする

関数


実行例

# 検索対象となるフォルダを指定
$FolderPath = "C:\Project\03.基本設計"
# 検索対象
$Target = "ユーザマスタ"

# 指定したフォルダからExcelファイル「xls」「xlsx 」を取得して検索する
Get-ChildItem $FolderPath -Recurse -Include *.xls,*.xlsx |
  ForEach-Object {
    # 検索
    Select-ExcelByWorkSheet -ExcelFilePath $_.FullName -Target $Target
  }

メモ

.Net Frameworkよりインスタンスを生成する

# インスタンス生成
PS > オブジェクト変数 = New-Object クラスの完全修飾名(引数)
# メソッドにアクセス
PS > オブジェクト変数.メソッド名(引数)

・.NET Framework からCOMオブジェクトを使用する

PS > オブジェクト変数 = New-Object -comobject クラスの完全修飾名(引数)

2013年8月11日日曜日

ExIf情報より画像ファイルを撮影日ごとにフォルダ分けする

概要

デジカメで撮った画像が1つのフォルダの中にたまってしまっているので
ExIf情報より撮影日ごとにフォルダ分けて整理する
・今回はmove(移動)ではなくてcopy(コピー)にする

コピー元(フォルダ)とコピー先(フォルダ)を指定して実行
・指定したコピー元が存在しない場合はコピーを行わない
・指定したコピー先が存在しない場合は作成してコピーを行う
・対象ファイルは「jpeg」「jpg」固定(大文字・小文字は気にしない)
・ExIf情報に撮影日時が存在しない場合は「unknown」フォルダに移動
・コピー先に対象ファイルが存在する場合はメッセージを出力してコピーしない

関数


実行例

# 実行
PS > Copy-ImagesByDateTimeOriginal -CopyFolderPath "C:DCIM" -DestFolderPath "C:DateTimeOriginal"

メモ

.Net Frameworkを呼び出す

[完全修飾名のクラス]::静的メソッド(引数)

画像ファイルのメタデータを取得

PS > [System.Drawing.Imaging.Metafile]::FromFile(<<画像ファイルのフルパス>>)
例)
PS >[System.Drawing.Imaging.Metafile]::FromFile("C:\DateTimeOriginal\Blue hills.jpg")

Tag                  : 
PhysicalDimension    : {Width=800, Height=600}
Size                 : {Width=800, Height=600}
Width                : 800
Height               : 600
HorizontalResolution : 300
VerticalResolution   : 300
Flags                : 77960
RawFormat            : [ImageFormat: b96b3cae-0728-11d3-9d7b-0000f81ef32e]
PixelFormat          : Format24bppRgb
Palette              : System.Drawing.Imaging.ColorPalette
FrameDimensionsList  : {7462dc86-6180-4c7e-8e3f-ee7333a7a483}
PropertyIdList       : {282, 283, 296, 20515...}
PropertyItems        : {282, 283, 296, 20515...} 

フォルダ配下の指定した拡張子のファイル情報を取得(Get-ChildItem)

・引数[-Include]を指定して対象となる拡張子のファイル情報を取得
※複数の拡張子を指定する場合はカンマ「,」を使用
※拡張子の大文字、小文字は気にする必要はなし

PS > Get-ChildItem -Path <<フォルダのフルパス>> -Recurse -Include *.<<拡張子>>, *.<<拡張子>>
■補足
例1)フォルダ・ファイル情報を取得
PS > Get-ChildItem -Path C:\sample

    ディレクトリ: C:\sample


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----        2013/07/09     13:59            sample
-a---        2013/07/09     13:57          0 sample1.txt
-a---        2013/07/09     13:58          0 sample2.txt
例2)そのまま引数「Include」で拡張子を指定したが取得できない
PS > Get-ChildItem -Path C:\sample -Include *.txt

# 表示されない
例3)「フォルダのフルパス」の後ろに「\*」を追加して取得可能
PS > Get-ChildItem -Path C:\sample\* -Include *.txt

    ディレクトリ: C:\sample


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        2013/07/09     13:57          0 sample1.txt
-a---        2013/07/09     13:58          0 sample2.txt

※サブフォルダ配下取得する場合(Recurseを指定)は特に気にしなくてよかった

パスと子パスを 1 つのパスに結合「Join-Path」

PS > Join-Path -Path <<パス>> -ChildPath <<子パス>>

2013年8月7日水曜日

フォルダ構成のみコピーする

概要

システム開発を行っている中で同一のフォルダ構成を作成する場合がある
・現行プロジェクトのフォルダ構成を新規プロジェクトにも適用
・ソースファイル/設定ファイル等の修正前後の差分をフォルダ構成含めて確認

コピー元(フォルダ)とコピー先(フォルダ)を指定して実行
・指定したコピー元が存在しない場合はコピーを行わない
・指定したコピー先が存在しない場合は作成してコピーを行う
・コピー元のフォルダがコピー先に存在する場合は上書き
・コピー先にコピー元に存在しないフォルダが存在する場合そのまま

関数


実行例

# 実行
PS > Copy-Folder -CopyFolderPath "C:\Project123" -DestFolderPath "C:\Project345"

メモ

新規にフォルダ・ファイルを作成「New-Item」

・引数[-Type directory]を指定して新規にフォルダを作成する

PS > New-Item <<フォルダのフルパス>> -Type directory

・引数[-Type file]を指定して新規にファイルを作成する
PS > New-Item <<ファイルのフルパス>> -Type file

・引数[-Force]を指定して強制上書きする
PS > New-Item <<ファイルのフルパス>> -Type file -Force

フォルダ配下のフォルダ・ファイル情報を取得「Get-ChildItem」

・フォルダ配下のみ取得する

PS > Get-ChildItem -Path <<フォルダのフルパス>>

・引数[-Recurse]を指定してサブフォルダ配下も再帰的に取得する
PS > Get-ChildItem -Path <<フォルダのフルパス>> -Recurse
例1) 「C:\sample」フォルダ配下のフォルダ・ファイル情報を取得
PS > Get-ChildItem -Path C:\sample

    ディレクトリ: C:\sample


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----        2013/07/09     13:59            sample
-a---        2013/07/09     13:57          0 sample1.txt
-a---        2013/07/09     13:58          0 sample2.txt
例2)「C:\sample」フォルダのサブフォルダ配下も含めてフォルダ・ファイル情報を取得
PS > Get-ChildItem -Path C:\sample -Recurse

    ディレクトリ: C:\sample


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----        2013/07/09     13:59            sample
-a---        2013/07/09     13:57          0 sample1.txt
-a---        2013/07/09     13:58          0 sample2.txt


    ディレクトリ: C:\sample\sample


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        2013/07/09     13:57          0 sample1_2.txt
-a---        2013/07/09     13:58          0 sample2_2.txt

Get-ChildItemで取得した「Mode(属性)」

Mode(属性) 内容
d フォルダ
a ファイル
r 読み取り専用
h 隠しファイル
s システムファイル

文字列すべてを小文字に変換「ToLower()」

・メソッド[ToLower()]を使用して小文字に変換

PS > <<文字列>>.ToLower()
例) 英大文字を英小文字に変換
PS > $value = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
PS > $value = $value.ToLower()
PS > $value

abcdefghijklmnopqrstuvwxyz

2013年8月1日木曜日

システム日付取得

自宅のWikiサーバーが壊れたため、今後ブログにて技術系のメモをとる
select sysdate from dual;