Powershellでネットワークドライブに接続(net useみたいなこと)しよう

# 参考
  * Windows PowerShell ドライブの管理
      * https://docs.microsoft.com/ja-jp/powershell/scripting/getting-started/cookbooks/managing-windows-powershell-drives?view=powershell-5.1
  * PowerShell で 共有ドライブ(マップドライブ)を作成する
      * http://tech.guitarrapc.com/entry/2013/07/08/231043


# やりたいこと

* バッチ処理の中で、他のWindowsサーバにネットワークドライブ接続したい
* ネットワークドライブ接続した後に、メインの処理(copyなど)をして、終わった時に切断したい
* 使っていいドライブ文字列(G〜Pまでの間)から、空いているドライブ文字列を使いたい

# コード
```ps1
# ネットワークドライブ接続

  # 1. 使用済みドライブ文字を配列格納
  [array]$usinglist = get-psdrive |%{$_.name}

  # 2. 使用しても良い全てのドライブ文字を配列格納
  [array]$alldrivelist = @("G","H","I","J","K","L","M","N","O","P")

  # 3.  2.と1.を比較し、現在利用可能なドライブ文字を格納
  [array]$availablelist = Compare-Object $alldrivelist $usinglist |?{$_.SideIndicator -match "<="}|%{$_.InputObject}

  # 4.  3.で作った配列のうち、最初の1文字を選択し、使用するドライブ文字とする
  $drivelettertoconnect = $availablelist[0]

  # 5. 4.で作った、使用するドライブ文字にマウントするパスを変数格納
  $SharePath = "\\localhost\c$"

  # 6. ネットワークドライブ接続（このPowershellセッションのみで使用可能）
  New-PSDrive -Name $drivelettertoconnect -PSProvider FileSystem -Root $SharePath

  # 7. やりたい処理(copyなど)

  # 8. exitする。(ネットワークドライブも自動で削除される)
  exit $exitcode

```
# 解説
### 1.使用済みドライブ文字を配列格納
* Get-Psdrive コマンドレットでは、使用しているドライブ一覧を取得できる
 ![Screen Shot 2017-10-08 at 11.03.16.png](https://qiita-image-store.s3.amazonaws.com/0/193085/c07b61af-1efd-51fe-5bab-fc7eb4673137.png)
* パイプに渡してドライブ文字列だけ取り出し、配列($usinglist)に入れる
![Screen Shot 2017-10-08 at 11.08.20.png](https://qiita-image-store.s3.amazonaws.com/0/193085/93dc1f68-b37d-94a3-f6d3-74dcc74301c9.png)  
![image.png](https://qiita-image-store.s3.amazonaws.com/0/193085/55b68790-5508-3587-6f01-bff6c2d280f7.png)

### 2.使用しても良い全てのドライブ文字を配列格納
* 私の環境で使用しているドライブ一覧からみてG〜Pあたりまでは使用して良さそうなので、G〜Pを配列($alldrivelist)に入れる
![image.png](https://qiita-image-store.s3.amazonaws.com/0/193085/27bed83b-84ec-b201-01b0-bca90cbc1a45.png)

### 3.  2.($alldrivelist)と1.($usinglist)を比較し、現在利用可能なドライブ文字を格納
* まず、Compare-Objectで２つの配列にある要素を比較できる。SideIndicatorが「<=」となっているものが、2. (alldrivelist)にあって、1. (usinglist)にない要素。つまり、使用済みでないドライブ文字列。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/193085/587137ae-fc5a-6910-64b3-975773dc5dbd.png)

* 次に、SideIndicatorが「<=」となっているもの(使用済みでないドライブ文字列)だけを取り出す
![image.png](https://qiita-image-store.s3.amazonaws.com/0/193085/0f3edc8e-2156-e92f-66a5-3ee7ee7aeed9.png)

* 配列(availablelist)に入れる
![Screen Shot 2017-10-08 at 11.34.52.png](https://qiita-image-store.s3.amazonaws.com/0/193085/f332b80b-6b7c-27a3-3a18-fa46b9541881.png)

### 4.  3.で作った配列(availablelist)のうち、最初の1文字を選択し、使用するドライブ文字とする

![Screen Shot 2017-10-08 at 11.40.01.png](https://qiita-image-store.s3.amazonaws.com/0/193085/0911c475-51a6-e512-1a30-db4c733a6b51.png)

### 5. 4.で作った、使用するドライブ文字(drivelettertoconnect)にマウントするパス(CIFS)を変数格納
![Screen Shot 2017-10-08 at 11.42.55.png](https://qiita-image-store.s3.amazonaws.com/0/193085/e3d0a499-57ab-8708-c513-57b9b5dc5a8c.png)

### ネットワークドライブ接続
* New-PSDrive コマンドレットを用いて、ネットワークドライブを作成
* New-PSDrive -Name (使用するドライブ文字) -PSProvider FileSystem -Root (マウントするパス)
![Screen Shot 2017-10-08 at 12.28.25.png](https://qiita-image-store.s3.amazonaws.com/0/193085/bd9ca677-c7d4-f929-4936-8dc5a2b6042a.png)





# 補足
* 作成したドライブは、ドライブを作成したPowershellセッションのみで使用可能です。
  * 永続的に使うには「-Persist」オプションを付けます。
    * 「-persist」オプションをつけると、GUIからも操作できます
      * こちらが本来のWindowsの「ネットワークドライブ」である
      * 上で私が作ったのは、細かく言うと「PSドライブ」と言う。(なので、PSセッションからexitすると作ったドライブも消える。)
      * -Persist を付けて作ったRドライブの例。(上で-Persistを付けないで作ったGドライブは、他のPSウインドウ、GUIには表示されない)
![Screen Shot 2017-10-08 at 12.32.43.png](https://qiita-image-store.s3.amazonaws.com/0/193085/c5cefaaf-83bb-6f15-bd80-1532a4f11102.png)


* -Credential オプションを用いて、資格情報も埋め込み可能です。
  * インターネットにいい記事がたくさんあるので割愛
* エラー処理、例外については別途実装する必要があります。

* Powershellの基本的な書き方について、slideshareに資料をupしています。
  * https://www.slideshare.net/TetsuYama/powershell-v1


# 追記(2017/10/09)
検証したサンプルコード載せときますね。scope指定も使いました(作成したネットワークドライブをスクリプト内、関数外で有効にするために)。

```ps1

# 引数受け取り
Param(
    [string]$userid,    # ユーザ名
    [string]$SharePath, # マウント先
    [string]$logfile    # 出力ログ
    )




# 資格情報取得
  $passwdfile = "C:\pass.txt"

  function Make-PSCredential($ID){
    try {
          $exitcode = 0
          $PlainPassword = import-csv $passwdfile |?{$_.user -like $ID} |%{$_.Password}
          $SecurePassword = ConvertTo-SecureString -String $PlainPassword -AsPlainText -Force
          $Credential = New-Object System.Management.Automation.PSCredential($ID, $SecurePassword)

    } catch [Exception] {

          $exitcode = 1
          $error |out-file -Append $logfile
          exit $exitcode

    } finally {

          "資格情報取得処理 $exitcode で終了します。0=正常、1=異常。" |out-file -Append $logfile
    }

      Return $Credential
  }

  $credential = Make-PSCredential -ID $userid




# ネットワークドライブ接続(exitで切断)
function net-use ($cifspath,$cred) {

    try {
          $exitcode = 0

          # 1. 使用済みドライブ文字を格納
          [array]$usinglist = get-psdrive |%{$_.name}

          # 2. 使用しても良い全てのドライブ文字を格納
          [array]$alldrivelist = @("G","H","I","J","K","L","M","N","O","P")

          # 3.  2.から1.を引いて、現在利用可能なドライブ文字を格納
          [array]$availablelist = Compare-Object $alldrivelist $usinglist |?{$_.SideIndicator -match "<="}|%{$_.InputObject}

          # 4.  3.で作った配列のうち、最初の1文字を選択し、使用するドライブ文字とする
          $drivelettertoconnect = $availablelist[0]

          # 5. ネットワークドライブ接続
          New-PSDrive -Name $drivelettertoconnect -PSProvider FileSystem -Root $cifspath -credential $cred -Scope script -ErrorAction Stop >null 2>&1
          return "${drivelettertoconnect}:"

    } catch [Exception] {

          $exitcode = 2
          $error |out-file -Append $logfile
          exit $exitcode

    } finally {

          "ネットワークドライブ接続処理 $exitcode で終了します。0=正常、1=異常。" |out-file -Append $logfile
    }

}

$connecteddrive = net-use $SharePath $credential




  # 6. メイン処理(copy)
  try {
        $exitcode = 0
        copy "${connecteddrive}\pass.txt" "C:\PerfLogs\" -ErrorAction stop >null 2>&1

  } catch [Exception] {

        $exitcode = 3
        $error |out-file -Append $logfile
        exit $exitcode

  } finally {

        "コピー処理 $exitcode で終了します。0=正常、1=異常。" |out-file -Append $logfile
  }


  # 7. 終了
  exit 0

```

以上