実行イメージ
出力ファイルイメージ
件名 :XXXXXXXXXXXXXXXXXXXXXXX
送信者 :XXXXXX XXXXXX
宛先 :XXXXXXX XXXXXXXX
CC :
送信日時:XXXX/XX/XX(XX) XX:XX:XX
添付 :XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
添付 :XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
----------------------------------------
XXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXX
起動用BAT
@ECHO OFF
ECHO しばらくお待ちください...
PowerShell.exe -NoLogo -NoProfile -ExecutionPolicy RemoteSigned .\ExportOutlookMsg.ps1
ECHO.
PAUSE
スクリプト本体
InboxFolderPath
に「受信トレイ」の出力先フォルダを、SentItemFolderPath
に「送信済みアイテム」の出力先フォルダを指定しておく。
ExportOutlookMsg.ps1
# requires -version 3.0
Set-StrictMode -Version Latest
<#
【Outlookメールをテキスト形式でエクスポート】
「受信トレイ」または「送信済みアイテム」のメールを
所定の場所にテキスト形式で出力する。
添付ファイルはテキストのヘッダ部にファイル名のみ出力する。
※スクリプト実行前にOutlookを起動しておくこと。
# >
# region 変数・定数定義
# ■「受信トレイ」メール用出力フォルダ
Set-Variable -Name InboxFolderPath -Value '.\受信トレイExport' -Option ReadOnly -Force
# ■「送信済みアイテム」メール用出力フォルダ
Set-Variable -Name SentItemFolderPath -Value '.\送信済みアイテムExport' -Option ReadOnly -Force
# エラーログ出力先
Set-Variable -Name ErrLogPath -Value '.' -Option ReadOnly -Force
# エラーログファイル名プレフィックス
Set-Variable -Name ErrLogFileNamePrefix -Value 'ExportOutlookMsg_Err' -Option ReadOnly -Force
# 出力ファイル名部分の最大文字数
Set-Variable -Name MaxFileNameLength -Value 60 -Option ReadOnly -Force
# 処理終了番号
Set-Variable -Name InputNo_Exit -Value '0' -Option ReadOnly -Force
# 対象フォルダ(受信トレイ)
Set-Variable -Name FolderKind_Inbox -Value '1' -Option ReadOnly -Force
# 対象フォルダ(送信済みアイテム)
Set-Variable -Name FolderKind_SentMail -Value '2' -Option ReadOnly -Force
# 抽出対象期間(直近1週間)
Set-Variable -Name PeriodKind_1Week -Value '1' -Option ReadOnly -Force
# 抽出対象期間(直近2週間)
Set-Variable -Name PeriodKind_2Week -Value '2' -Option ReadOnly -Force
# 抽出対象期間(直近1ヶ月)
Set-Variable -Name PeriodKind_1Month -Value '3' -Option ReadOnly -Force
# 抽出対象期間(直近2ヶ月)
Set-Variable -Name PeriodKind_2Month -Value '4' -Option ReadOnly -Force
# 抽出対象期間(開始日を直接指定)
Set-Variable -Name PeriodKind_UserInput -Value '5' -Option ReadOnly -Force
# 抽出対象期間(全件)
Set-Variable -Name PeriodKind_All -Value '9' -Option ReadOnly -Force
# 受信トレイを表す定数
Set-Variable -Name olFolderInbox -Value 6 -Option Constant
# 送信済みアイテムを表す定数
Set-Variable -Name olFolderSentMail -Value 5 -Option Constant
# Outlookのプロセス名(起動チェック用)
Set-Variable -Name OutlookProcesName -Value 'OUTLOOK' -Option Constant
# ウィンドウタイトル
Set-Variable -Name WindowTitle -Value 'Outlookメール エクスポート' -Option Constant
# 選択メニュー1
[string]$FolderSelectMenuText =
@'
Outlookメールをテキスト形式でファイル出力します。
処理対象の数字を入力してEnterキーを押下してください。
[対象メールフォルダ]
1 ... 受信トレイ
2 ... 送信済みアイテム
0 ... 終了
'@
# 選択メニュー2
[string]$PeriodSelectMenuText =
@'
[抽出対象期間]
1 ... 直近1週間(今日は除く)
2 ... 直近2週間(今日は除く)
3 ... 直近1ヶ月(今日は除く)
4 ... 直近2ヶ月(今日は除く)
5 ... 指定日から(今日は除く)
9 ... 全て
0 ... 終了
'@
# endregion
[datetime]$NowDate = Get-Date
# エラーログファイル名
[string]$ErrLogFilePath = "{0}_{1}.log" -f (Join-Path $ErrLogPath $ErrLogFileNamePrefix), $NowDate.ToString("yyyyMMdd-HHmmss")
# region 関数定義
<#
.SYNOPSIS
エラーメッセージ表示
.PARAMETER msg
コンソールに表示するメッセージ
# >
function ErrMsg([string]$msg) {
Write-Host -Object $msg -ForegroundColor Red
}
<#
.SYNOPSIS
プロパティ値チェック
.DESCRIPTION
プロパティが存在し、値がNULL以外のときTrueを返す
.PARAMETER item
オブジェクト
.PARAMETER prop
プロパティ名
# >
function HasPropertyValue([object]$item, [string]$prop) {
if([bool]($item.PsObject.Properties.Name -match ('^' + $prop + '$'))) {
# プロパティあり
if (($item.$prop) -eq $null) {
# 値がNULL
return $false
}
else {
return $true
}
}
else {
# プロパティなし
return $false
}
}
<#
.SYNOPSIS
Outlookメールを1件テキストファイル出力
.PARAMETER item
MailItemオブジェクト
.PARAMETER outPath
出力フォルダパス
.PARAMETER folderIndex
Outlookの既定フォルダを表すインデックス
# >
function ExportOutlookMailData([object]$item, [string]$outPath, [int]$folderIndex) {
# 出力ファイル名組み立て
[string]$dtStr = ""
if ($folderIndex -eq $olFolderInbox) {
# 受信トレイ
if (HasPropertyValue $item "ReceivedTime") {
# 受信日時
$dtStr = $item.ReceivedTime.ToString('yyyyMMdd(ddd)-HHmmss')
}
else {
# 日付を取得できなかったものは件名をエラーログに出力
$item.Subject | Out-File $ErrLogFilePath -Encoding UTF8 -Append
return ""
}
}
elseif ($folderIndex -eq $olFolderSentMail) {
# 送信済みアイテム
if (HasPropertyValue $item "SentOn") {
# 送信日時
$dtStr = $item.SentOn.ToString('yyyyMMdd(ddd)-HHmmss')
}
elseif (HasPropertyValue $item "ReceivedTime") {
# 送信日時が取得できない場合、受信日時を使う
$dtStr = $item.ReceivedTime.ToString('yyyyMMdd(ddd)-HHmmss')
}
else {
# 日付を取得できなかったものは件名をエラーログに出力
$item.Subject | Out-File $ErrLogFilePath -Encoding UTF8 -Append
return ""
}
}
else {
# フォルダインデックス不正
ErrMsg ("ExportOutlookMailData(), folderIndexが不正です。[" + $item.Subject + "][" + $folderIndex + "]")
return ""
}
# 件名をファイル名に使う。ファイル名として使えない文字や使いたくない文字は全角に置換
[string]$subjectStr = $item.Subject.Replace('/', '/').Replace('\', '¥'). `
Replace('<', '<').Replace('>', '>').Replace('*', '*').Replace('?', '?'). `
Replace('|', '|').Replace(':', ':').Replace(';', ';').Replace('[', '['). `
Replace(']', ']').Replace('"', '”')
# 出力ファイル名決定(受信日/送信日_件名)
[string]$fname = "${dtStr}_${subjectStr}"
[int]$len = $fname.Length
if ($MaxFileNameLength -lt $len) {
# 長すぎる件名は途中で切る
$fname = $fname.Substring(0, $MaxFileNameLength)
}
# 出力ファイルパス
[string]$filePath = "${outPath}\${fname}.txt"
try {
"件名 :" + $item.Subject |
Out-File $filePath -Encoding UTF8 -ErrorAction Stop
"送信者 :" + $item.SenderName |
Out-File $filePath -Encoding UTF8 -Append -ErrorAction Stop
if (HasPropertyValue $item "To") {
"宛先 :" + $item.To |
Out-File $filePath -Encoding UTF8 -Append -ErrorAction Stop
}
if (HasPropertyValue $item "CC") {
"CC :" + $item.CC |
Out-File $filePath -Encoding UTF8 -Append -ErrorAction Stop
}
if ($folderIndex -eq $olFolderInbox) {
# 受信トレイ
"受信日時:" + $item.ReceivedTime.ToString('yyyy/MM/dd(ddd) HH:mm:ss') |
Out-File $filePath -Encoding UTF8 -Append -ErrorAction Stop
}
elseif ($folderIndex -eq $olFolderSentMail) {
# 送信済みアイテム
"送信日時:" + $item.SentOn.ToString('yyyy/MM/dd(ddd) HH:mm:ss') |
Out-File $filePath -Encoding UTF8 -Append -ErrorAction Stop
}
# 添付ファイル
$item.Attachments | ForEach-Object {
"添付 :" + $_.FileName |
Out-File $filePath -Encoding UTF8 -Append -ErrorAction Stop
}
# 本文との区切り線
"----------------------------------------" |
Out-File $filePath -Encoding UTF8 -Append -ErrorAction Stop
# 本文
$item.Body |
Out-File $filePath -Encoding UTF8 -Append -ErrorAction Stop
}
catch {
ErrMsg "${filePath} の出力でエラーが発生しました。"
ErrMsg $Error[0]
}
return $filePath
}
# endregion
# =======================================================================
# ウィンドウタイトル設定
$ui = (Get-Host).UI.RawUI
$ui.WindowTitle = $WindowTitle
[string]$inputFolderKind = ""
# 対象のメールフォルダを選択
while ($true) {
# コンソール画面クリア
Clear-Host
# メニュー表示(対象のメールフォルダ)
Write-Host $FolderSelectMenuText -ForegroundColor Cyan
# キー入力
$inputFolderKind = Read-Host '番号を入力'
if ($inputFolderKind -eq $InputNo_Exit) {
# 終了
return
}
elseif ($inputFolderKind -ne $FolderKind_Inbox -and
$inputFolderKind -ne $FolderKind_SentMail) {
ErrMsg '処理対象番号が不正です。'
continue
}
else {
# ループを抜けて次のメニュー表示へ
break
}
}
[string]$inputPeriod = ""
# 抽出期間を選択
while ($true) {
# メニュー表示(対象の期間)
Write-Host $PeriodSelectMenuText -ForegroundColor Cyan
# キー入力
$inputPeriod = Read-Host '番号を入力'
if ($inputPeriod -eq $InputNo_Exit) {
# 終了
return
}
elseif ($inputPeriod -ne $PeriodKind_All -and
$inputPeriod -ne $PeriodKind_1Week -and
$inputPeriod -ne $PeriodKind_2Week -and
$inputPeriod -ne $PeriodKind_1Month -and
$inputPeriod -ne $PeriodKind_2Month -and
$inputPeriod -ne $PeriodKind_UserInput) {
# 再度入力
ErrMsg '処理対象番号が不正です。'
continue
}
else {
# 入力受け付け、次の処理へ
break
}
}
# Outlook起動チェック
$p = Get-Process -Name "${OutlookProcesName}*"
[bool]$hit = $false
$p | ForEach-Object {
if ($_.Name -ieq $OutlookProcesName) {
$hit = $true
}
}
if ($hit -eq $false) {
ErrMsg 'Outlookを起動しておいてください。'
return
}
[string]$targetName = ""
[string]$outFolderPath = ""
[int]$folderIndex = -1
if ($inputFolderKind -eq $FolderKind_Inbox) {
# 受信トレイの処理
$targetName = "受信トレイ"
$outFolderPath = $InboxFolderPath
$folderIndex = $olFolderInbox
}
elseif ($inputFolderKind -eq $FolderKind_SentMail) {
# 送信済みアイテムの処理
$targetName = "送信済みアイテム"
$outFolderPath = $SentItemFolderPath
$folderIndex = $olFolderSentMail
}
else {
Write-Error 'エラーです。'
return
}
[string]$extractionPeriod = ""
[datetime]$fromDate = [DateTime]::MinValue
# 抽出終了日(昨日)
[datetime]$toDate = $NowDate.AddDays(-1)
# 抽出開始日
if ($inputPeriod -eq $PeriodKind_All) {
# 全件対象
}
elseif ($inputPeriod -eq $PeriodKind_1Week) {
# 1週間前
$fromDate = $NowDate.AddDays(-7)
}
elseif ($inputPeriod -eq $PeriodKind_2Week) {
# 2週間前
$fromDate = $NowDate.AddDays(-14)
}
elseif ($inputPeriod -eq $PeriodKind_1Month) {
# 1ヶ月前
$fromDate = $NowDate.AddMonths(-1)
}
elseif ($inputPeriod -eq $PeriodKind_2Month) {
# 2ヶ月前
$fromDate = $NowDate.AddMonths(-2)
}
elseif ($inputPeriod -eq $PeriodKind_UserInput) {
# 直接指定
$inputDate = Read-Host "yyyymmdd形式で入力してください"
if ([datetime]::TryParseExact(
$inputDate,
'yyyyMMdd',
[Globalization.DateTimeFormatInfo]::CurrentInfo,
[Globalization.DateTimeStyles]::None,
[ref]$fromDate) -eq $false) {
Write-Host "処理を中断します。"
return
}
}
else {
Write-Error 'エラーです。'
return
}
[string]$receivedTimeFilter = ""
if ($inputPeriod -eq $PeriodKind_All) {
$extractionPeriod = "全て"
}
else {
# 表示用の抽出対象期間
$extractionPeriod =
"{0} ~ {1}" -f $fromDate.ToString("yyyy/MM/dd(ddd)"), $toDate.ToString("yyyy/MM/dd(ddd)")
# Outlookフィルタ条件
$receivedTimeFilter =
'[ReceivedTime] >= "{0}" AND [ReceivedTime] <= "{1}"' -f $fromDate.ToString("yyyy/MM/dd"), $toDate.ToString("yyyy/MM/dd")
}
Write-Host "${extractionPeriod}の「${targetName}」のメールを`n「${outFolderPath}」にテキスト保存します。" -ForegroundColor Cyan
# フォルダ存在チェック
if ((Test-Path $outFolderPath) -eq $false) {
# 無ければ作成
mkdir $outFolderPath -ErrorAction Stop > $null
}
$mapi = (New-Object -ComObject Outlook.Application).GetNamespace('MAPI')
# Outlookから対象のメールフォルダを取得
$outlookFolder = $mapi.GetDefaultFolder($folderIndex)
# 抽出期間を反映
$targetCollection = $outlookFolder.Items
if ($inputPeriod -ne $PeriodKind_All) {
$targetCollection = $outlookFolder.Items.Restrict($receivedTimeFilter)
}
# 件数確認
if ($targetCollection.Count -eq 0) {
Write-Host "データはありません。"
return
}
Write-Host ("対象データ " + $targetCollection.Count + " 件") -ForegroundColor Yellow
# 処理を続行するか確認
while ($true) {
[string]$yesNo = Read-Host "処理を開始しますか?(y/n)"
if ($yesNo -ieq 'y') {
# 処理続行
Write-Host "処理中..."
break
}
elseif ($yesNo -ieq 'n') {
# 中断
Write-Host "処理を中断しました。"
return
}
}
# ウィンドウタイトル設定
$ui.WindowTitle = '処理中 - ' + $WindowTitle
[int]$errCnt = 0
# 指定した条件でファイル出力
foreach ($item in $targetCollection) {
# 1件、ファイル出力
[string]$ret = ExportOutlookMailData $item $outFolderPath $folderIndex
if ($ret -eq "") {
# 処理失敗
Write-Host 'x' -NoNewline
$errCnt++
}
else {
# 一件処理した
Write-Host '.' -NoNewline
}
}
# ウィンドウタイトル設定
$ui.WindowTitle = $WindowTitle
Write-Host "`n「${targetName}」のメールエクスポート処理が完了しました。"
Write-Host ("出力先⇒" + $outFolderPath)
if ($errCnt -ne 0) {
Write-Host "${errCnt}件の出力に失敗しました。"
Write-Host "${ErrLogFilePath}を参照してください。"
}