PowerShellでフォルダ一覧を取得すると、同僚は「isInheritanceBlocked」プロパティが使えるのに自分では見えない――この差は権限ではなく、モジュールや型拡張(ScriptProperty)の読み込み差で起きることがほとんどです。原因の特定と揃え方を手順付きで解説します。
起きている現象を正しく言語化する
質問で出てくるコードは、次のようなものです。
$folders = Get-ChildItem -Directory -Path "C:\Folders"
$folders[0]
ここで得られる $folders[0] は通常 System.IO.DirectoryInfo(System.IO.FileSystemInfo 派生)です。問題は「同僚のPowerShellでは $folders[0].isInheritanceBlocked が補完され、値も取れるのに、自分のセッションではメンバーとして存在しない」ことです。
まず重要なのは、これはWindowsの管理者権限(ローカル管理者)とは別の層で起きることが多い、という点です。PowerShellの表示やメンバーは、実体の.NETプロパティに加えて、PowerShellの拡張(Extended Type System: ETS)で“後付け”されるからです。
結論:isInheritanceBlockedは標準プロパティではなく、型拡張で追加されたScriptProperty
System.IO.FileSystemInfo や System.IO.DirectoryInfo 自体には、標準で isInheritanceBlocked という.NETプロパティはありません。多くのケースでこれは、次のどれかによってScriptProperty(スクリプトプロパティ)として追加されています。
- PowerShellモジュールの
Types.ps1xml(TypesToProcess) Update-TypeDataによるセッション内の型データ更新- ユーザープロファイル(
$PROFILE)での自動読み込み
そのため、同じPCでも「同僚のユーザーだけ」特定モジュールを入れていたり、プロファイルで型拡張を読み込んでいたりすると、同僚にだけ isInheritanceBlocked が見えるという差が生まれます。特に、NTFS権限を扱うモジュール(例:NTFS権限管理系のサードパーティモジュール)が、DirectoryInfo に「継承がブロックされているか」を返すScriptPropertyを足しているパターンがよくあります。
最初の確認:本当に“存在しない”のか、“表示されていないだけ”なのか
PowerShellはオブジェクトをそのまま出力しても、表示(フォーマット)上は一部の既定プロパティしか見せません。「画面に出ない」だけで、メンバー自体は存在することもあります。まずは Get-Member で事実を確定させます。
| 確認したいこと | コマンド例 | 分かること |
|---|---|---|
| isInheritanceBlockedがメンバーとして存在するか | $folders[0] | Get-Member -Name isInheritanceBlocked | 存在すれば MemberType が ScriptProperty 等で表示される |
| 隠しメンバー含めて確認する | $folders[0] | Get-Member -Force | ? Name -eq 'isInheritanceBlocked' | 通常見えないメンバーまで含めた一覧で確認できる |
| 表示定義だけが拡張されていないか | $folders[0] | Format-List * | 表示上の列が増えただけか、実体のメンバーがあるかの切り分けに使える |
| プロパティ候補の補完が効くか | $folders[0].<TAB> | 存在すれば候補に出る(環境差の把握に便利) |
ここでGet-Memberでも出てこないなら、あなたのセッションにはその型拡張が入っていません。以降は「なぜ入っていないか」「どう揃えるか」を詰めます。逆に Get-Member で出るのに画面表示に出ないだけなら、Select-Object で明示して使えばOKです(表示定義の差に過ぎません)。
環境差チェック:同じPowerShellを見ているか
同じPCでも、同僚は Windows PowerShell 5.1、自分は PowerShell 7(pwsh)ということは珍しくありません。モジュールが片方にしか対応していないと、型拡張も片方にしか入らず、結果としてプロパティが見えません。まずは両者で次を比較します。
$PSVersionTable | Format-List PSVersion, PSEdition, OS, Platform
$Host.Name
[Environment]::Is64BitProcess
| 差が出やすいポイント | 例 | 影響 |
|---|---|---|
| PowerShellの世代 | Windows PowerShell 5.1 / PowerShell 7.x | 読み込めるモジュール、プロファイル、モジュール配置先が変わる |
| 32/64bit | SysWOW64側で起動している | PSModulePathが違い、モジュールが見つからないことがある |
| プロファイルの実行有無 | -NoProfileで起動している | プロファイルでImportしている型拡張が入らない |
| 実行ポリシー | AllSigned / RemoteSigned など | プロファイルやスクリプトが途中で失敗し、結果としてImportが走らないことがある |
同僚が「通常のWindows PowerShell」を開いており、あなたが「pwsh」を開いている場合は、まず同僚と同じホストで再現するか、両方に同じモジュールを入れる方針を取るのが近道です。
原因の本命:同僚だけがモジュールをCurrentUserスコープで入れている
PowerShellモジュールは、インストール先(スコープ)によって「そのユーザーにだけ見える」状態になり得ます。典型的には次の配置です。
| PowerShell | スコープ | 代表的なパス | 説明 |
|---|---|---|---|
| Windows PowerShell 5.1 | AllUsers | C:\Program Files\WindowsPowerShell\Modules | 全ユーザーから参照可能 |
| Windows PowerShell 5.1 | CurrentUser | C:\Users\(ユーザー)\Documents\WindowsPowerShell\Modules | そのユーザーだけが参照可能 |
| PowerShell 7 | AllUsers | C:\Program Files\PowerShell\Modules | 全ユーザーから参照可能 |
| PowerShell 7 | CurrentUser | C:\Users\(ユーザー)\Documents\PowerShell\Modules | そのユーザーだけが参照可能 |
同僚が Install-Module -Scope CurrentUser で入れていれば、あなたのアカウントの PSModulePath にはその場所が存在しないため、同じPCでもモジュールが見つからず、結果として型拡張が読み込まれません。「同じマシンで両者ともローカル管理者」でも、ユーザーのドキュメント配下に置かれたモジュールは他ユーザーからは参照できないのがポイントです。
同僚の環境で「どのモジュールが追加しているか」を特定する
isInheritanceBlockedを提供している“元”が分からないと、揃え方が決まりません。特定の近道は「型データ(TypeData)を辿る」「モジュールのTypes.ps1xmlを探す」の二段構えです。
Get-TypeDataで型拡張の有無を確認する
同僚のセッションで、対象型に型拡張が入っているか確認します。DirectoryInfo と FileSystemInfo の両方を見てください(どちらに定義されているかは実装次第です)。
Get-TypeData -TypeName System.IO.DirectoryInfo
Get-TypeData -TypeName System.IO.FileSystemInfo
さらに、メンバー一覧から目的のプロパティを絞り込みます。
(Get-TypeData -TypeName System.IO.DirectoryInfo).Members.GetEnumerator() |
Where-Object Key -eq 'isInheritanceBlocked' |
ForEach-Object { $_.Value }
ここでScriptPropertyとして定義が出れば、「型拡張として追加されている」ことが確定します。逆に何も出ないなら、Format.ps1xml(表示定義)側の拡張で、見た目だけ追加されている可能性もあります。
モジュール内のTypes.ps1xmlを“文字列検索”で突き止める
現場で一番強いのは、シンプルに「isInheritanceBlocked」という文字列をモジュール配下から検索する方法です。同僚のアカウントで次を実行します(管理者でなくても可)。
$pattern = 'isInheritanceBlocked'
$paths = $env:PSModulePath -split ';' | Where-Object { Test-Path $_ }
Get-ChildItem -Path $paths -Recurse -File -ErrorAction SilentlyContinue |
Where-Object { $_.Extension -in '.ps1', '.psm1', '.psd1', '.ps1xml' } |
Select-String -Pattern $pattern -SimpleMatch -List |
Select-Object Path
結果に Types.ps1xml やモジュールのソースが出てきたら、その親フォルダ名がモジュール名のヒントになります。モジュールが分かったら、次で場所とバージョンも押さえます。
# 例:候補モジュールが分かったら
Get-Module -ListAvailable -Name YourModuleName | Select-Object Name, Version, Path
自分のセッションで“何が足りないか”を比較する
原因がモジュール差なら、比較が早いです。両者で次を取り、差分を確認します。
読み込まれているモジュール(セッション内)を比較する
Get-Module | Sort-Object Name | Select-Object -ExpandProperty Name
同僚にだけ存在するモジュール名が見つかったら、そのモジュールが型拡張を入れている可能性が高いです。ただし、型拡張が「プロファイルでUpdate-TypeData」されている場合は、モジュール一覧だけでは見つからないこともあります。
利用可能なモジュール(インストール済み)を比較する
Get-Module -ListAvailable | Sort-Object Name | Select-Object -ExpandProperty Name
この一覧に同僚のモジュールが出ず、自分には当然ないなら、同僚のCurrentUser領域にだけ入っていると判断できます。
差分を自動で出す(Compare-Object)
口頭でリストを見比べるより、機械的に差分を出す方が確実です。例えば、両者がそれぞれ自分のアカウントで以下を実行し、結果をファイルに保存して比較します。
# それぞれのユーザーで実行して保存
Get-Module -ListAvailable |
Sort-Object Name |
Select-Object -ExpandProperty Name |
Set-Content -Encoding UTF8 "$env:TEMP\modules.txt"
次に、同僚側の modules.txt を受け取り、自分のファイルと比較します。
$mine = Get-Content "$env:TEMP\modules_mine.txt"
$other = Get-Content "$env:TEMP\modules_other.txt"
Compare-Object -ReferenceObject $mine -DifferenceObject $other
=> が付く行が「同僚にはあるが自分にはない」候補です。ここから型拡張を入れているモジュールを絞り込みます。
PSModulePathを比較する
モジュールが見える/見えないの根本は検索パスです。次で比較します。
$env:PSModulePath -split ';'
同僚のパスに「同僚のドキュメント配下」が含まれていても、あなたのパスには含まれません(ユーザーが違うので当然です)。したがって、同僚がCurrentUserに入れたモジュールはあなたのセッションから見えません。
解決策:モジュールをAllUsersで入れる(推奨)
チーム内で同じ挙動に揃えたいなら、型拡張を提供しているモジュールをAllUsersに配置するのがシンプルです。PSGallery等から入れるケースを例にします。
管理者PowerShellでAllUsersにインストールする
# 管理者として実行したPowerShellで
Install-Module -Name YourModuleName -Scope AllUsers
既に同僚がCurrentUserに入れている場合でも、AllUsersに入れ直せば他ユーザーも参照できるようになります。インストール後、自分のアカウントで確認します。
Import-Module -Name YourModuleName
$folders = Get-ChildItem -Directory -Path "C:\Folders"
$folders[0] | Get-Member -Name isInheritanceBlocked
ここで MemberType が ScriptProperty として出れば成功です。もしモジュールが自動で読み込まれる設計なら、Import-Module なしでも、該当コマンド実行をきっかけに読み込まれる場合もあります。ただし型拡張だけを期待しているなら、明示Importしておく方が事故が減ります。
インストール前後で確認しておくと安全なこと
| 観点 | コマンド | 目的 |
|---|---|---|
| リポジトリの確認 | Get-PSRepository | どこからモジュールを取得する設定になっているか把握する |
| インストール済みバージョン確認 | Get-InstalledModule -Name YourModuleName | 端末ごとのバージョン差を避ける(同僚と揃える) |
| 読み込みエラー確認 | Import-Module YourModuleName -Verbose | 依存関係不足や互換性問題を早期発見する |
AllUsersに入れられない場合の現実的な代替
- あなたのアカウントにもCurrentUserで同じモジュールを入れる
- 同僚のモジュールフォルダを配布して、あなたのCurrentUser配下に配置する(オフライン環境向け)
- 社内リポジトリ(PSRepository)を用意し、承認済みモジュールだけを配布する
「PCは同じだがユーザーが違う」ケースでは、AllUsers配置にしておくと、将来の引き継ぎやRDP先でも再現性が上がります。
もう一つの原因:プロファイル($PROFILE)で同僚だけが読み込んでいる
同僚が毎回モジュールをインポートしている覚えがないのにプロパティが見えるなら、プロファイルに仕込みがある可能性があります。PowerShellのプロファイルは複数種類あり、どれが適用されるかはホストとEditionで変わります。
| 種類 | 参照 | 用途 |
|---|---|---|
| CurrentUserCurrentHost | $PROFILE.CurrentUserCurrentHost | そのユーザー+そのホスト限定 |
| CurrentUserAllHosts | $PROFILE.CurrentUserAllHosts | そのユーザー+全ホスト共通 |
| AllUsersCurrentHost | $PROFILE.AllUsersCurrentHost | 全ユーザー+そのホスト限定 |
| AllUsersAllHosts | $PROFILE.AllUsersAllHosts | 全ユーザー+全ホスト共通(チーム標準化に向く) |
同僚のプロファイルに、次のような記述があると、同僚だけ型拡張が入ります。
Import-Module YourModuleName
# または
Update-TypeData -TypeName System.IO.DirectoryInfo -MemberType ScriptProperty -MemberName isInheritanceBlocked -Value { ... }
プロファイルの場所は環境によって違うため、まずは「どこがプロファイルとして扱われているか」を両者で表示して一致/不一致を確認します。
$PROFILE | Format-List *
また、プロファイルが存在して実行されているかは次で確認できます。
Test-Path $PROFILE.CurrentUserAllHosts
Get-ExecutionPolicy -List
あなた側でも同じ挙動にしたいなら、社内運用として AllUsersAllHosts 側のプロファイルで共通化する、あるいはチーム配布のスクリプトを用意して毎回読み込む、という選択肢があります。
isInheritanceBlockedの実体を理解する:NTFS継承ブロックの判定はAreAccessRulesProtectedで代替できる
このプロパティ名から推測できる通り、対象は多くの場合「NTFSアクセス制御の継承がブロックされているか」です。WindowsのACLでは、継承の保護状態が AreAccessRulesProtected として取得できます。モジュールが何をしているか分からない時でも、次のように素のPowerShellだけで同等の判定ができます。
$dir = Get-Item "C:\Folders\Example"
$acl = Get-Acl -Path $dir.FullName
$acl.AreAccessRulesProtected # True なら継承が保護(=継承ブロック)されていることが多い
つまり、今すぐに「同僚と同じプロパティ名が必要」という事情がなければ、Select-Object の計算プロパティで代替するのも現実的です。
Get-ChildItem -Directory -Path "C:\Folders" |
Select-Object FullName,
@{ Name = 'IsInheritanceBlocked'; Expression = { (Get-Acl $_.FullName).AreAccessRulesProtected } }
大量フォルダに対して何度も Get-Acl を呼ぶと遅くなるため、パフォーマンスが気になる場合は対象を絞る、または必要な時だけ評価する運用にしておくと安全です(ScriptPropertyはアクセスした瞬間に評価されるため、知らないうちに重い処理を踏むことがあります)。
どうしてもプロパティ名を揃えたい場合:自前でScriptPropertyを追加する
「既存スクリプトが .isInheritanceBlocked を前提にしている」「同僚の手元のレポートと同じ列名で揃えたい」といった事情があるなら、あなたの環境に同等のScriptPropertyを追加できます。最短は Update-TypeData です。
Update-TypeData -TypeName System.IO.DirectoryInfo `
-MemberType ScriptProperty `
-MemberName isInheritanceBlocked `
-Value { (Get-Acl $this.FullName).AreAccessRulesProtected } `
-Force
これで、そのセッション内では次が動くようになります。
$folders = Get-ChildItem -Directory -Path "C:\Folders"
$folders[0].isInheritanceBlocked
ただし、これはセッションを閉じると消えます。恒久化したい場合は、プロファイルに同じ Update-TypeData を書くか、Types.ps1xml を作って読み込む運用にします。
プロファイルに追記して恒久化する例
# 例:CurrentUserAllHosts のプロファイルに追記
# PowerShell起動時に毎回同じ型拡張を適用する
Update-TypeData -TypeName System.IO.DirectoryInfo `
-MemberType ScriptProperty `
-MemberName isInheritanceBlocked `
-Value { (Get-Acl $this.FullName).AreAccessRulesProtected } `
-Force
なお、環境によっては「プロファイルはあるが実行されていない」こともあります。例えば、ショートカットやタスクスケジューラで -NoProfile を付けて起動している場合です。チームで運用するなら、どの起動方法でも同じ結果になるように、スクリプト側で必要な型拡張を適用する設計が安全です。
トラブルシューティング集:うまく見えない時のチェックポイント
| 症状 | チェック | 対処 |
|---|---|---|
| 同僚と同じコマンドでもプロパティが出ない | $PSVersionTable の差、$env:PSModulePath の差 | 同じEditionで揃える/モジュールを両方に入れる |
| Import-Moduleしても出ない | モジュールがTypesToProcessを持つか、読み込みエラーがないか | Import-Module -Verboseで確認、モジュール更新 |
| -NoProfileで起動すると出ない | プロファイル依存の型拡張か | AllUsersプロファイルに移す/運用を明文化する |
| タブ補完に出るが値取得で遅い | ScriptPropertyがGet-Aclを毎回実行している可能性 | 必要な時だけ評価、計算プロパティで一括取得 |
| GUIでは継承OFFなのにFalseになる | 対象が共有/再解析ポイント、権限不足、例外処理不足 | 対象パスを絞る、例外処理を入れる、管理者実行で検証 |
チームでの再発防止:環境を揃える運用設計
「同じスクリプトが人によって動いたり動かなかったり」を防ぐには、次のどれかを決めておくと安定します。
- 依存モジュールを明記し、AllUsersに入れる(端末標準化)
- スクリプト冒頭で
Import-Moduleを明示し、無ければエラーにする(再現性優先) - 社内リポジトリで承認済みモジュールだけ配布し、バージョンを固定する(監査対応)
- プロファイルに依存しない(-NoProfileでも動く)設計にする
特に「ScriptPropertyがある前提」でレポートや監視を作る場合、プロファイル依存にしてしまうと、別端末・別ユーザー・タスクスケジューラ実行で破綻しやすいです。スクリプト側で必要なモジュールを読み込むか、代替ロジック(Get-Acl)を持たせると、運用事故が減ります。
まとめ
isInheritanceBlocked が自分にだけ表示されないのは、ローカル管理者かどうかではなく、PowerShellの型拡張(ETS)を提供しているモジュールやプロファイルが同僚のユーザー環境にだけ入っている可能性が高いからです。まず Get-Member で存在を確認し、Get-TypeData と文字列検索で提供元を突き止め、モジュールをAllUsersに入れるか、必要なら自前で Update-TypeData を適用して揃える――この流れで解決できます。

コメント