Azure FunctionsをPowerShellで使ってみよう

## はじめに
Azure Function(Function App)は、AWSでいうところのLambdaのような所謂サーバーレスアーキテクチャの仲間です。
C\#やNode.jsのほかにもバッチやPowerShellなどを使って処理を実装することも可能です。
そこで今回は、PowerShellのスクリプトを使って簡単なFunction Appを作ってみます。

## 注意
この記事は、2016年10月7日現在のFunction Appのランタイムバージョンであるv0.6をベースにしているのでバージョンに気を付けてください。

## Function Appを作成する
AzureのポータルでFunctionで検索をすると下図のようにFunction Appの項目が出てくるのでそれを選択します。
![image](https://qiita-image-store.s3.amazonaws.com/0/28367/0c975afc-04f9-9cc9-9e3c-6aac4e72e24a.png)
作成は、普通のWeb Appsと同じ要領で名前とApp Serviceプランを設定します。
Function Appの場合は、App Serviceプランがクラシックと動的の2つから選ぶことができます。動的の場合は、実際にFunction Appが処理を実行した実行時間ベースでの課金になり、クラシックだと通常のApp Serviceプランと同じように扱えます。
![image](https://qiita-image-store.s3.amazonaws.com/0/28367/7b6ac935-255a-b378-2389-085da7bbccbd.png)

## テンプレートを作成する
Function Appのインスタンスが作成で来たら作成したインスタンスを選択します。
選択すると、Function App専用のダッシュボードに移動するので下図のように新しい関数 → 言語でPowerShellを選択します。
![image](https://qiita-image-store.s3.amazonaws.com/0/28367/a41091bf-284c-0ff1-1363-909893c515e5.png)
PowerShellを選択したら、今回は、Empty - PowerShellの項目を選択します。
選択すると、Function App名を入れるテキストボックスが出るので適当に選択して先に進みます。
![function01.png](https://qiita-image-store.s3.amazonaws.com/0/28367/ef7f70fa-f9ef-5948-4d6c-8440d9547be9.png)

すると、下記のような画面になります。
![image](https://qiita-image-store.s3.amazonaws.com/0/28367/dac57639-6a84-5d26-df0c-c604d7fc3ada.png)
この画面がエディタになっているので入力していきます。

## 簡単な実装をしてみる
まずは簡単な実装をしてみましょう。
Emptyのテンプレートだと最初の画面で下記のようなエラーが出ます。
![image](https://qiita-image-store.s3.amazonaws.com/0/28367/def58683-c7e5-b3d7-8833-725e6dc1279d.png)

これは、Functionを呼び出すトリガーが設定されていないために表示されるエラーです。
最初にトリガーを設定しましょう。
下図のように左メニューの統合から設定をします。
![image](https://qiita-image-store.s3.amazonaws.com/0/28367/b770a870-cd2d-0b74-5f0c-781581976454.png)
今回は、HTTPトリガーをトリガーに設定します。
トリガーを選択すると下図のようになります。
選択するといろいろ設定画面が出ますがとりあえずデフォルトで保存します。
![image](https://qiita-image-store.s3.amazonaws.com/0/28367/de3e23ef-7fc5-fa48-5335-267f9916cff1.png)
ここで設定する要求パラメーター名が、スクリプト内でリクエスト内容を格納するファイル的なものになります。
リクエストの内容を出力するコードは、下記の通りです。

```
Get-Content $req
```
でリクエストの内容を取得できます。
これは、Blobトリガーなども共通です。
テストは、エディタ下部の実行から行います。
![image](https://qiita-image-store.s3.amazonaws.com/0/28367/e84c04c7-9020-e55b-3574-f0c775a0cc41.png)
先ほどのコードでこれを実行するとhogeが出力されます。

## Blobをトリガーにしてみる
Httpリクエストで簡単な実装をしてみましたので、次にBlobを使ってみましょう。
Blobトリガーは、指定したBlobに変更が入ったら実行されるトリガーです。

とりあえずトリガーを下記のように設定します。
![image](https://qiita-image-store.s3.amazonaws.com/0/28367/d31a1a70-26aa-2933-c15f-46773d3791dc.png)

選択すると下図のような画面になるのでファイルのパスとストレージアカウントを設定します。
![image](https://qiita-image-store.s3.amazonaws.com/0/28367/ea860741-4bec-05d2-de2c-b34d521cb243.png)
パスは、コンテナ名/blob名で設定します。

### スクリプトを実装する
トリガーの設定ができたので簡単に実装してみます。
まずは、トリガーされたBlobが格納されるパスとBlobファイルの中身を表示してみます。

```
$myBlob
Get-Content $myBlob
```
トリガーになったBlobは、Blobパラメーター名で指定した名前と同名の変数に格納されています。先ほどのHttpトリガーのリクエストが格納されている場所と同じです。
基本的にこのパスは、

```
D:\local\Temp\Functions\Binding\{functionの実行時ID}\パラメーター名
```
になります。
これは、一時フォルダ扱いで、Functionが実行されるたびに毎回変更されます。

それでは、次にアーカイブファイルを扱ってみます。
下記のようなコードになります。

```
$CWD = "D:\local\Temp\Functions\Binding\" + $InvocationId + "\"
Add-Type -AssemblyName "System.IO.Compression.FileSystem"
$sourceZip = [System.IO.Compression.ZipFile]::Open($myBlob, "Update")
[System.IO.Compression.ZipFileExtensions]::ExtractToDirectory($sourceZip, "$CWD")
Get-ChildItem $CWD
```

最新のPowerShell v5では、アーカイブファイルを扱うための機能が追加されていますが、Azure Function(というかWeb Appsの乗っているマシン)のPowerShellは、v4なので.NETのライブラリを使ってアーカイブファイルを処理しています。

```
$InvocationId
```

には、アプリの実行時IDが格納されているので、

```
"D:\local\Temp\Functions\Binding\" + $InvocationId + "\"
```
で一時フォルダのフルパスを取得します。
Function Appは、スクリプトのパスを取得しようとすると、

```
D:\Windows\system32
```

を指してしまうので必ずパスを指定します。

## まとめ
PowerShellで基本的な実装をしてみました。
まだまだPowerShell版のFunction Appは、ほかの言語に比べて機能が少ないのでこれからという感じですが、大体のことはPowerShellでできるのでサクッと使い捨てのコードを書いたりするときに非常におすすめなのでぜひ使ってみてください。