はじめに

Outlookメール(.msg)をPowerShellで解析し、Redmineへ自動起票したい。しかし、開発前に「Redmineに渡すJSONの形」「各項目のID」「必須入力」を確認する必要がある。

Redmineの標準REST APIには、新規チケットの必須項目をロール・ワークフロー込みですべて返す専用スキーマAPIはない。 そこでGET APIを組み合わせ、わからない部分は管理者設定や検証環境で補う。

この記事のPowerShellスクリプトはGET専用。実行してもチケットは作らない。

1. チケット登録用JSONの構造

起票は POST /issues.json に、トップレベルが issue のJSONを送る。

{
  "issue": {
    "project_id": 10,
    "tracker_id": 2,
    "subject": "Outlookメールから自動起票",
    "description": "端末の設定確認をお願いします。",
    "priority_id": 2,
    "custom_fields": [
      { "id": 5, "value": "システムA" }
    ]
  }
}

上記の数値IDは例であり、実際には接続先Redmineから取得すること。公式の基本例では project_id と subject を指定する。実際の必須項目はトラッカー・カスタムフィールド・ユーザー権限などによって変わる。tracker_id を明示しておくと自動起票の振り分けが安定する。

2. 使うGET API一覧

GET API 調べられること 備考
/projects/{id}.json?include=trackers,issue_categories,issue_custom_fields 対象プロジェクト、トラッカー、カテゴリ、利用カスタムフィールド issue_custom_fields はRedmine 4.2以降
/trackers.json トラッカーIDと名称、標準フィールド enabled_standard_fields はRedmine 5.0以降
/projects/{id}/issue_categories.json カテゴリIDと名称 プロジェクト固有
/enumerations/issue_priorities.json 優先度IDと名称
/issue_statuses.json ステータスIDと名称 起票時に指定できるかは別
/custom_fields.json 項目の型、必須フラグ、候補値 管理者権限が必要

3. PowerShellで受け入れ項目を調査する

以下を RedmineSchemaInspector.ps1 に保存し、URLとプロジェクト識別子を変更する。APIキーは実行時入力にする。

# RedmineSchemaInspector.ps1
# GET専用:チケットを作成・更新・削除しない
$ErrorActionPreference = "Stop"

$baseUrl = "https://redmine.example.com".TrimEnd("/")
$projectKey = "sample-project"
$outDir = Join-Path $PSScriptRoot "redmine-schema"

$secureKey = Read-Host "Redmine APIキー" -AsSecureString
$credential = [pscredential]::new("redmine", $secureKey)
$apiKey = $credential.GetNetworkCredential().Password

$headers = @{
    "X-Redmine-API-Key" = $apiKey
    "Accept" = "application/json"
}

New-Item -Path $outDir -ItemType Directory -Force | Out-Null

function Get-Redmine {
    param([Parameter(Mandatory)][string]$Path)
    Invoke-RestMethod -Uri "$baseUrl$Path" -Method Get -Headers $headers
}

$project = ::EscapeDataString($projectKey)

$endpoints = [ordered]@{
    project = "/projects/$($project).json?include=trackers,issue_categories,issue_custom_fields"
    trackers = "/trackers.json"
    categories = "/projects/$($project)/issue_categories.json"
    priorities = "/enumerations/issue_priorities.json"
    statuses = "/issue_statuses.json"
    custom_fields = "/custom_fields.json"
}

$responses = @{}

foreach ($name in $endpoints.Keys) {
    Write-Host ("GET " + $endpoints[$name])
    try {
        $data = Get-Redmine -Path $endpoints[$name]
        $responses[$name] = $data
        $file = Join-Path $outDir ($name + ".json")
        $data | ConvertTo-Json -Depth 30 | Set-Content -Path $file -Encoding UTF8
        Write-Host "保存: $file"
    }
    catch {
        Write-Warning ("{0}: {1}" -f $name, $_.Exception.Message)
    }
}

Write-Host "=== プロジェクト ==="
if ($responses.ContainsKey("project")) {
    $p = $responses["project"].project
    $p | Select-Object id, identifier, name | Format-List
    $p.trackers | Select-Object id, name | Format-Table -AutoSize
    $p.issue_custom_fields | Select-Object id, name | Format-Table -AutoSize
}

Write-Host "=== 優先度 ==="
if ($responses.ContainsKey("priorities")) {
    $responses["priorities"].issue_priorities |
        Select-Object id, name, is_default | Format-Table -AutoSize
}

Write-Host "=== カスタム項目(管理者のみ) ==="
if ($responses.ContainsKey("custom_fields")) {
    $responses["custom_fields"].custom_fields |
        Where-Object { $_.customized_type -eq "issue" } |
        Format-List id, name, field_format, is_required, multiple, possible_values
}

Write-Host ("出力先: " + $outDir)

実行例:

Set-ExecutionPolicy -Scope Process Bypass
.\RedmineSchemaInspector.ps1

custom_fields.json に対して403が返る場合は管理者権限を確認する。取得に失敗した項目は警告を表示し、ほかの調査を続ける。保存したJSONには組織内のプロジェクト名・項目名が含まれる可能性があるため、そのままQiitaやGitHubへ公開しないこと。

4. 「必須項目」を確定する際の注意

APIで取得できるのは、利用可能なトラッカー・カテゴリ・優先度・カスタム項目のIDなど。管理者権限があればカスタムフィールドの is_required や候補値も取得できる。

一方で、ロールやワークフローで必須/読み取り専用になっている項目、拡張プラグインの独自検証は、これらのGET結果だけで完全には判定できない。実際の起票アカウントで新規チケット画面を確認し、管理者と設定を照合する。

5. HTTP 422からバリデーションエラーを確認

Redmineでは、登録内容が検証に失敗するとHTTP 422 Unprocessable Entity と errors 配列が返される。

{
  "errors": [
    "題名を入力してください",
    "担当部署を入力してください"
  ]
}

※これは説明用の架空の応答。実際のエラーメッセージや項目は環境により異なる。

POSTにドライラン機能があるわけではない。正常ならチケットが作られるため、必ず検証環境で実施し、本番での試行錯誤を避ける。

6. Outlookメール→Redmine自動起票へ展開

  • 定義取得:本記事のGETスクリプトで登録先のIDを確認する。
  • メール解析:件名→subject、本文→description、依頼種別→tracker_id、部署等→custom_fields に変換する。
  • 事前チェック:わかっている必須値・型を検査してからPOSTする。
  • 起票・エラー処理:POST /issues.json の成功(通常201)と422を記録する。
  • 重複防止:同じ.msgを複数回処理しても二重起票しない仕組みを用意する。

項目IDのマッピングはプログラムに直書きせず、設定JSONへ分離するのがおすすめ。

まとめ

RedmineのAPI起票は、最初にGETで項目のIDと設定を調べると実装しやすい。ただし必須項目をすべてGETで確定することはできない。権限・ワークフロー・管理者設定を合わせて確認し、テスト後に自動起票へ進める。

参考資料(公式)

Previous Post Next Post