Rest API Explorerを用いて、レコードから情報を取得したい場合

### 想定
ServiceNow内部だけで業務が完結せず、外部からcurl/shellなどを叩いて、レコードの状態を確認したい場合を想定して(例えば、ST環境と本番環境の設定差分をチェックしたい場合)、調べたことを書きおく。

### ServiceNow内部で完結する場合(基本形)
Rest API Exploer(system web service > rest api explorer)のtable APIを活用する。
![Screenshot 2021-08-06 00.39.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/e5f41f23-eabe-9396-740b-6f283427e4ab.png)

table api では細かくノーコードで設定値やクエリを設定できる。
例)incidentテーブルのレコード、field条件(Number/Description/State)を取得するケース
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/31eb092d-fe5c-68dc-170f-40a3c8376301.png)
実行結果は下記
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/4e166041-1ead-706a-3676-d78925d5f8a4.png)

中段ボタンでスクリプトを自動生成してくれる機能がある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/cdc5a2d2-f834-1e51-9681-2b50bc89e047.png)

[powershellの例]

```powershell:auto_produce.ps1
#Eg. User name="admin", Password="admin" for this code sample.
$user = "admin"
$pass = "admin"

#Build auth header
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user, $pass)))

# Set proper headers
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Authorization',('Basic {0}' -f $base64AuthInfo))
$headers.Add('Accept','application/json')


# Specify endpoint uri
$uri = "https://devxxxx.service-now.com/api/now/table/incident?sysparm_fields=number%2Cdescription%2Cstate&sysparm_limit=1"

# Specify HTTP method
$method = "get"

# Send HTTP request
$response = Invoke-RestMethod -Headers $headers -Method $method -Uri $uri 

# Print response
$response.RawContent
```


### endpoint urlの構造

```
"https://devxxxx.service-now.com/api/now/table/incident?sysparm_fields=number%2Cdescription%2Cstate&sysparm_limit=1"
```


- base_url...https://devxxxx.service-now.com
- table_api.../api/now/table
- table...incident
- target_field...?sysparm_fields=number%2Cdescription%2Cstate&
- option...&sysparm_limit=1

の構造になる。上記の組み立てをGUI上で簡単にしてくれることがrest api explorerのメリット。しかしこれは完全ではなく、取得できないテーブル(sys_properties)の存在や、他環境だと書き換えが必要だったりもするので、今回はpowershellで組み立てる。

### powershell 


```powershell:get_incident_record.ps1
Param (
    [parameter(mandatory)][string]$mfa
)

$conf_file = "config.json"
$conf = Get-Content $conf_file | ConvertFrom-Json
$user = $conf.userid
$pass = $conf.password + $mfa

$base = $conf.target_url
$restapi = 'api/now/table'
$table = "incident"
$query = "?sysparm_fields=number%2Cdescription%2Cstate&"

$url = $base + $restapi + $table + query
$secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($user, $secpasswd)

Invoke-RestMethod $url -Credential -o datafile.txt
```
設定ファイルは外部ファイル化して読み込む形にする。

```json:config.json
{
  "target_url" : "http;//(あなたのインスタンス).servicenow.com",
  "userid" : "(あなたのユーザーID)",
  "password" : "(あなたのパスワード)"
}

```
### REST認証におけるMFA対応
REST認証では、パスワードだけを送信するのではなく、パスワード＋リアルタイム6桁のコードを送信する必要がある。 例えば アカウントのパスワードが「Pass123」で、現時点での6桁の認証コードが「987654」の場合、パスワードとして「Pass123987654」を送信する。
なので、今回のコードの以下部分はそちらに対応している。

```
Param (
    [parameter(mandatory)][string]$mfa
)
...
$pass = $conf.password + $mfa
```