【PowerShell】パイプラインで一括処理

PowerShell をちょっと勉強してみて、一番心に引っかかったパイプ処理についておぼえがき。

#### 結論

個人的には、こういうことだと思います。

**パイプラインは、表示結果が命。**
**一覧表示できるものは、パイプラインによる一括処理の対象になる。**


コマンドによるOU操作で動作を見ていきます。

#### 動作環境

Windows Server 2019
PowerShell のバージョンはちょっと失念しました。すみません。


#### やりたいこと

パイプライン処理でグループ「Rock」に所属するユーザをまるごとグループ「Water」へ移動させたいです。

##### 1. 「Rock」に属するユーザの一覧を表示結果として得る。

次のコマンドでユーザグループ「Rock」内のユーザ名を一覧で表示できます。

``` powershell
Get-ADGroupMember Rock | fl Name  #  
```

##### 2. 一覧で表示できたオブジェクトに対してやりたい操作を確認する．

ユーザ「スターミー」をグループ「Water」へ所属させるコマンドは次のとおり．

``` powershell
Add-ADPrincipalGroupMembership -Identity スターミー  -MemberOf Water
```

##### 3. パイプで繋げる．

パイプを利用して，一覧で表示できたオブジェクトすべてをグループ「Water」へ所属させます．
基本文法は**「操作対象オブジェクトの一覧 | オブジェクトへの操作内容」**です。


``` powershell
Get-ADGroupMember -Identity Rock | Add-ADPrincipalGroupMembership -MemberOf Water
# 操作対象となるRock グループのすべてのユーザを取得 | Water へ追加
```

#### 表示結果をムリヤリ形成する


PowerShell は上のパイプ処理の結果を何も返しません。結果表示がなければ、その先にパイプ処理を追加することはできません。
そこで結果表示をムリヤリ作ってしまうのが「-PassThru」オプションです。

先のパイプ処理にPassThruオプションを追加します．2行目です．

``` powershell
Get-ADGroupMember -Identity Rock | `
    Add-ADPrincipalGroupMembership -MemberOf Water -PassThru | `
    fl Name
```

するとWater に新たに追加されたユーザの名前一覧が結果表示されます。
この結果表示を用いて、さらに別のグループ「Grass」へこれらユーザを追加する操作もパイプ処理に組み込むことが可能です。

``` powershell 
Get-ADGroupMember -Identity Rock | `
    Add-ADPrincipalGroupMembership -MemberOf Water -PassThru | `
    Add-ADPrincipalGroupMembership -MemberOf Grass -PassThru
```

最後の操作に-PassThru をつけているので、これの実行結果として再びグループ追加対象となったユーザ一覧が表示されます。


**【注】**実際には追加先グループは**カンマで複数指定することが可能**なので、下記のほうがスマートです。

``` powershell
Get-ADGroupMember -Identity Rock | `
    Add-ADPrincipalGroupMembership -MemberOf Water, Grass -PassThru
```

### PassThru オプションを用いた他の例

PassThru オプションはユーザをグループ間で移動（＝追加&削除）するときに有効です。
移動操作は

1. ユーザを移動元グループから抽出
2. ユーザを移動先へ追加
3. ユーザを移動元から削除

することで実現します．

##### 1. ユーザを移動元グループから抽出

「イシツブテ」が「Rock」グループに所属していることの確認も踏まえて「Rock」から抽出します．

``` powershell
Get-ADGroupMember -Identity Rock | Where-Object {$_.Name -like "イシツブテ"}
#  完全一致なら -like は -eq でも良い．{$_.Name -eq 'イシツブテ'} とか．
#  -like はワイルドカードが使える．{$_.Name -like "イシ*"} としてもイシツブテは抽出できる．
#  ただその場合は他のユーザも抽出されうる．「イシアタマ」とか．
```


##### 2. ユーザを移動先グループへ追加

ユーザ「イシツブテ」をグループ「Water」へ追加するコマンド（復習）．

``` powershell 
Add-ADGroupmember -Identity イシツブテ -MemberOf Water
```

##### 3. ユーザを移動元グループから削除

ユーザ「イシツブテ」をグループ「Rock」から削除するコマンド（復習）．

``` powershell 
Remove-ADGropuMember -Identity イシツブテ -MemberOf Rock -Confirm:0
```

それぞれのコマンドの実行結果はnull なので、このままではパイプで次の処理に繋ぐことができません．
PassThru オプションをつけることで、操作対象となっているユーザ「イシツブテ」の情報をコマンド実行時に表示させることができます．
これを用いて追加と削除を一括で実行＝移動、を実現します．


``` powershell 
Get-ADGroupMember -Identity Rock | Where-Object {$_.Name -like "イシツブテ"} |`  #  イシツブテ をRock グループから抽出
    Add-ADPrincipalGroupMembership -MemberOf Water -PassThru |`  #  Water グループに追加
    Remove-ADPrincipalGroupMembership -MemberOf Rock -Confirm:0  #  Fruit グループから削除
```

**【参考】** 次のコマンドはPassThru オプションが抜けているのでRemove- 操作でエラーが出ます（パラメータ不足）．

``` powershell
Get-ADGroupMember -Identity Rock | Where-Object {$_.Name -like "イシツブテ"} |`
    Add-ADPrincipalGroupMembership -MemberOf Water |`  #  ここで結果表示がない
    Remove-ADPrincipalGroupMembership -MemberOf Fruit -Confirm:0
```

※以下のようなエラーが出る．

    Remove-ADPrincipalGroupMembership : オブジェクト参照がオブジェクト インスタンスに設定されていません。


**【さらに参考】** グループ間の移動操作は，ユーザを削除→追加，という順番でも実行できます．

``` powershell 
Get-ADGroupMember -Identity Rock | Where-Object {$_.Name -like "イシツブテ"} | `  #  イシツブテ をRock グループから抽出
    Remove-ADPrincipalGroupMembership -MemberOf Rock -Confirm:0  -PassThru | `  #  Fruit グループから削除
    Add-ADPrincipalGroupMembership -MemberOf Water  #  Water グループに追加
```


### まとめ

・パイプ処理は**表示**が命．表示結果を変数として，パイプで次の処理に繋げる．
・表示は**PassThru** オプションで強制的に得られる．
・イシツブテは岩タイプ．