AWS Tools for PowerShellで、AWS S3の指定フォルダ直下のフォルダを取得したかった。例えばバケット内に次のような構成があるとして…
AWSLogs/
+-- o-xxx9xxx9xx/
+-- 000000000000/
| +-- ap-northeast-1/
| :
+-- 111111111111/
:
… AWSLogs/o-xxx9xxx9xx/ 直下の 000000000000/ 111111111111/ … というリストを得たい。
結論としては、以下のようにすればいい。
$objects = Get-S3ObjectV2 -BucketName $bucketName -Prefix "AWSLogs/o-xxx9xxx9xx/" -Delimiter "/" -Select CommonPrefixes
$objects には以下が格納されている。型は文字列。
AWSLogs/o-xxx9xxx9xx/000000000000/
AWSLogs/o-xxx9xxx9xx/111111111111/
:
直下のものの取得: -Delimiter "/" オプション
-Prefix でのプレフィックス指定だけだと、内部的には「フルパスがこれに前方一致する」ものをすべて返してしまうので、「指定ディレクトリ以下のファイルを再帰的にリストアップする」ような動作になる。期待動作と違ったり、該当するものが多いと時間がかかったり上限(1度に1,000件まで)に引っかかったりする。
直下のもの=プレフィックスから次の / までの要素だけを取得するには、 -Delimiter "/" を指定する。
$objects = Get-S3ObjectV2 -BucketName $bucketName -Prefix "AWSLogs/o-xxx9xxx9xx/" -Delimiter "/"
フォルダーの取得:-Select CommonPrefixes オプション
Get-S3ObjectV2 をそのまま実行すると、オブジェクト(ファイル的なもの)だけが返される。ディレクトリに相当するものはCommonPrefixと呼ばれており、取得したい時には -Select CommonPrefixes を付ける。
$objects = Get-S3ObjectV2 -BucketName $bucketName -Prefix "AWSLogs/o-xxx9xxx9xx/" -Delimiter "/" -Select CommonPrefixes
フォルダ相当のものが、文字列型で返される。
PS> $objects[0]
AWSLogs/o-xxx9xxx9xx/000000000000/
PS> $objects[0].GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
参考
以下を参考にした。
AWS CLIやSDKでのS3利用経験があれば、わりとすぐに「 -Delimiter "/" 使うだけだろ、悩むとこある?」と思う気がする。でも実際には上述の通り「オブジェクトだけが返さ、CommonPrefixは返されない」ということになる。ここの解決方法を、このGitHubイシューで知った。
まず「パイプライン処理と $AWSHistory - AWS Tools for PowerShell」によれば、AWS Tools for PowerShellは次の挙動をする。
- コレクションを返すコマンドレットは、コレクション内のオブジェクトが返される。
- 内部で実行したAWS APIの結果値が、上のコレクションの他にページング制御フィールドではない追加フィールドを含む場合は、
$AWSHistoryセッション変数に記録される。
つまり、APIの実行結果そのままではない。Get-S3ObjectV2コマンドレットであれば、Synopsysに書かれているように内部では S3 ListObjectsV2 APIを実行している。その結果値は以下で解説されている通り Contents に格納されたオブジェクトのコレクションとは別に、 CommonPrefixes にCommonPrefixが格納されている。
で、Get-S3ObjectV2コマンドレットはそのAPIの実行結果から Contents だけを抜き出されて返し、CommonPrefixはたぶん(確認してないけど)$AWSHistory変数に格納する。前記のGithub Issueでは…
「そういういものだから」(2021.10.16)
「いやもっとわかりやすく」(2021.10.18)
「-Select CommonPrefixesでもイケるっぽいけど、せめてドキュメントのExampleに入れようよ」(2022.5.13)
「わかったよドキュメント改定するよ」(2023.04.08)
…みたいなやり取りしてて、これ読んで-Select CommonPrefixesでイケるのがわかって助かったけど、最後のコメントから1年余り経過した2024年5月10日現在、ドキュメントは改定されてないですよね?