【PowerShell】Notes DB ファイルから、設計書 (Markdown形式) を自動作成する

# 概要

Notes DB ファイル(.nsf) からビュー、フォーム、エージェント等の情報記載した設計書を自動作成するサンプルコードです。

# 前提

LotusScript は 32bit版 PowerShell でしか動作しません。

https://qiita.com/yoshi_iwa/items/13a74e534bc5f2b6aaae

# ソース

## XML ファイルに変換する

※こちらは 32bit版 でしか使えません。

```powershell:Convert-NotesToXml.ps1
using namespace System.IO;

Param (
    # Notes DB ファイルパス
    [Parameter(Mandatory, ValueFromPipeline, Position=0)]
    [FileInfo] $Path,

    # データを含むどうか
    [switch] $ContainsData
) Begin {
    # Notes を設定するセッション接続
    $Notes = New-Object -ComObject Lotus.NotesSession
    $Notes.Initialize('')
} Process {
    $db = $Notes.GetDatabase('', $Path, $false) 

    $nc = $db.CreateNoteCollection($true)
    $nc.SelectAllDataNotes($ContainsData)
    # ログを対象外に
    $nc.SelectMiscCodeElements = $false
    # ビルド
    $nc.BuildCollection()

    # 出力XML
    [FileInfo] $xmlPath = Join-Path $Path.DirectoryName ("{0}.xml" -f $db.Title)

    $exporter = $Notes.CreateDXLExporter()
    $exporter.Export($nc) | Out-File $xmlPath -Encoding utf8

    $xmlPath
} End {
}
```

## XML ファイルから設計書 (Markdown形式) を作成する

※こちらは 64bit 版でもつかえます。

### Markdown 形式の表変換

```powershell:ConvertTo-Markdown.ps1
<#
.Synopsis
   Markdown 形式変換
.DESCRIPTION
   Markdown 形式の表に変換します。
#>
function ConvertTo-Markdown {
    [Alias('cnvmd')]
    Param (
        # 項目
        [Parameter(Mandatory, Position=0)]
        $Item,

        # 番号列を使用するかどうか
        [switch] $Numbering
    ) Begin {
        # 列情報取得
        $Header = $Item | select -First 1 | Get-member -MemberType NoteProperty | select -ExpandProperty Name
        $Cols = $Header -join ' | '
        $ColCount = ($Header | measure).Count

        if ($Numbering) {
            echo ('| No. | {0} |' -f $Cols)
            echo ('| :-: |' + (' ---- |' * $ColCount))
        } else {
            echo ('| {0} |' -f $Cols)
            echo ('|' + (' ---- |' * $ColCount))
        }

        $num = 1
    } Process {
        $Item | % {
            $row = $_
            $cells = ($Header | % {
                $cell = $row."$_" -replace "`r?`n", '<br />'
                $cell.Replace('|', '│')
            }) -join ' | '
            if ($Numbering) {
                echo "| $num | $cells |"
            } else {
                echo "| $cells |"
            }

            $num++
        }
    } End {
    }
}
```

### Markdown 形式文書変換処理

```powershell:Make-Document.ps1
using namespace System.IO;

Param (
    # XML ファイルパス
    [Parameter(Mandatory, ValueFromPipeline, Position=0)]
    [FileInfo] $Path
) Begin {
    pushd $PSScriptRoot
    . .\ConvertTo-Markdown.ps1
} Process {
    [FileInfo] $md = [Path]::ChangeExtension($Path, '.md')

    [XML] $xml = Get-Content $Path
    $db = $xml.database

    echo ("# {0}" -f $Path.BaseName) > $md

    echo '' >> $md
    echo '## 情報' >> $md

    $info = [PSCustomObject]@{
        Version = $db.version
        MaintenanceVersion = $db.maintenanceversion
        ReplicaID = $db.replicaid
        Path = [FileInfo] $db.path
        Title = $db.title
        IncreaseMaxFields = $db.increasemaxfields -eq $true
        ShowInOpenDialog = $db.showinopendialog -eq $true
        MarkModifiedUnread = $db.markmodifiedunread -eq $true
        Uselz1 = $db.uselz1 -eq $true
        FileName = $Path.Name
    }
    $infos = @(
        [PSCustomObject]@{ Name = 'Version'; Value = $info.Version }
        [PSCustomObject]@{ Name = 'MaintenanceVersion'; Value = $info.MaintenanceVersion }
        [PSCustomObject]@{ Name = 'ReplicaID'; Value = $info.ReplicaID }
        [PSCustomObject]@{ Name = 'Path'; Value = $info.Path }
        [PSCustomObject]@{ Name = 'Title'; Value = $info.Title }
        [PSCustomObject]@{ Name = 'IncreaseMaxFields'; Value = $info.IncreaseMaxFields }
        [PSCustomObject]@{ Name = 'ShowInOpenDialog'; Value = $info.ShowInOpenDialog }
        [PSCustomObject]@{ Name = 'MarkModifiedUnread'; Value = $info.MarkModifiedUnread }
        [PSCustomObject]@{ Name = 'Uselz1'; Value = $info.Uselz1 }
        [PSCustomObject]@{ Name = 'FileName'; Value = $info.FileName }
    )

    echo '' >> $md
    cnvmd $infos -Numbering >> $md

    echo '' >> $md
    echo '## 項目数一覧' >> $md

    $objs = @(
        [PSCustomObject]@{ 名前 = '[ビュー](#1.-ビュー)'; 数 = ($db.view | measure).Count }
        [PSCustomObject]@{ 名前 = '[フォーム](#2.-フォーム)'; 数 = ($db.form | measure).Count }
        [PSCustomObject]@{ 名前 = '[エージェント](#3.-エージェント)'; 数 = ($db.agent | measure).Count }
        [PSCustomObject]@{ 名前 = '[スクリプト](#4.-スクリプト)'; 数 = ($db.scriptlibrary | measure).Count }
    )

    echo '' >> $md
    cnvmd $objs -Numbering >> $md

    echo '' >> $md
    echo '# 詳細' >> $md

    echo '' >> $md
    echo '## 1. ビュー' >> $md

    $sub = 1
    $Views = $db.view | % {
        [PSCustomObject]@{
            Num = $sub
            Name = $_.name
            Alias = $_.alias
            Columns = $_.column
        }

        $sub++
    }

    echo '' >> $md
    cnvmd ($Views | select @{name='Name'; expression={('[{0}](#1-{1}. {0})' -f $_.Name, $_.Num)}}, Alias) -Numbering >> $md

    $Views | % {
        $view = $_

        echo '' >> $md
        echo ("### 1-{0}. {1}" -f $view.Num, $_.Name) >> $md

        $columns = $view.Columns | % {
            [PSCustomObject]@{
                Disp = $_.columnheader.title
                Name = $_.itemname
                Summary = $_.code.formula
            }
        }

        echo '' >> $md
        cnvmd $columns -Numbering >> $md
    }

    echo '' >> $md
    echo '## 2. フォーム' >> $md

    $sub = 1
    $Forms = $db.form | % {
        [PSCustomObject]@{
            Num = $sub
            Name = $_.name
            Alias = $_.alias
            Codes = $_.code
        }

        $sub++
    }

    echo '' >> $md
    cnvmd ($Forms | select @{name='Name'; expression={('[{0}](#2-{1}. {0})' -f $_.Name, $_.Num)}}, Alias) -Numbering >> $md

    $Forms | % {
        $form = $_

        echo '' >> $md
        echo ("### 2-{0}. {1}" -f $form.Num, $_.Name) >> $md

        echo '' >> $md
        echo ("#### 2-{0}-1. コード" -f $form.Num) >> $md

        $codes = $form.Codes | % {
            [PSCustomObject]@{
                Name = $_.event
                Summary = $_.formula
                Script = $_.lotusscript
            }
        }

        $codes | % {
            $code = $_

            echo '' >> $md
            echo ('##### {0}' -f $code.Name) >> $md

            if (![string]::IsNullOrEmpty($code.Summary)) {
                echo '' >> $md
                echo ('> {0}' -f $code.Summary) >> $md
            }

            if (![string]::IsNullOrEmpty($code.Script)) {
                echo '' >> $md
                echo '```vb' >> $md
                echo $code.Script >> $md
                echo '```' >> $md
            }
        }
    }

    echo '' >> $md
    echo '## 3. エージェント' >> $md

    $sub = 1
    $Agents = $db.agent | % {
        [PSCustomObject]@{
            Num = $sub
            Name = $_.name
            Alias = $_.alias
            Codes = $_.code
        }

        $sub++
    }

    echo '' >> $md
    cnvmd ($Agents | select @{name='Name'; expression={('[{0}](#3-{1}. {0})' -f $_.Name, $_.Num)}}, Alias) -Numbering >> $md

    $Agents | % {
        $agent = $_

        echo '' >> $md
        echo ("### 3-{0}. {1}" -f $agent.Num, $_.Name) >> $md

        echo '' >> $md
        echo ("#### 3-{0}-1. コード" -f $agent.Num) >> $md

        $codes = $agent.Codes | % {
            [PSCustomObject]@{
                Name = $_.event
                Summary = $_.formula
                Script = $_.lotusscript
            }
        }

        $codes | % {
            $code = $_

            echo '' >> $md
            echo ('##### {0}' -f $code.Name) >> $md

            if (![string]::IsNullOrEmpty($code.Summary)) {
                echo '' >> $md
                echo ('> {0}' -f $code.Summary) >> $md
            }

            if (![string]::IsNullOrEmpty($code.Script)) {
                echo '' >> $md
                echo '```vb' >> $md
                echo $code.Script >> $md
                echo '```' >> $md
            }
        }
    }

    echo '' >> $md
    echo '## 4. スクリプト' >> $md

    $sub = 1
    $Scripts = $db.scriptlibrary | % {
        [PSCustomObject]@{
            Num = $sub
            Name = $_.name
            Alias = $_.alias
            Codes = $_.code
        }

        $sub++
    }

    echo '' >> $md
    cnvmd ($Scripts | select @{name='Name'; expression={('[{0}](#4-{1}. {0})' -f $_.Name, $_.Num)}}, Alias) -Numbering >> $md

    $Scripts | % {
        $script = $_

        echo '' >> $md
        echo ("### 4-{0}. {1}" -f $script.Num, $_.Name) >> $md

        echo '' >> $md
        echo ("#### 4-{0}-1. コード" -f $script.Num) >> $md

        $codes = $script.Codes | % {
            [PSCustomObject]@{
                Name = $_.event
                Summary = $_.formula
                Script = $_.lotusscript
            }
        }

        $codes | % {
            $code = $_

            echo '' >> $md
            echo ('##### {0}' -f $code.Name) >> $md

            if (![string]::IsNullOrEmpty($code.Summary)) {
                echo '' >> $md
                echo ('> {0}' -f $code.Summary) >> $md
            }

            if (![string]::IsNullOrEmpty($code.Script)) {
                echo '' >> $md
                echo '```vb' >> $md
                echo $code.Script >> $md
                echo '```' >> $md
            }
        }
    }
} End {
    popd
}
```

## 使用方法

```powershell
dir C:\NotesDb -File -Recurse -Include *.nsf | .\Convert-NotesToXml.ps1 | .\Make-Document.ps1

```

---
# 参考サイト

- [GDIplusCODE (sakura.ne.jp)](http://gdipluscode.sakura.ne.jp/etc/shortcode4notes.html#section9)
- [Lotus Domino Designer 8.5 ヘルプ - 例: COM を使用して Lotus Domino オブジェクトにアクセスする](http://153.231.246.220/help/help85_designer.nsf/f4b82fbb75e942a6852566ac0037f284/3b7b2e64a2433180492575050037e130?OpenDocument)
- [ノーツ/ドミノの即戦力サンプルコード | 120 サンプル (tooljp.com)](http://tooljp.com/notes_qa/notes_qa_list.html)
- [PowerShellでNotesメールを取得する - 適材適所 (tekizai.net) 【注意点】32Bit版のPowerShellを使います](https://www.tekizai.net/entry/2019/09/14/130000#注意点32Bit版のPowerShellを使います)
- [Lotus Domino Designer 8.5 ヘルプ - createDxlExporter メソッド (smaconne.com)](https://www.smaconne.com/help/help85_designer.nsf/f4b82fbb75e942a6852566ac0037f284/6106d3607592c8594925762d0035bd6c!OpenDocument)