SharePoint リストのカスタム列だけ取得する方法|標準列を除外してフィールド一覧を抽出

SharePoint リストの列を取得すると、Title や Created などの標準列に加え、利用者が追加したカスタム列、さらにシステム用の非表示列まで混在します。この記事では CSOM(PowerShell)で list.Fields を列挙し、標準列を除外して「カスタム列だけ」を抽出する現実的な判定方法をまとめます。

目次

SharePoint の「列(Field)」が混在する理由

SharePoint のリスト/ライブラリは、見た目以上に多くの列を内部に持っています。列は大きく分けると、次のような由来を持ちます。

  • 標準(組み込み)列:Title、Created、Modified、Author、Editor、ID、Attachments など、SharePoint が最初から提供する列
  • テンプレート/機能(Feature)由来の列:ドキュメント ライブラリ特有の列や、特定の機能を有効化したときに追加される列
  • サイト列(Site Column):サイトレベルで作られ、複数のリストで再利用できる列
  • リスト列(List Column):特定のリストにだけ存在する列(列の作成場所がリスト)
  • システム列/内部列:画面には表示されないが、検索、権限、バージョン管理、アイテムの状態管理などを支える列

問題は、「これは標準列」「これはカスタム列」と明示したフラグが CSOM の Field に用意されていない点です。結果として、Field のプロパティの傾向から「カスタムっぽい列」を抽出する、という現実解になります。

まず押さえる:表示名と内部名が違う(そして内部名が重要)

列には、ユーザーが画面で見る表示名(Title)と、API やコードで扱う内部名(InternalName)があります。内部名は作成時に確定し、表示名を変更しても内部名は基本的に変わりません。移行・連携・スクリプト化を考えるなら、表示名だけでなく内部名も必ず一緒に扱うのが安全です。

例表示名(Title)内部名(InternalName)よくある落とし穴
空白を含む列顧客 名顧客_x0020_名空白がエンコードされ、見た目と一致しない
作成後に名前変更案件名(現表示)ProjectName(作成時)画面上の名称は変わるが、内部名は変わらない
同名列を作り直した担当者担当者0 / 担当者1…重複回避のため内部名が自動採番されることがある

結論:カスタム列は「プロパティの特徴」でフィルタするのが実務的

SharePoint では Field に「標準/カスタム」の明確なラベルがありません。そこで、現場でよく採られるのが次の 3 条件です。

  • Hidden = false(非表示ではない)
  • ReadOnlyField = false(読み取り専用ではない)
  • CanBeDeleted = true(削除可能)

これらを満たす列を「カスタム列候補」とみなすと、標準列や内部列の大半を除外できます。特に CanBeDeleted は強力で、組み込み列は削除不可のものが多いため、候補がかなり絞れます。

プロパティ意味カスタム列抽出に効く理由例外になりやすいケース
HiddenUI から非表示の列か内部列・補助列の多くは Hidden = true運用で「非表示のカスタム列」を作ると取りこぼす
ReadOnlyField読み取り専用の列かシステム列は ReadOnlyField = true が多いワークフローや自動更新前提でカスタム列を ReadOnly にすると取りこぼす
CanBeDeleted削除可能な列か組み込み列は削除不可が多く、強いフィルタになる機能追加列や保護された列は「カスタムでも削除不可」の場合がある

PowerShell + CSOM で「カスタム列候補」を抽出するサンプル

ここでは list.Fields を読み込み、上記 3 条件でフィルタして、表示名と内部名を一覧出力します。認証部分は環境によって異なるため、SharePoint Online で扱いやすい「PnP PowerShell で接続し、CSOM コンテキストを取り出す」形にしています(列の列挙ロジック自体は CSOM です)。

準備:PnP PowerShell のインストール

Install-Module PnP.PowerShell -Scope CurrentUser

抽出スクリプト(カスタム列候補)

$siteUrl   = "https://tenant.sharepoint.com/sites/YourSite"
$listTitle = "YourList"

# SharePoint Online / MFA 環境でも扱いやすい接続

Connect-PnPOnline -Url $siteUrl -Interactive

# CSOM コンテキストを取得(以降は CSOM で Fields を扱う)

$ctx  = Get-PnPContext
$web  = $ctx.Web
$list = $web.Lists.GetByTitle($listTitle)

$fields = $list.Fields

# 必要なプロパティだけを Include して通信量を抑える

$ctx.Load($fields, "Include(Title,InternalName,Id,TypeAsString,Hidden,ReadOnlyField,CanBeDeleted,Sealed,FromBaseType,Group,Required)")
$ctx.ExecuteQuery()

# 基本フィルタ:非表示ではない/読み取り専用ではない/削除可能

$customCandidates = $fields | Where-Object {
($*.Hidden -eq $false) -and
($*.ReadOnlyField -eq $false) -and
($_.CanBeDeleted -eq $true)
}

# 画面で見て確認しやすいように並べ替えて表示

$customCandidates |
Sort-Object Title |
Select-Object Title, InternalName, TypeAsString, Required, Group, Id |
Format-Table -AutoSize

# CSV に吐き出しておくと後工程が楽

$customCandidates |
Sort-Object Title |
Select-Object Title, InternalName, TypeAsString, Required, Group, Id |
Export-Csv -Path ".\custom-fields.csv" -NoTypeInformation -Encoding UTF8

診断用:なぜ除外されたのかを見える化する

「思ったより列が取れない」「標準列が混ざる」と感じたら、まずはフィルタ前の全列を診断して、どのフラグが効いているかを確認するのが近道です。

$fields |
  Select-Object Title, InternalName, TypeAsString, Group,
    Hidden, ReadOnlyField, CanBeDeleted, Sealed, FromBaseType,
    @{Name="IsCustomCandidate";Expression={ (-not $_.Hidden) -and (-not $_.ReadOnlyField) -and ($_.CanBeDeleted) }} |
  Sort-Object IsCustomCandidate, Title |
  Format-Table -AutoSize

この「診断」を 1 回挟むだけで、環境固有の列(テンプレート列、ソリューション列、運用で非表示化された列など)が見えて、フィルタ調整がスムーズになります。

判定精度を上げる追加条件(目的別に使い分ける)

3 条件だけでも実務では十分役立ちますが、「この列は本当に標準列ではないのか?」をもう少し確度高くしたい場合、追加で見られる代表的なプロパティがあります。全部を一律に厳しくすると取りこぼすため、目的に応じて段階的に足すのがおすすめです。

追加条件見方効きどころ注意点
Sealed = false保護された列(システムが封印)かどうか標準列・機能列は Sealed = true が混ざりやすく、除外の精度が上がる「どうしても消してほしくない」列を運用で保護している場合は、ここだけで判断しない
FromBaseType = falseベース定義(基盤)由来かどうか組み込み列の除外に効きやすいテンプレートやソリューション由来の列を「標準扱い」にしたい場合は要調整
Group の傾向列グループ(UI の分類)カスタム列を「カスタム列」などのグループに揃えていると判定が安定する過去の運用でグループがバラバラだと当てにならない
TypeAsString で除外Computed / ContentTypeId など内部計算列や管理用の列をさらに減らせる計算列(Calculated)を「カスタム扱い」にしたい場合は除外しない

強化フィルタの例(より「標準列っぽいもの」を落とす)

$customCandidatesStrict = $fields | Where-Object {
    ($_.Hidden -eq $false) -and
    ($_.ReadOnlyField -eq $false) -and
    ($_.CanBeDeleted -eq $true) -and
    ($_.Sealed -eq $false) -and
    ($_.FromBaseType -eq $false)
}

ただし、FromBaseType / Sealed は環境や列の由来で挙動が変わることがあります。「ユーザーが追加した列だけ欲しい」のか、「システム列を除いた入力対象列が欲しい」のかで、最適な条件は変わります。

パターンで見分ける:標準列・内部列に多い「内部名」と「グループ」

プロパティ判定に加えて、列名のパターンを知っておくと「この列はシステムっぽい」を素早く見抜けます。もちろん例外はありますが、トラブルシュートに強い武器になります。

よくあるパターン例(InternalName)傾向扱いの目安
先頭がアンダースコア_UIVersionString / _ModerationStatus内部管理用の列に多いまずは標準/内部列として疑う
OData__ で始まるOData__ColorTagモダン UI や表示制御関連で見かけやすい入力項目の抽出目的なら除外候補
ドキュメント ライブラリ特有FileRef / FileLeafRef / FSObjTypeファイルパスや種別など、ライブラリ内部の根幹情報ほぼ標準/内部列(消さない)
リンク表示用LinkTitle / LinkTitleNoMenuビュー表示に使われる計算列的なもの入力項目ではないので通常は除外

また、Group(列グループ)に「Base Columns」「Core Document Columns」「_Hidden」などが含まれる場合、標準列や内部列の可能性が高いです。逆に、組織ルールでカスタム列を「Custom Columns」「業務項目」などのグループに統一していると、Group 条件が強いフィルタになります。

「カスタム列だけ」の定義を揃えると、判定が一気に安定する

現場で混乱しやすいのが、関係者によって「カスタム列」の意味がズレることです。例えば、テンプレートが追加した列や、アプリ/ソリューションが作った列をカスタムに含めるのか、含めないのかで結果が変わります。そこで、用途別にフィルタのプリセットを作ると運用が安定します。

目的おすすめ条件得られるもの向いている作業
入力対象の列を取りたいHidden = false AND ReadOnlyField = falseユーザーが触れる可能性の高い列フォーム設計、入力項目の棚卸し
「ユーザー作成列っぽい」ものを取りたいHidden = false AND ReadOnlyField = false AND CanBeDeleted = true標準列をかなり避けつつ、実用的な候補移行、連携、列一覧の自動生成
削除候補(掃除対象)を厳しめに取りたい上記 + Sealed = false + FromBaseType = false標準/保護列をより避けた候補不要列の整理、ガバナンス
100% を狙いたいプロパティ判定 + 除外リスト(InternalName の denylist)環境に最適化された確実な結果本番自動処理、監査、定期ジョブ

例外パターン:この方法でもズレることがある(対策込み)

プロパティ判定は実用的ですが、厳密な保証ではありません。よく起きる例外と、その対策を押さえておくと運用が楽になります。

カスタム列を非表示にしている

入力フォームからは消したいが保持はしたい、といった理由で Hidden = true にされるカスタム列があります。この場合、基本フィルタでは取りこぼします。

  • 対策:目的が「ユーザー作成列の棚卸し」なら Hidden 条件を外す、または「非表示のカスタム列も別枠で抽出」する

自動更新前提で ReadOnly にしている

Power Automate などで値を入れる運用だと、意図的に ReadOnlyField = true にされることがあります。

  • 対策:ReadOnlyField は「入力対象」を探すときに強い。棚卸しなら ReadOnly を許容し、別途「入力可否」フラグとして扱う

テンプレート列やソリューション列をどう扱うか

テンプレートやアドインが追加した列は「組み込みではないが、利用者が直接作ったわけでもない」中間的な存在です。ここをカスタムに含めるかどうかで結果がぶれます。

  • 対策:列の Group や命名規則(接頭辞)を組織ルールで決め、機械判定しやすくする
  • 対策:InternalName の denylist / allowlist を併用して“最終確定”する

実務で効く小技:除外リスト(denylist)を「内部名」で持つ

自動化を本番で回すなら、最後は InternalName の除外リストが最も堅いです。理由はシンプルで、標準列の内部名は基本的に不変だからです(表示名は変わる)。

例えば、最低限除外しておくことが多い内部名は次のようなものです(リスト種別で差があるため、ここでは代表例だけに留めます)。

  • ID
  • Title
  • Created
  • Modified
  • Author
  • Editor
  • Attachments
  • ContentType
  • ContentTypeId

プロパティ判定で候補を絞ったうえで、最後に denylist を当てると、誤判定がぐっと減ります。

$denyInternalNames = @(
  "ID","Title","Created","Modified","Author","Editor","Attachments",
  "ContentType","ContentTypeId"
)

$customCandidatesStable = $customCandidates | Where-Object {
  $denyInternalNames -notcontains $_.InternalName
}

CSOM 以外の方法も知っておく(ただし最終的な考え方は同じ)

列の取得は CSOM 以外にも、PnP PowerShell のコマンドだけで行う方法や、REST API で取得する方法もあります。ただし「標準/カスタムのラベルが無いので、結局はプロパティや名前で判定する」という本質は変わりません。

PnP PowerShell だけで取得する例

Connect-PnPOnline -Url $siteUrl -Interactive

Get-PnPField -List $listTitle |
Where-Object { $*.Hidden -eq $false -and $*.ReadOnlyField -eq $false -and $_.CanBeDeleted -eq $true } |
Select-Object Title, InternalName, TypeAsString, Required, Group

REST API の例(取得はできるが、判定は結局必要)

REST でもフィールド一覧は取得できますが、返ってくる列情報は多く、ここから「カスタムだけ」を切り出すには同様に Hidden や ReadOnlyField、Sealed などでのフィルタが必要です。PowerShell で完結させたいなら、CSOM または PnP に寄せたほうが実装・保守ともに楽です。

まとめ:100% の正解より、目的に合う「条件設計」が成果につながる

SharePoint の列には「標準/カスタム」の明確なラベルが無いため、Hidden / ReadOnlyField / CanBeDeleted を軸に「カスタム列候補」を抽出するのが現実的です。さらに精度が必要なら Sealed / FromBaseType を追加したり、最後は InternalName の denylistで確定させると安定します。列の取得結果は、必ず表示名と内部名をセットで出力し、後工程の事故を防ぎましょう。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次