New-Object PSObject -Property　と　New-Object PSObject | Select-Object -Property　についての小話

# 言いたいこと
早い話これが、

```powershell
$list = @()
$KSAD = @("これ" , "それ", "あれ" , "どれ")
$5W1H = @("when" , "where", "who" , "what", "why", "how")
$list += New-Object PSObject -Property @{
    $KSAD[0] = $null
    $KSAD[1] = $null
    $KSAD[2] = $null
    $KSAD[3] = $null
    $5W1H[0] = $null
    $5W1H[1] = $null
    $5W1H[2] = $null
    $5W1H[3] = $null
    $5W1H[4] = $null
    $5W1H[5] = $null
}
```

こう書けたってお話を書いていこうと思います。

```powershell
$list = @()
$KSAD = @("これ" , "それ", "あれ" , "どれ")
$5W1H = @("when" , "where", "who" , "what", "why", "how")
$list += New-Object PSObject | Select-Object -Property ($KSAD + $5W1H)
```

# New-Object PSObjectでのオブジェクト作成
以前からPowershellで配列処理っぽいことをやろうと思ったとき、
``New-Object PSObject -Property @{...}``
を使ってオブジェクトを作成して、データを積み重ねて処理を行っていました。

``New-Object PSObject``を使う際の用法は概ね上記のように ``-Property @{...}``
を続けて記述して、プロパティ名とvalueを格納するのが一般的なのかなと、
いくつかのPowershellの記事を見て思います。

そして蓄積しようとすると、何らかの形でforループなどを用いて処理します。
こんな感じで。
```powershell
$data ## 何らかの連想配列・ハッシュテーブル
$list = @()
$KSAD = @("これ" , "それ", "あれ" , "どれ")
$5W1H = @("when" , "where", "who" , "what", "why", "how")
foraech($x in $data){
    $list += New-Object PSObject -Property @{
        $KSAD[0] = $x.kore
        ～略～
        $KSAD[3] = $x.dore
        $5W1H[0] = $x.when
        ～略～
        $5W1H[5] = $x.how
    }
}
```
つまり、``New-Object PSObject -Property @{}``構文にて
**PSObjectを作成すると同時にプロパティとvalueを作成**し、for文の数だけ繰り返す。
ということです。

しかし、当然ながら上記の構文だと@{}内でfor文やif文が使えません。
文法の幅が狭くなるということです。

例えば、連想配列を処理してると以下のような構造の連想配列があるとします。
| これが | → | こうだった場合 |
| --- | --- | --- |
| $data.when | → | $data.situation.when |
| $data.where	| → | $data.situation.where	 |
| $data.who		| → | $data.situation.who		 |
| $data.what	| → | $data.situation.what		 |
| $data.why		| → | $data.situation.why		 |
| $data.how		| → | $data.situation.how		 |

```$5W1H = @("when" , "where", "who" , "what", "why", "how")```だとしたら、
$data.situation.whenは``$data.situation[0]``、``$data.situation.($5W1H[0])``
のような書き方ができ、配列番号を使って指定することができます。
この配列番号を上手く使ってfor文などで繰り返しの処理を行いたいのですが、
先ほども申した通り@{}内でfor文やif文が使えません。
やろうと思うと先にNULLの状態でプロパティを作成しておき、
そのあとfor文やif文で自由に記述をすることになります。

したがって、**PSObjectを作成すると同時にプロパティとvalueを作成**ではなく、
**PSObjectを作成すると同時にプロパティを作成し、NULLのvalueを作成**する必要があります。

NULLのvalueを作成するだけなら簡単です。
``New-Object PSObject -Property @{}``構文で以下のように作文するだけです。
```powershell
$list += New-Object PSObject -Property @{
    $KSAD[0] = $null
    ～略～
    $KSAD[3] = $null
    $5W1H[0] = $null
    ～略～
    $5W1H[5] = $null
}
```
これだけです。あとは自由に各プロパティに指定の値を入れるだけです。
ですがこのNULLを入れる処理もいい感じにできないのがどうもすっきりしないのです。

# New-Object PSObject | Select-Object -Property 構文の発見
何かいい方法はないかと試行錯誤しながら書き殴っていた時、ふと以下のコマンドを投入しました。
```powershell
> $KSAD = @("これ" , "それ", "あれ" , "どれ")
> $5W1H = @("when" , "where", "who" , "what", "why", "how")
> $param = New-Object PSObject | Select-Object -Property ($KSAD + $5W1H)
> $param | Format-Table

これ それ あれ どれ when where who what why how
-- -- -- -- ---- ----- --- ---- --- ---

> $param | Get-Member

   TypeName: Selected.System.Management.Automation.PSCustomObject

Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
how         NoteProperty object how=null
what        NoteProperty object what=null
when        NoteProperty object when=null
where       NoteProperty object where=null
who         NoteProperty object who=null
why         NoteProperty object why=null
あれ          NoteProperty object あれ=null
これ          NoteProperty object これ=null
それ          NoteProperty object それ=null
どれ          NoteProperty object どれ=null
```
っ!これや!~~(綾鷹感)~~

天啓を受けたかのような爽快感です！
普段、`` | Select-Object -Property``構文は指定のプロパティのみを表示させたいときに使うのですが、
指定プロパティが無い場合、NULLが入るようです。知らんかった。

``New-Object PSObject -Property @{}``構文
と
``New-Object PSObject | Select-Object -Property``構文
を並べてみます。
どうです？かなりすっきりしたと思いませんか？
```powershell
$list += New-Object PSObject -Property @{
    $KSAD[0] = $null
    ～略～
    $KSAD[3] = $null
    $5W1H[0] = $null
    ～略～
    $5W1H[5] = $null
}
```
```powershell
$param = New-Object PSObject | Select-Object -Property ($KSAD + $5W1H)
```
これがやりたかったんだよ！


# 考察
以下二つの構文の比較となります。
``New-Object PSObject -Property @{}``構文
``New-Object PSObject | Select-Object -Property``構文

この``New-Object PSObject | Select-Object -Property``構文でググってみると、
以下の記事ですでにこの構文を使っている方がいらっしゃいました。

https://qiita.com/oxalis-san/items/c33db07fcd4d10ae221f
https://mtgpowershell.blogspot.com/2011/01/psobjectnew-object.html

他にもいらっしゃるものと思いますが、それでもあまり主流ではない印象です。
というのもどこか裏技というか小技のような臭みを残している感じがします。
Select-Objectの性質上たまたまこうなっているだけなんだとしたら、
それを理由に正式なリファレンスとは言い切れないという感じなんでしょうか。

それに``New-Object PSObject -Property @{}``構文の方が、
どういった処理をしているかが分かり易いというのもあるかもしれません。
事前にNULLを入れた状態の連想配列を準備して-Propertyで指定することもできるんでしょうが、
それでもクドイ書き味になりそうです。。。
そもそもNULL使うのを控えるべきなんでしょうか？

# 改めて、言いたかったこと
これが、

```powershell
$list = @()
$KSAD = @("これ" , "それ", "あれ" , "どれ")
$5W1H = @("when" , "where", "who" , "what", "why", "how")
$list += New-Object PSObject -Property @{
    $KSAD[0] = $null
    $KSAD[1] = $null
    $KSAD[2] = $null
    $KSAD[3] = $null
    $5W1H[0] = $null
    $5W1H[1] = $null
    $5W1H[2] = $null
    $5W1H[3] = $null
    $5W1H[4] = $null
    $5W1H[5] = $null
}
```

こう書けました。

```powershell
$list = @()
$KSAD = @("これ" , "それ", "あれ" , "どれ")
$5W1H = @("when" , "where", "who" , "what", "why", "how")
$list += New-Object PSObject | Select-Object -Property ($KSAD + $5W1H)
```


ご拝読ありがとうございました。