LoginSignup
13
8

More than 3 years have passed since last update.

PowerShellメモ Outlookメールをテキスト出力

Posted at

実行イメージ

ExportOutlook.png

出力ファイルイメージ

件名  :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}を参照してください。"
}
13
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
8