none
get-childitem コマンドの強制終了を回避する方法はありますか? RRS feed

  • 質問

  • お世話になります。

    特定のフォルダ配下の情報をget-childitemコマンドを使って取得しようとしています。

    フォルダ配下に「パスの長いデータ(ファイル)」や「文字化けしたファイル」が存在するとコマンドがエラー終了してしまいます。

    ファイルが原因でエラーになるのは仕方ないのですが、コマンドが終了することなくフォルダ配下のデータを取得する方法はないでしょうか?

    $ErrorActionPreference = "SilentlyContinue"

    を試してみましたが、コマンドが異常終了($?の結果がFalse)となり停止してしまいました。

    下記は実行例で、\\test01\test01nt\data01\test 配下を表示させようとしていますが、「123456.......txt」のファイルパスが長すぎるため、コマンドが終了し「test00」「download」フォルダ配下の情報を取得することができません。

     =======================================================================================

     PS C:\Windows\system32> Get-ChildItem  \\test01\test01nt\data01\test -Recurse

        ディレクトリ: \\test01\test01nt\data01\test

    Mode                LastWriteTime     Length Name
    ----                -------------     ------ ----
    d----        2016/03/01     12:45            test00
    d----        2016/03/01     12:47            download
    -a---        2016/02/28     21:17          0 Out-Null
    -a---        2016/02/28     21:28          0 test01.txt
    -a---        2016/02/28     21:07          0 test test1 -  
    -a---        2016/03/01     10:45        765 StorageX - ショートカット.lnk
    -a---        2016/03/01     12:22          8 12345678912345678901234567890123456789012345678901234567890123456789012345
                                                 67890123456789012345678901234567890123456789012345678901234567890123456789
                                                 0123456789012345678901234567890123456789012345678901234567890.txt
    Get-ChildItem : 指定されたパス、ファイル名、またはその両方が長すぎます。完全限定型名は 260 文字未満で指定し、ディレクト
    リ名は 248 未満で指定してください。
    発生場所 行:1 文字:1
    + Get-ChildItem  \\test01\test01nt\data01\test -Recurse
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : ReadError: (\\test01\test01nt\data01\test:String) [Get-ChildItem], PathTooLongExcept
       ion
        + FullyQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand

     =======================================================================================

    最終的にはGet-ChildItem を|(パイプ)でつなぎ、ACL情報を取得しようと考えています。

    Get-ChildItem \\test01\test01nt\data01\test\* -Force -Recurse | Get-Acl | Select-Object @{Label=" Path";Expression={Convert-Path$_.PSPath}},PSPath,PSParentPath,PSChildName,owner,group,accesstostring,sddl | epcsv C:\LOG\acllog\data01_test_Source_acl.csv -Encoding Default

    回避策やアドバイスがあれば、ご教授頂きたいと思います。

    よろしくお願い致します。


    • 編集済み yoshihi 2016年3月1日 6:28
    2016年3月1日 6:28

すべての返信

  • 【追記です】

    ErrorActionのIgnoreオプションも検証してみましたが、結果は同じでした。

    当方のPowerShell Versionは下記の状態です。

    > $PSVersionTable

    Name                           Value

    ----                           -----
    PSVersion                      4.0
    WSManStackVersion              3.0
    SerializationVersion           1.1.0.1
    CLRVersion                     4.0.30319.34014
    BuildVersion                   6.3.9600.17400
    PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0}
    PSRemotingProtocolVersion      2.2

    よろしくお願いします。

    2016年3月1日 7:18
  • -ErrorActionパラメータで処理できるのは、処理が続行可能なエラーに限ります。(正確にはコマンドレットクラスのWriteErrorメソッドで書き出されたエラー)

    したがって、今回のPathTooLongExceptionのような致命的エラーが発生した場合、処理の続行はできません。

    またPathTooLongExceptionについては、.NET Frameworkの標準的なクラス(System.IO名前空間)でファイルを扱う以上、パス名を短くする以外に回避する方法はありません。

    PowerShellのファイル処理のコマンドレットは、内部的に.NETの標準のクラスを利用しているので、この制限を受けます。

    結論として、Get-ChildItemコマンドレットを利用する場合は、回避策は基本的には存在しないので、ファイルパスを短くする、ファイルパスが長いフォルダは扱わないなど、運用でカバーするしかないかと思います。

    他の方法で長いファイル名を扱うには、Win32APIを直接呼び出すか、ラップした.NETライブラリを利用するしかなさそうです。

    # 個人的には、システム管理用シェルなのに管理できないリソースがあるって何事!って思いますけどね。

    2016年3月1日 8:12
    モデレータ
  • 牟田口さん

    早々のご返答ありがとうございます。

    >PowerShellのファイル処理のコマンドレットは、内部的に.NETの標準のクラスを利用しているので、この制限を受けます。

    >他の方法で長いファイル名を扱うには、Win32APIを直接呼び出すか、ラップした.NETライブラリを利用するしかなさそうです。

    APIを直接呼び出す・ラップした.NETを利用するのは今の私にはレベルが高いです。。。

    しかし、.NETの制限を受けコマンドがエラーとなること。回避策が容易ではないことが分かっただけでも前進です。ご教授ありがとうございます。

    #分からなければ上記原因にたどり着くまで時間をかけてネットを徘徊していたと思います。

    今回は、一時的に特定フォルダ配下にあるデータのACLを取得するのが目的であるため、エラーが出た場所からアナログ的にパス指定しACLを取得していくことにします。

    #制限に該当するファイルが少ないことを願うばかりです。

    P.S 牟田口さんからご返答いただけるとは!ポケットリファレンス、Blogやttitter でいつもお世話になっています。


    2016年3月1日 11:38
  • yoshihi さま よろしく。

    実際のコードがどうなるかは分からないのですが、
    階層が深過ぎてオーバーフローしているのでなければ、(名称のみが長いのならば、)
    そして、該当ドライブが 8.3 形式の 短いフォルダ名やファイル名を許容していれば、
    それを使ってアクセスする方法がある気がしますが。

    見当違いでしたら、ご容赦下さい。

    2016年3月2日 7:29
  • パスの長さが260文字を超えるファイルでもリストを表示できるPowerShell スクリプトがスクリプトセンターで公開されていました。

    List All Files Regardless of 260 Character Path Limit

    このスクリプトを使い260文字を超えるパスを持つファイルについては例外処理を行うことで強制終了を回避できるのではないかと思います。



    2016年3月2日 9:05
  • ShiroYuki_Mot さま

    ご返答ありがとうございます。 ご返信おそくなりすみません。

    こちらこそよろしくお願いします。

    アドバイス通り、8.3形式でファイル指定するとエラーになること無く、結果を得ることができました。

    Mode                LastWriteTime     Length Name
    ----                -------------     ------ ----
    -a---        2016/03/01     12:22          8 123456~1.txt

    今回は特定のフォルダ配下の情報を取得しようとしています。Get-ChildItemコマンドでパスが長くエラーとなるファイルに対してはアドバイス頂いた方法で個別に情報を取得するか検討します!

    アドバイスありがとうございます。

    2016年3月5日 4:59
  • kenjinote さん

    ご返答ありがとうございます。ご返信遅くなりすみません。

    ご教示頂いた公開情報を早速使ってみました。

    PS C:\> Get-FolderItem \\testas01\testas01nt\data03\test

    【結果より1ファイルの情報を抜粋】

    FullName       : \\testas01\testas01nt\data03\test\test00\1234567890123456789012345678901234567890123456789012345678901
                     234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123
                     456789012345678901234567890123456789012345678901234567890123456789.txt
    ParentFolder   : \\testas01\testas01nt\data03\test\test00\
    FullPathLength : 274
    Extension      : txt
    Name           : 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012
                     345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234
                     5678901234567890123456789.txt
    Length         : 8
    LastWriteTime  : 2016/03/01 3:22:15

    パスの長さが260文字を超えるファイルの情報(FullName, ParentFolder, FullPathLength, Extension, Name, Length, LastWriteTime)も取得することができました。

    Get-FolderItemの結果からFullNameをget-aclコマンドに渡してACL情報の取得を試みましたが、エラー(「get-acl :パス’\\testas01\xxxxxxx.txt'が存在しないため検出できません。」)となりました。

     PS C:\> Get-FolderItem \\testas01\testas01nt\data03\test | % {@($input).FullName} | get-acl

    しかし、get-ChildItem コマンドではパスが長いファイルが存在すると致命的エラーで停止してしまいましたが、Get-FolderItemコマンドはget-aclコマンドでエラーになりますが、停止することなく特定フォルダ配下のファイルの情報を取得出来そうでした。

    $errorからget-aclで失敗したファイルも特定する事ができるのでとってもいい情報ありがとうございます。

    2016年3月5日 8:32