【Accessをメール検索GUIとして使う】PowerShellでOutlookのメールアイテム一覧をcsvで吐いてAccessに食わせる

https://qiita.com/taleau/items/6dd52229719cb1a7efc8

またまた前回からの続きです。

ExcelのPowerQueryではなくAccessに食わせるようにしました。

Accessの方が楽なので今後はAccessで作り込んでいこうと思います。

## PowerShell
### 前回からの変更点
####  csv1行目の`"TYPE System.Management.Automation.PSCustomObject"`を消すようにした
Accessにインポートする際に、1行目の非テーブル行が邪魔なので

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/2df6a0a1-98f6-a80c-8b44-639f8cf33d52.png)


1. 最初の書き出しをテンポラリーファイルにして
1. パイプ処理で1行目をスキップして別名保存
1. テンポラリーファイルを削除

という工程を追加しました。

PowerQueryに食わせる場合でもこの処理をやっておくとクエリの編集で1行目を削除したりフィールド名設定が不要になります。

####  `EntryID`プロパティを追加
Outlookでメールアイテムを開くのに必要なので列を追加


### コード:PowerShell

``` powershell
# Outlookのフォルダからメール一覧を作成、CSVに吐き出す

# 参考（Outlook取得）：https://www.itlab51.com/?p=6171
# 参考（CSV出力）：https://use-computer.net/powershell/powershell-course-5
# 参考（列挙型）：https://docs.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_enum?view=powershell-7.2


$oOutlook = New-Object -ComObject Outlook.Application
$oNamespace = $oOutlook.GetNamespace("MAPI")


# フォルダIndexの配列を作成
$arr_oFolders = @(5,6)
#$olFolderInbox = 6 #受信トレイ
#$olFolderSentMail = 5 #送信済みトレイ

# ループ回数の上限を設定（CSVに書き出すメール数）
$LimLoopCnt=10000

# 取得する文字数に制限をかける
$LimLenStr=10000                

# 変数の初期化
$CsvData = @()
$rr=0
 
# $ary_namesの要素を 1 つずつ $oFolder に格納してループする
for($fld = 0; $fld -lt $arr_oFolders.Count; $fld++){
    $oFolder = $oNamespace.GetDefaultFolder($arr_oFolders[$fld])

    # $oFolder内の全アイテムを巡回して1レコードずつCSV出力用の変数に格納していく
    foreach($oItem in $oFolder.Items){
            # 取得する文字数に制限をかける（文字数が多すぎるとセルをはみ出してテーブル構造が崩れるため）
            $Str = $oItem.Body
            $LenStr = ($oItem.Body).Length
            if ( $LenStr -gt $LimLenStr)
                {$Str = $Str.Substring(0,$LimLenStr)}
            
            # 添付ファイルリストを取得
            $attList=""
            foreach($att in $oItem.Attachments){
                $attList += ";" + $att.FileName
            }
            
            # 1レコードずつCSV用の変数につぎ足していく
            $CsvData += [PSCustomObject]@{
                No = $rr+1 # 0始まりのため出力は1始まりにする
                件名 = $oItem.Subject
                本文 = $Str.Replace("`r`n","") #改行殺し
                受信日時 = $oItem.ReceivedTime
                受信者名  =$oItem.To #ReceivedByNameだと自分以外が空白になる
                送信者名  =$oItem.SenderName
                CC = $oItem.CC
                ConversationID = $oItem.ConversationID
                添付ファイル = $attList

            }

            # ループ脱出
            $rr = $rr + 1
            if( $rr -gt $LimLoopCnt){break}
        }

} 

# CSVに吐き出す
$CsvData | ft -AutoSize

$path = "C:\Users\●●●\●●●\"
$tmp = "temp.csv"
$csvName1 = "ol_受信BOX_Items.csv"

#テンポラリーファイル（csv）に書き出す
$CsvData | Export-Csv -Path $path$tmp -Encoding Default

#1行目を消して別名保存する（ これ→ "TYPE System.Management.Automation.PSCustomObject"）
Get-content $path$tmp | Select-Object -Skip 1 | Set-Content $path$csvName

#テンポラリーファイルを削除する
Remove-Item $path$tmp 
```



## Access
### csvを取り込む
PowerShellで吐き出したcsvファイルを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/7a236acc-9e51-9fb1-c9eb-c76afb19c090.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/756205c2-2534-217e-19ed-d88a10e8edbe.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/6a4ae213-8cb4-0ca8-2632-641abc724d73.png)

取り込みできました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/63c3b825-0024-5b5a-5ee5-4e22a48a1362.png)

### フォームの作成
最終的には
- 検索ボックス
- メール一覧
- メール詳細

を同時に並べたいところですが、まずは

- 最低限のフォームを作成
- 表示中のメールアイテムをOutlookで開く

だけを作ります。

リボンからフォームを作成します。
このボタン１つでフィールドに合わせたフォームが自動生成されます。
（ExcelやOutlookでユーザーフォーム作ろうと思ったらここがもう面倒）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/d03a7240-4b50-4876-8fe3-fe69593611ed.png)


作成したフォームをデザインビューで開いてボタンを追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/9c817404-a54d-c3d5-5e01-f49eea78b15c.png)

ボタンに適宜名前をつけて、プロパティシートからクリック時イベントを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/93baeb32-acbd-e7cb-37a7-3a4e6ee47803.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/94e04720-6db8-04fb-86d3-fd87148b91fc.png)

以下コードを貼り付けます。

### コード：Access

`GetNamespace("MAPI").GetItemFromID(EntryID)`で指定したメールアイテムを表示(`Display`)するだけの超簡単なコードです。

``` vb
Option Compare Database
Option Explicit

Private Sub btnアイテムをolで開く_Click()
  Call EntryIDからメールを開く(EntryID.Value)
End Sub

Sub EntryIDからメールを開く(EntryID As String)
  'appOLを呼び出す
  Dim appOL As Outlook.Application
  Set appOL = New Outlook.Application

  Dim objMailItem As MailItem 'GetItemFromIDメソッドでEntryIDからメールアイテムを抽出する
  Set objMailItem = appOL.GetNamespace("MAPI").GetItemFromID(EntryID)
  
  objMailItem.Display
    
  'オブジェクトをNothingしておく
  Set appOL = Nothing
  Set objMailItem = Nothing
    
End Sub

```

以上です。


## 残課題

### Accessを開いたままPowerShellからcsvを更新したい
csvインポート時に「リンク」を選ぶと、PowerShellでcsvを更新したものがAccess側で自動でテーブルが更新されます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/cb3cae3f-24a9-84f5-442a-d4a85164dd58.png)


が、Accessを開いたままでPowerShellを実行すると
``` powershell
Set-Content : 別のプロセスで使用されているため、プロセスはファイル 'C:\Users\●●●\●●●\ol_受信BOX_Items.csv' にアクセスできません。
```
とエラーが出ます。

リンクせずに取り込んでおいて、csvを読み直すのは別処理をすればいけるのかな？

### メールアイテムの検索クエリを追加していく
クエリでテーブル抽出ができることは既知なので、メールアイテムをOutlookで開くことができるかの確認と、PowerShellの出力にEntryIDが必要と知ることが先だと思い、スモールステップで作りました。

次回は選択クエリの復習も兼ねてここやっていこうかな。