PowershellでやるSmartHRでのAPI操作

# 目的、背景など
最近になって職場で総務部主導でSmartHRが導入されました。それに伴い既存システム間の連携といった情報処理を依頼されます。その情報処理の一環でAPIの調査を担当しております。開発ベンダーなどは専用のツールでAPIの送受信の確認を行っているんじゃないかと思うんですが、私はPowershellのInvoke-WebRequestにて主に調査を行っています。
記憶が確かなら、コマンドさえ間違っていなければ標準のPowershellの環境で気楽に実行できるので重宝しています。
その際に使用するAPIコマンドラインを備忘録・非常用に記載しようと思います。
SmartHR APIの調査の手助けになればと思い投稿に至りました。

# 作業環境
・OS：Windows10 64bit
・Powershellバージョン：PSVersion 5.1.19041.1320

# SmartHR APIリファレンス
https://developer.smarthr.jp/api/index.html#!

# 諸変数の格納
API実行に必要なヘッダー情報を前もって投入します。一度投入すればPowershellを閉じるまで有効です。
アクセストークンやサブドメインはSmartHRで管理者権限を持っていれば、作成が可能です。（詳しくはSmartHRの公式で）

```powershell
$ACCESS_TOKEN = "********************************************"
$SUB_DOMAIN = "******"
$headers = @{}
$headers["Authorization"] = "Bearer ${ACCESS_TOKEN}"
$headers["Content-Type"] = "application/json"
```


# 従業員リスト１名分取得
社員番号が **0001** の方の情報を取得します。
Invoke-WebRequestは-METHODを指定していない場合、GETリクエストになります。
-Verboseオプションを入れると以下のようなデバッグ情報が出力されます。
```詳細: GET https://amaze.smarthr.jp/api/v1/crews?emp_code=0001 with 0-byte payload```
```詳細: received -1-byte response of content type application/json;charset=utf-8```

```powershell
$bodys = @{}
$bodys["emp_code"] = "0001" ## 社員番号
$URI="https://${SUB_DOMAIN}.smarthr.jp/api/v1/crews"
$RESPONSE = Invoke-WebRequest -Uri $URI -Headers $headers -Body $bodys -UseBasicParsing -Verbose
$RES_HEADERS = $RESPONSE.headers #System.Management.Automation.PSCustomObject
$RES_CONTENT = $RESPONSE.content | ConvertFrom-Json
$RES_HEADERS
$RES_CONTENT
```

# 登録されている全従業員のリスト取得
１ページの最大表示数が１００件までなので、ページ数分だけAPIを実行します。
以下のコマンド実行直後であれば、クリップボードにCSVデータとしてメモ帳などに貼り付けができます。
```powershell
$page_num = 1
$per_page_num = 1 ##１ページ当たりの表示件数
$pager = "page=${page_num}&per_page=${per_page_num}"
$URI = "https://${SUB_DOMAIN}.smarthr.jp/api/v1/crews?${pager}"
$RESPONSE = Invoke-WebRequest -Uri $URI -Headers $headers -Body $bodys -UseBasicParsing -Verbose
$RES_HEADERS = $RESPONSE.headers
 
$bodys = @{}
$per_page_num = 100 ##１ページ当たりの表示件数
$forx = [math]::Ceiling($RES_HEADERS."x-total-count" / $per_page_num) ## x-total-countから最大ページ数を取得
$emp_list = @()
for($page_num = 1 ; $page_num -lt $forx + 1 ; $page_num++) {
    $pager = "page=${page_num}&per_page=${per_page_num}"
    $URI = "https://${SUB_DOMAIN}.smarthr.jp/api/v1/crews?${pager}"
    $RESPONSE = Invoke-WebRequest -Uri $URI -Headers $headers -Body $bodys -UseBasicParsing -Verbose
    $RES_CONTENT = $RESPONSE.content | ConvertFrom-Json
    $emp_list += $RES_CONTENT
}

## クリップボードに貼り付け
$emp_list | Sort-Object "emp_code" | ConvertTo-Csv -NoTypeInformation | clip
## Powershell標準のグリッドビュー表示
$emp_list | Sort-Object "emp_code" | Out-GridView
```

# 登録されているアカウントのリスト取得
2023/11/24時点で、SmartHRではアカウントの種別がメールアドレスアカウントと社員番号アカウントというものがあります。
自分のメールアドレスを持っていない従業員などは社員番号アカウントを発行してSmartHRを使用することになります。
Web上の管理画面だと別々に表示されますが、APIだと一つの一覧として取得されます。
しかし、この一覧からだとその人がメールアカウントなのか社員番号アカウントなのか区別がつきませんのでご注意を。
また、ややこしいのが従業員情報のidとアカウントのidは別物であり、アカウント情報に含まれるcrew_idは従業員情報のidであるなど、こちらも注意が必要です。
```powershell
$page_num = 1
$per_page_num = 1 ##１ページ当たりの表示件数
$pager = "page=${page_num}&per_page=${per_page_num}"
$URI="https://amaze.smarthr.jp/api/v1/users?${pager}"
$RESPONSE = Invoke-WebRequest -Uri $URI -Headers $headers -Body $bodys -UseBasicParsing -Verbose
$RES_HEADERS = $RESPONSE.headers
$bodys = @{}
$per_page_num = 100 ##１ページ当たりの表示件数
$forx = [math]::Ceiling($RES_HEADERS."x-total-count" / $per_page_num)
$user_list = @()
for($page_num = 1 ; $page_num -lt $forx + 1 ; $page_num++) {
    $pager = "page=${page_num}&per_page=${per_page_num}"
    $URI="https://amaze.smarthr.jp/api/v1/users?${pager}"
    $RESPONSE = Invoke-WebRequest -Uri $URI -Headers $headers -Body $bodys -UseBasicParsing -Verbose
    $RES_CONTENT = $RESPONSE.content | ConvertFrom-Json
    $user_list += $RES_CONTENT
}

## クリップボードに貼り付け
$user_list | Sort-Object "id" | ConvertTo-Csv -NoTypeInformation | clip
## Powershell標準のグリッドビュー表示
$user_list | Sort-Object "id" | Out-GridView
```

# カスタム従業員項目の取得
p1,p2,p3というのはpositionのpです。ソート用に表示させています。

```powershell
## カスタム従業員項目の項目数取得 ##
$bodys = @{}
$page_num = 1 ##１ページ目を表示 ##
$per_page_num = 100 ##１ページ当たりの表示件数 ##
$pager = "page=${page_num}&per_page=${per_page_num}"
$URI = "https://${SUB_DOMAIN}.smarthr.jp/api/v1/crew_custom_field_templates?${pager}"
$RESPONSE = Invoke-WebRequest -Uri $URI -Headers $headers -Body $bodys -UseBasicParsing -Verbose
$RES_HEADERS = $RESPONSE.headers #System.Management.Automation.PSCustomObject

$forx = [math]::Ceiling($RES_HEADERS."x-total-count" / $per_page_num)
$cus_info = @()
for($page_num = 1 ; $page_num -lt $forx + 1 ; $page_num++) {
    $pager = "page=${page_num}&per_page=${per_page_num}"
    $URI = "https://${SUB_DOMAIN}.smarthr.jp/api/v1/crew_custom_field_templates?${pager}"
    $RESPONSE = Invoke-WebRequest -Uri $URI -Headers $headers -Body $bodys -UseBasicParsing -Verbose
    $RES_CONTENT = $RESPONSE.content | ConvertFrom-Json
    $cus_info += $RES_CONTENT ## カスタム従業員項目を格納 ##
}
$cus_info.Count

## カスタム従業員項目グループの取得 ##
$bodys = @{}
$page_num = 1 ##１ページ目を表示 ##
$per_page_num = 100 ##１ページ当たりの表示件数 ##
$pager = "page=${page_num}&per_page=${per_page_num}"
$bodys = @{}
$URI="https://${SUB_DOMAIN}.smarthr.jp/api/v1/crew_custom_field_template_groups?${pager}"
$RESPONSE = Invoke-WebRequest -Uri $URI -Headers $headers -Body $bodys -UseBasicParsing -Verbose
$RES_HEADERS = $RESPONSE.headers #System.Management.Automation.PSCustomObject
$RES_CONTENT = $RESPONSE.content | ConvertFrom-Json
$group_info = @()
$group_info = $RES_CONTENT | Sort-Object position
$group_info | Select-Object id ,name | Format-Table

## カスタム従業員項目 CSV作成 ##
$cus_list = @()
$posi_info = @("p1","p2","p3")
$id_info = @("group_id","field_id","list_id")
$field_info = @("group_name","field_name","type","list_name","list_phy_name","hint","scale","separated_by_commas","updated_at","created_at")
$other_info = @("csv_upload_name")
foreach($gro in $group_info){
    ## 行作成 NULL ##
    $cus_line = New-Object PSObject | Select-Object ($posi_info + $id_info + $field_info + $other_info)

    ## グループ情報取得 ##
    $cus_line.p1 = $gro.position
    $cus_line.group_id = $gro.id
    $cus_line.group_name = $gro.name
    $cus_list += $cus_line

    $cus_info2 = $cus_info | Where-Object { $_.group_id -eq $gro.id }
    foreach($cus in $cus_info2){
        ## 行作成 NULL ##
        $cus_line = New-Object PSObject | Select-Object ($posi_info + $id_info + $field_info + $other_info)

        $cus_line.p1 = $gro.position
        $cus_line.group_id = $gro.id
        $cus_line.group_name = $gro.name

        ## カスタム項目取得 ##
        $cus_line.p2 = $cus.position
        $cus_line.field_id = $cus.id
        $cus_line.field_name = $cus.name
        $cus_line.type = $cus.type
        $cus_line.hint = $cus.hint
        $cus_line.scale = $cus.scale
        $cus_line.separated_by_commas = $cus.separated_by_commas
        $cus_line.updated_at = $cus.updated_at
        $cus_line.created_at = $cus.created_at
        $cus_line.csv_upload_name = $gro.name + "." + $cus.name
        $cus_list += $cus_line

        ## リスト項目取得 ##
        foreach($ele in $cus.elements){
            $cus_line = New-Object PSObject | Select-Object ($posi_info + $id_info + $field_info + $other_info)
            $cus_line.p1 = $gro.position
            $cus_line.group_id = $gro.id
            $cus_line.group_name = $gro.name
            $cus_line.p2 = $cus.position
            $cus_line.field_id = $cus.id
            $cus_line.field_name = $cus.name
            $cus_line.p3 = $ele.position
            $cus_line.list_id = $ele.id
            $cus_line.list_name = $ele.name
            $cus_line.list_phy_name = $ele.physical_name
            $cus_list += $cus_line
        }
    }
}

## クリップボードに貼り付け
$cus_list | Sort-Object p1,p2,p3 | ConvertTo-Csv -NoTypeInformation | clip
## Powershell標準のグリッドビュー表示
$cus_list | Sort-Object p1,p2,p3 | Out-GridView

```

# POSTメソッド送信サンプル
給与明細を例にPOSTメソッドを記述します。
指定のpayroll_idのcrew_idに対し、登録・更新を行います。
```$bodys["values"] += @{"key" = "明細項目"; "value" = "123"}```を追記すれば登録項目を増やせます。
また、```$bodys = [Text.Encoding]::UTF8.GetBytes($bodys)```がないとPOSTメソッドで送った日本語などの全角文字が文字化けします。
（参考記事：https://feeld-uni.com/?p=2554）
```powershell
$bodys = @{}
$bodys["crew_id"] = "************************************"
$bodys["memo"]    = "【API】給与明細登録テスト"
$bodys["values"] = @()
$bodys["values"] += @{"key" = "基本給"; "value" = "10"}
$bodys["values"] += @{"key" = "残有休"; "value" = "20"}
$bodys["values"] += @{"key" = "市県民税"; "value" = "30"}
$bodys = $bodys | ConvertTo-Json
$bodys
$bodys = [Text.Encoding]::UTF8.GetBytes($bodys) ## この一行がないと全角文字が文字化けする
$payroll_id = "************************************"
$URI="https://${SUB_DOMAIN}.smarthr.jp/api/v1/payrolls/${payroll_id}/payslips"
$RESPONSE = Invoke-WebRequest -Uri $URI -Headers $headers -Body $bodys -Method POST -UseBasicParsing -Verbose
$RES_CONTENT = $RESPONSE.content | ConvertFrom-Json
$RES_CONTENT
```

# おわり
以上でございます。
SmartHRに限らずPowershellでAPI調査を行いたい方などもこの記事が何かの手助けになればと思います。

・Powershell　Invoke-WebRequest　API
・Powershell　Invoke-WebRequest　API　POST　文字化け
・SmartHR　API