LoginSignup
2

More than 3 years have passed since last update.

posted at

updated at

配列から直接文字列を並べると正しく動かない場合がある

この記事はPowerShell Advent Calendar 2019 の 22 日目です。

野暮用でスクリプトを作っている時にハマった内容です。
小ネタレベルではありますし、普通に作ればハマらない内容ではあると思うのですが、ちょっとした小ネタとして記事を書いておきます。

環境

PSVersion5と6の両方でこの現象は発生するようです。
※PSVersion6はWSL上のPowerShellで確認しています。

経緯

Get-ChildItem $HashTable.Path\*.logのように、ハッシュテーブルに入れたファイルパスファイルを指定するワイルドカードを並べてをGet-ChildItemを実行すると、Get-ChildItem : 2 番目のパス フラグメントを ドライブ名または UNC 名にすることはできません。とエラーを吐きました。

実行ログ1
PS C:\> $HashTable = @{} #ハッシュテーブルの定義
PS C:\> $HashTable.Add("Path","C:\log") #ハッシュテーブルへ追加
PS C:\> Get-ChildItem $HashTable.Path\*.log #ハッシュテーブル内のパスと[\*.log]を並べてGet-ChildItemを実行
Get-ChildItem : 2 番目のパス フラグメントを ドライブ名または UNC 名にすることはできません。
パラメーター名:path2
発生場所 :1 文字:1
+ Get-ChildItem $HashTable.Path\*.log
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (C:\log:String) [Get-ChildItem]ArgumentException
    + FullyQualifiedErrorId : DirArgumentError,Microsoft.PowerShell.Commands.GetChildItemCommand

ハッシュテーブルが悪さをしているのかな?と思い、適当な変数に入れて実行すると、問題なく通ります。

実行結果2
PS C:\> $NonHashTable = $HashTable.Path
PS C:\>
PS C:\> Get-ChildItem $NonHashTable\*.log
    ディレクトリ: C:\log
Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019/12/20     13:08              0 1.log

変な文字列とかが入っちゃっている?と思って文字列長を調べましたが、結果は同じ文字列長。

実行結果3
PS C:\> $HashTable.Path.Length
6
PS C:\> $NonHashTable.Length
6

ハッシュテーブルが悪いのか?と思い、普通の配列で試してみるも、同じエラーが発生。

実行結果4
PS C:\> $Table = @("C:\log") #テーブルの定義と値の代入
PS C:\> Get-ChildItem $Table[0]\*.log
Get-ChildItem : 2 番目のパス フラグメントを ドライブ名または UNC 名にすることはできません。
パラメーター名:path2
発生場所 :1 文字:1
+ Get-ChildItem $Table[0]\*.log
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (C:\log:String) [Get-ChildItem]ArgumentException
    + FullyQualifiedErrorId : DirArgumentError,Microsoft.PowerShell.Commands.GetChildItemCommand

何故…?

原因

Get-ChildItemの引数と指定したパスをWrite-Hostで表示させてみたところ、
ハッシュテーブル/配列問わず、文字列の後に謎の空白が入っていることを確認しました。
そのため、Get-ChildItemに二つのパスが渡されている状態となり、エラーが発生していたようです。

実行結果6
PS C:\> Write-Host $NonHashTable\*.log
C:\log\*.log #正しく繋がっている
PS C:\> Write-Host $HashTable.Path\*.log
C:\log \*.log #間に空白がある…!
PS C:\> Write-Host $Table[0]\*.log
C:\log \*.log #間に空白がある…!

対策

そもそも、$HashTable.Path\*.logという書き方は美しくないよね、ということもあり、($HashTable.Path + "\*.log")と文字列を結合するように書き換えることで回避しました。

実行結果5
PS C:\> Get-ChildItem ($HashTable.Path + "\*.log")
    ディレクトリ: C:\log
Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019/12/20     13:08              0 1.log

余談

  • $HashTable.Path\*.log文字列を結合と称するのは何か違う気がしたので、文字列を並べるとしました。
  • 特にファイルパスを変数で取り扱うとき、「\」で変数名が丁度よく区切れるので並べて書いてしまう傾向があるのですが、それが良くなかったように思えます。
余談の例
###良くない書き方($date部分が通常の変数では問題ないけど、配列になるとエラーになる)
Get-ChildItem C:\log\$date\*.log
###少し気を付けた書き方
Get-ChildItem ("C:\log\" + $date + "\*.log")

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
2