2013年8月29日木曜日

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

概要

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

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

関数


# ------------------------------------------------------------------
# デバッグログをファイルに出力する
# 関数名:Write-DebugLog
# 引数 :Value ログとして出力する文字列
# 戻り値:なし
# ------------------------------------------------------------------
function Write-DebugLog([String]$VALUE){
if($LogLevel-le 0){
Out-LogFile -LogFilePath $LogFilePath -Value $Value -LogType 0 -LogEncoding $LogEncoding
}
}
# ------------------------------------------------------------------
# 情報ログをファイルに出力する
# 関数名:Write-InfoLog
# 引数 :Value ログとして出力する文字列
# 戻り値:なし
# ------------------------------------------------------------------
function Write-InfoLog([String]$VALUE){
if($LogLevel -le 1){
Out-LogFile -LogFilePath $LogFilePath -Value $Value -LogType 1 -LogEncoding $LogEncoding
}
}
# ------------------------------------------------------------------
# 警告ログをファイルに出力する
# 関数名:Write-WarnLog
# 引数 :Value ログとして出力する文字列
# 戻り値:なし
# ------------------------------------------------------------------
function Write-WarnLog([String]$VALUE){
if($LogLevel -le 2){
Out-LogFile -LogFilePath $LogFilePath -Value $Value -LogType 2 -LogEncoding $LogEncoding
}
}
# ------------------------------------------------------------------
# エラーログをファイルに出力する
# 関数名:Write-ErrorLog
# 引数 :Value ログとして出力する文字列
# 戻り値:なし
# ------------------------------------------------------------------
function Write-ErrorLog([String]$VALUE){
if($LogLevel -le 3){
Out-LogFile -LogFilePath $LogFilePath -Value $Value -LogType 3 -LogEncoding $LogEncoding
}
}
view raw Write-Log.ps1 hosted with ❤ by GitHub

実行例

### 最初に設定を指定
# ログファイル出力先を指定
[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日火曜日

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

概要

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

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

関数


# ------------------------------------------------------------------
# ファイル名をリネームする
# 関数名:Rename-File
# 引数 :FilePath 名前を変更するファイルパス
# :NewFileName 新しいファイル名前
# 戻り値:なし
# ------------------------------------------------------------------
function Rename-File([String]$FilePath, [String]$NewFileName){
if(Test-Path -LiteralPath $FilePath -PathType Leaf){
Rename-Item $FilePath -newName $NewFileName
Write-Host "ファイル名を変更しました。置換前[ $FilePath ] 置換後[ $NewFileName ]"
}else{
Write-Host "ファイルが存在しません。ファイル名[ $FilePath ]"
}
}
view raw Rename-File.ps1 hosted with ❤ by GitHub

# ------------------------------------------------------------------
# フォルダ名をリネームする
# 関数名:Rename-Folder
# 引数 :FolderPath 名前を変更するフォルダパス
# :NewFolderName 新しいフォルダ名前
# 戻り値:なし
# ------------------------------------------------------------------
function Rename-Folder([String]$FolderPath, [String]$NewFolderName){
if(Test-Path -LiteralPath $FolderPath -PathType Container){
Rename-Item $FolderPath -newName $NewFolderName
Write-Host "フォルダー名を変更しました。置換前[ $FolderPath ] 置換後[ $NewFolderName ]"
}else{
Write-Host "フォルダーが存在しません。フォルダー名[ $FolderPath ]"
}
}

実行例

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」

関数


# ------------------------------------------------------------------
# ログをファイルに出力する
# 関数名:Out-LogFile
# 引数 :LogFilePath ログファイルパス
# :Value ログとして出力する文字列
# :LogType ログの種類(0:デバック,1:情報,2:警告,3:エラー)
# 指定がない場合は「情報」として出力
# :Encoding 文字コード
# 指定がない場合は「UTF8」として出力
# 戻り値:なし
# ------------------------------------------------------------------
function Out-LogFile([String]$LogFilePath,[String]$Value,[Int]$LogType=1,[String]$LogEncoding="utf8"){
# 日付のフォーマット
[String]$LogDateFormat = "yyyy/MM/dd HH:mm:ss.fff"
if($Value){
switch ($LogType){
0{ [String]$log = (Get-Date -Format $LogDateFormat) + " [DEBUG] : " + $Value }
1{ [String]$log = (Get-Date -Format $LogDateFormat) + " [INFO ] : " + $Value }
2{ [String]$log = (Get-Date -Format $LogDateFormat) + " [WARN ] : " + $Value }
3{ [String]$log = (Get-Date -Format $LogDateFormat) + " [ERROR] : " + $Value }
}
Write-Output $Log | Out-File -FilePath $LogFilePath -Encoding $LogEncoding -append
}
}
view raw Out-LogFile.ps1 hosted with ❤ by GitHub

実行例

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

関数


# ------------------------------------------------------------------
# Windowsでファイル名に使用できない禁止文字を全角に変換する
# 関数名:ConvertTo-UsedFileName
# 引数 :FileName ファイル名
# 戻り値:変換後のファイル名
# ------------------------------------------------------------------
function ConvertTo-UsedFileName([String]$FileName){
# 禁止文字(半角記号)
$CannotUsedFileName = "\/:*?`"><|"
# 禁止文字(全角記号)
$UsedFileName = "¥/:*?`”><|"
for ($i = 0; $i -lt $UsedFileName.Length; $i++) {
$FileName = $FileName.Replace($CannotUsedFileName[$i], $UsedFileName[$i])
}
return $FileName
}

実行例

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

2013年8月14日水曜日

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

概要

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


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

関数


# ------------------------------------------------------------------
# Excelファイルをシート単位で検索
# 関数名:Select-ExcelByWorkSheet
# 引数 :ExcelFilePath 検索対象のExcelファイル
# :Target 検索対象項目
# 戻り値:検索結果
# ------------------------------------------------------------------
function Select-ExcelByWorkSheet([String]$ExcelFilePath, [String]$Target){
# 検索結果
$result = @()
# Excel のインスタンスを作成
$excel = New-Object -comobject Excel.Application
# Excelファイルを開かない
$excel.Visible = $False
# 確認メッセージを非表示
$excel.DisplayAlerts = $False
# ワークブックを開く
$workBook = $excel.Workbooks.Open($excelFilePath)
# ワークシート分ループ
foreach($workSheet In $workBook.workSheets){
# 検索対象が存在するか確認
if($workSheet.UsedRange.Find($Target) -ne $Null){
# オブジェクト作成
$value = New-Object PSCustomObject -Property @{
# Excelファイル名(フルパス)
ExcelFilePath = $excelFilePath
# ワークシート名
WorkSheet = $workSheet.Name
}
$result += $value
}
}
$workBook.Close()
[void][System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($workBook)
$excel.Quit()
[void][System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($excel)
return $result
}

実行例

# 検索対象となるフォルダを指定
$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」フォルダに移動
・コピー先に対象ファイルが存在する場合はメッセージを出力してコピーしない

関数


# ------------------------------------------------------------------
# 画像ファイル(jpeg,jpg)を撮影日ごとにフォルダ分けする
# 関数名:Copy-ImagesByDateTimeOriginal
# 引数 :CopyFolderPath コピー元のフォルダパス
# :DestFolderPath コピー先のフォルダパス
# 戻り値:なし
# ------------------------------------------------------------------
function Copy-ImagesByDateTimeOriginal([String]$CopyFolderPath, [String]$DestFolderPath){
# EXIFタグ一覧より撮影日時のIDを指定
$DateTimeOriginalId = "36867"
# EXIFの撮影日時のフォーマット
$DateTimeFormat = "yyyy:MM:dd HH:mm:ss`0"
# コピー元の指定したフォルダのチェック
if(-not(Test-Path $CopyFolderPath)){
Write-Host "指定したコピー元フォルダが存在しません"
break
}
# コピー先の指定したフォルダが存在しない場合に作成
$destItem = New-Item $DestFolderPath -Type directory -Force
# 拡張子(jpeg、jpg)のファイルのみ
Get-ChildItem $CopyFolderPath -Recurse -Include *.jpeg ,*.jpg |
ForEach-Object {
# 画像ファイルを読み込み、撮影日時のオブジェクト取得
$image = [System.Drawing.Imaging.Metafile]::FromFile($_.FullName)
$propertyItem = $image.PropertyItems | Where-Object {$_.Id -eq $DateTimeOriginalId}
# 撮影日時が取得できない場合「unknown」フォルダを作成
if($propertyItem -ne $Null){
# EXIFの撮影日時のフォーマットが「YYYY:MM:DD HH:MM:SS」のため日付に変換
$value = $image.GetPropertyItem($DateTimeOriginalId).Value
$DateTimeOriginal = [System.Text.Encoding]::ASCII.GetString($value)
$date = [DateTime]::ParseExact($DateTimeOriginal,$DateTimeFormat,$Null).ToString("yyyyMMdd")
}else{
$date = "unknown"
}
# フォルダを作成
$createFolderPath = Join-Path -Path $DestFolderPath -ChildPath $date
$destFolderItem = New-Item $createFolderPath -Type directory -Force
# 作成したフォルダに画像ファイルをコピー
$destFilePath =  Join-Path -Path $createFolderPath -ChildPath $_.Name
if(Test-Path $destFilePath){
Write-Host "すでに存在します。コピー先 : [$destFilePath]"
return
}
$destFileItem = Copy-Item -Path $_.FullName -Destination $destFilePath
# 閉じる
$image.Dispose()
}
}

実行例

# 実行
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日水曜日

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

概要

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

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

関数


# ------------------------------------------------------------------
# コピー元のフォルダ構成をコピー先にコピーする
# 関数名:Copy-Folder
# 引数  :CopyFolderPath コピー元のフォルダフルパス
# DestFolderPath コピー先のフォルダフルパス
# 戻り値:なし
# ------------------------------------------------------------------
function Copy-Folder([String]$CopyFolderPath, [String]$DestFolderPath){
# コピー元の指定したフォルダのチェック
if(-not(Test-Path $CopyFolderPath)){
Write-Host "指定したコピー元フォルダが存在しません"
break
}
# コピー先の指定したフォルダが存在しない場合は作成
$destItem = New-Item $DestFolderPath -Type directory -Force
# コピー元配下のフォルダをコピー
Get-ChildItem $CopyFolderPath -Recurse | Where { $_.mode -match "d" } |
ForEach-Object {
# フォルダ名の大文字小文字を区別しないので小文字に統一して作成
$destFullName = $_.FullName.ToLower().Replace($CopyFolderPath.ToLower(), $DestFolderPath)
$destItem = New-Item $destFullName -Type directory -Force
}
}
view raw Copy-Folder.ps1 hosted with ❤ by GitHub

実行例

# 実行
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;