Skip to main content

How to write to a custom field using the FileWave API

FrequentlyIt youis mightoften find it convenientdesirable to publish data back to aalter FileWave Custom Field,Field values, especially when it comes to driving automated workflows.

API Therecalls arehave somethe distinct advantagesadvantage toof this...especiallychanging inCustom thatField thevalues data change is made server-side immediatelydirectly on the APIserver, call.essentially making the change immediate.

In this article, we'll show you how to do this with a macOS shell script and with a Windows PowerShell script for boolean, string and date/timeWhere Custom Field values.values are Note:driving We'llSmart readGroup datadevice frominclusion, despite the API ascall making an immediate change, there will still be a smartperiod startingof block.time Being smart is always good.

We recommend only attempting to amend Custom Fields that will not be updated otherwise through other methods, Inventory for example.  'Administrator' Data Types arebefore the mostnext obviousSmart choice.

Group

The things we'll need to know to write a script:

  • FileWave server address
  • Base64 Encoded API token (from Assistants → Manage Administrators, and highly recommend a new admin account for this that has no rights assigned)
  • The Internal Name of the field you want to update
  • The type of Custom Field (string, boolean, integer, date/time)
  • The Device ID of the device you want to test with (in an actual script, FileWave can supply this automatically through a launch argument)
  • The URLs currently shown in this article use RESTful API (v1 API) so you will see 20445 used as a port. Simply add /api/ to the front of the /inv/api/ URL to make it. begin /api/inv/api/ and you can use 443 instead like the other APIs use. 

How to be Smart:

We can be smart by asking the API to show us data for Custom Fields we want to update.  So, we'll look at details for a specific device that has values set.  (Note this is a desktop client so we used /DesktopClient, but if a mobile device then it would be /MobileClient instead).  Elements in blue would need to be replaced with values for your environment. 

PlatformAPI CallPartial Result
macOS shellcurl -s -k -H "Authorization: base_64_token https://my.server.address:20445/inv/api/v1/client/details/device_id/DesktopClient | python -mjson.tool

Partial JSON Result
evaluation.

 

How

Partial

Writing JSONback Result

to
"CustomFields__school_type":a {Custom "updateTime":Field null,relies "value":upon "None",the "type":following "string"details:

},
    "CustomFields__user_role":
  • Server {URL
  • "updateTime":
  • A null,way "value":to "Student",recognise "type":which "string"device's },Custom "CustomFields__asset_tag":Field {should "updateTime":be "2020-07-28T18:47:20.604074Z",updated
  • "value":
  • A "FW-123456",way "type":to "string"recognise },the "CustomFields__phase_1":Custom {Field
  • "updateTime":
  • Custom null,Field "value":type
  • false,
  • An "type":authentication "bool"token
  • },
"CustomFields__image_date":

Some {Custom "updateTime":Fields "2020-07-28T19:15:34.568518Z",may "value":have "2019-05-28T15:15:09.672000Z",restricted "type":values.  "datetime"Only },one "CustomFields__school_name":of {these "updateTime":values "2020-07-28T19:15:34.571554Z",should "value":be "Deckardposted ES",in "type":the "string"API }

call to ensure expected behaviour.

 

Restricted

Windows PowerShellInvoke-RestMethod -Headers @{Authorization=('base_64_token')} "https://my.server.address:20445/inv/api/v1/client/details/device_id/DesktopClient" | ConvertTo-JSONValues

PartialValue JSONrestriction Result

may
be Partial JSON Result
"CustomFields__school_type": {
"updateTime": null,
"value": "None",
"type": "string"
},
"CustomFields__user_role": {
"updateTime": null,
"value": "Student",
"type": "string"
},
"CustomFields__asset_tag": {
"updateTime": "2020-07-28T18:47:20.604074Z",
"value": "FW-123456",
"type": "string"
},
"CustomFields__phase_1": {
"updateTime": null,
"value": false,
"type": "bool"
},
"CustomFields__image_date": {
"updateTime": "2020-07-28T19:15:34.568518Z",
"value": "2019-05-28T15:15:09.672000Z",
"type": "datetime"
},
"CustomFields__school_name": {
"updateTime": "2020-07-28T19:15:34.571554Z",
"value": "Deckard ES",
"type": "string"
}

 

As you can see, the results above are the sameobserved from the API regardless of calling platform and the data forwithin the Custom Field definition.

image.png

It is also possible to use Swagger (or therefore another API call) to return the 'choices' list of any Custom Field, by observing the Custom Field definition:

URL path for query:

/api/inv/api/v1/custom_field/

Query response:

  {
    "to_be_deleted": false,
    "field_name": "apple_battery_replace_2015",
    "display_name": "macOS Apple Battery Replace 2015",
    "data_type": "string",
    "provider": 0,
    "metadata": {},
    "description": "",
    "default_value": "Unchecked",
    "choices": [
      "Replaced",
      "Recall",
      "NA",
      "Serial",
      "Error",
      "Unchecked"
    ],
    "is_global": false,
    "used_in_inventory_queries": false,
    "used_in_smart_groups": false,
    "used_in_filesets": false,
    "used_in_license_definitions": false,
    "used_in_dep_profiles": false,
    "used_in_dep_rules": false,
    "used_in_workflows": false
  },

Which API

Custom Fields, as mentioned in the formother API KB documents, are best targeted with the Command Line RESTful API.

This example is demonstrating the possibility of antargeting array, so when we go to change it, we'll write it back that way as welldevices using theboth PATCHSerial commandNumber and anDevice arrayID.  data structure.

Changing Values:

The basicServer's methodFQDN, forAPI changingauthentication a value looks like this, where you would again substitute your valuestoken and environmentDevice info:

PlatformShell Script
macOS shell
curl -X PATCH \
  https://<server address>:20445/inv/api/v1/client/<device id> \
  -H 'authorization: <base64 token>' \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -d '{"CustomFields":{"field_name":{"exitCode":null,"status":0,"updateTime":"current_time","value":value_to_set}}}'
Windows PowerShell
Invoke-RestMethod -Method PATCH -Headers @{Authorization=<base_64_token>} `
 -Body '{"CustomFields":{"field_name":{"exitCode":null,"status":0,"updateTime":"current_time","value":value_to_set}}}' `
 -ContentType application/json `
 -Uri https://<server address>:20445/inv/api/v1/client/<device id>

Note, that in the above, "exitCode" and "status" are always required and a date value passed must always be in ISO-8601 format.  Also, it may seem like device_id is a challenge to set, because it would be different every time, but this is where the beauty of passing FileWave data elements in a script comes in.  If you simply pass %device_id% as a Launch Argument to your fileset script, then that valueID can be readsupplied dynamicallyas inLaunch yourArguments, however, for security reasons it is better to supply the token as an Environment variable.  When targeting Internal Names of Custom Fields (as either Launch Arguments or Environment Variables), surround the Internal Name with % symbols.

image.png

The start of a macOS script andmay substitutedlook with the specific Device ID of the current device.  See below, where %device_id% is read by the PowerShell script as $args[0].  In a mac shell script this same variable would be used as $1 in the script:like:

get_image_date.png
Windows$api = "https://" + $server + ":20445/inv/api/v1/client/" + $args[0]
macOShttps://$SERVER:20445/inv/api/v1/client/$1

Practical Examples (differing data types):

Using %device_id% as a  Launch Argument.

Field NameData TypePurpose/ActionmacOS Shell ScriptPowerShell Script
Asset TagStringSet device asset tag (a string field)...in this case to FW-198724Setting a string field (Bash)

Setting a string field (Bash)
#!/bin/zsh

SERVER=# Environment Variables
# $auth - base64 authentication token
# $device_id  - Device ID

server_fqdn=$(defaults read /usr/local/etc/fwcld.plist server) TOKEN=# FW Server FQDN
serial_number=$(ioreg -l -d 2 | awk -F "base_64_token"\"" DATE='/IOPlatformSerialNumber/ {print $(NF-1)}') # device serial number

It is of course possible that all of these values could be supplied to the script as Executable variables.

The start of a PowerShell script may look like:

# Environment Variables
# $Env:auth - base64 authentication token
# $Env:device_id - Device ID
# $Env:serial_number - device serial number
# $Env:server_fqdn - FW Server FQDN

Reading a Custom Field

It may be necessary to read the Custom Field during the script execution.  A JSON will be required for the data portion of the command:

{"criteria":
  {
    "column":"serial_number",
    "component":"Client",
    "operator":"is",
    "qualifier":'\"$serial_number\"'
  },
  "fields":
  [
    {
      "column":"apple_battery_replace_2015",
      "component":"CustomFields"
    }
  ],
  "main_component":"Client"
}

To continue the scripts, this could be assigned in the script as a variable

macOS script:

query='{"criteria":{"column":"serial_number","component":"Client","operator":"is","qualifier":'\"$serial_number\"'},"fields":[{"column":"apple_battery_replace_2015","component":"CustomFields"}],"main_component":"Client"}'

Windows PowerShell:

$query = '{"criteria":{"column":"serial_number","component":"Client","operator":"is","qualifier":"' + $serial_number + '"},"fields":[{"column":"apple_battery_replace_2015","component":"CustomFields"}],"main_component":"Client"}'

With the server details and JSON configured, it is now possible to read the value with a command:

macOS script:

curl -s -H "Authorization: $auth" https://$server_fqdn:20445/inv/api/v1/query_result/ --data $query -H "Content-Type: application/json"

The response may look something like:

{"offset":0,"fields":["CustomFields_apple_battery_replace_2015"],"values":[["Replaced"]],"filter_results":1,"total_results":1,"version":0}

Windows PowerShell script:

$header = @{Authorization=“$auth"}
$api = "https://" + $server_dns + ":20445/inv/api/v1/query_result/"

Invoke-RestMethod -Method GET -Headers $header -Uri $api

Due to this being a Custom Field designed for an Apple replacement programme, hopefully the response will look something like:

{"offset":0,"fields":["CustomFields_apple_battery_replace_2015"],"values":[["NA"]],"filter_results":1,"total_results":1,"version":0}
Handling JSON response

As noted earlier, since the response is also a JSON block, the desired information is somewhat buried within the response.  Windows PowerShell has tools to directly work with JSON and as such the desired item is more easily attainable.  

ConvertFrom-Json

ConvertTo-Json

macOS on the other hand, it would be beneficial to either instal Python and use Pythons tools to extract the response or get crazy with a tool like 'AWK'.

curl -s -H "Authorization: $auth" \
  https://$server_fqdn:20445/inv/api/v1/query_result/ \
  --data $query -H "Content-Type: application/json" \
  | awk -F  '[\\\[|\\\]]' '{gsub(/\"/,"",$0);print  substr( $(NF-2), 1, length($(NF-2)))}'

Response with AWK:

Replaced

Writing a Custom Field

Once the script has continued and actioned anything else desired, it then may be desirable to set the Custom Field to a new value, which may vary depending upon the outcome of the scripting.

In this example, we will consider the script will be writing back NA to the Custom Field:

current_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ"FT%TZ")
TAG="FW-198724"
DEVICE=$1
QUERY=data='{"CustomFields":{"asset_tag"apple_battery_replace_2015":{"exitCode":null,"status":0,"updateTime":"'$DATE'current_time'","value":"'$TAG'"NA"}}}'

curl -X PATCH https://$SERVER:server_fqdn:20445/inv/api/v1/client/$DEVICEdevice_id -Hd "authorization: $TOKEN" -H 'cache-control: no-cache'data" -H 'content-type: application/json'  -d $QUERY
 
exit 0
Setting string field (Powershell)

Setting a string field (Powershell)
$server = (Get-ItemProperty -Path REgistry::HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\FileWave\WinClient).server
$token = "base_64_token"
$api = "https://" + $server +  ":20445/inv/api/v1/client/" + $args[0]
$header = @{Authorization=$token}
$date = Get-Date -Format "o"
$tag = "FW-198724"
$data = '{"CustomFields":{"asset_tag":{"exitCode":null,"status":0,"updateTime":"' + $date + '","value":"' + $tag + '"}}}'
  
Invoke-RestMethod -Method PATCH -Headers $header -Body $data -ContentType application/json -Uri $api
Image DateDateWhen a device is newly imaged set this Custom Field to current date/time (again must be ISO-8601 format)Setting a date-type field (Bash)

Setting a date-type field (Bash)
#!/bin/zsh
SERVER=$(defaults read /usr/local/etc/fwcld.plist server)
TOKEN="base_64_token"
DATE=$(date -u +"%Y-%m-%d %H:%M:%S")
DEVICE=$1
QUERY='{"CustomFields":{"image_date":{"exitCode":null,"status":0,"updateTime":"'$DATE'","value":"'$DATE'"}}}'
 
curl -X PATCH https://$SERVER:20445/inv/api/v1/client/$DEVICEs -H '"authorization: '$TOKEN''auth_key"
-H 'cache-control: no-cache' -H 'content-type: application/json' -d $QUERY

Note:

Setting
  • This ais date-typenow fieldusing (Powershell)

    Setting a date-type field (Powershell)
    $server = (Get-ItemProperty -Path REgistry::HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\FileWave\WinClient).server
    $token = "base_64_token"
    $api = "https://" + $server +  ":20445/inv/api/v1/client/" + $args[0]
    $header = @{Authorization=$token}
    $date = Get-Date -Format "o"
    $data = '{"CustomFields":{"image_date":{"exitCode":null,"status":0,"updateTime":"' + $date + '","value":"' + $date + '"}}}'
     
    Invoke-RestMethod -Methodthe PATCH -Headersoption, $headersince -Bodyan $dataalready -ContentTypeexisting application/json -Uri $api
  • Phase 1BooleanSimple boolean field to indicate whether Phase 1value is enabledbeing (settingaltered to 1, which is True)Setting a boolean field (Bash)

    Setting a boolean field (Bash)
    #!/bin/zsh
    SERVER=$(defaults read /usr/local/etc/fwcld.plist server)
    TOKEN="base_64_token"
    DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
    FLAG=1
    DEVICE=$1
    QUERY='{"CustomFields":{"phase_1":{"exitCode":null,"status":0,"updateTime":"'$DATE'","value":"'$FLAG'"}}}'
     
    curl -X PATCH https://$SERVER:20445/inv/api/v1/client/$DEVICE -H 'authorization: '$TOKEN'' -H 'cache-control: no-cache' -H 'content-type: application/json' -d $QUERY
    Setting boolean field (PowerShell)

    Setting boolean field (PowerShell)
    $server = (Get-ItemProperty -Path REgistry::HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\FileWave\WinClient).server
    $token = "base_64_token"
    $api = "https://" + $server +  ":20445/inv/api/v1/client/" + $args[0]
    $header = @{Authorization=$token}
    $date = Get-Date -Format "o"
    $flag = 1
    $data = '{"CustomFields":{"phase_1":{"exitCode":null,"status":0,"updateTime":"' + $date + '","value":"' + $flag + '"}}}'
      
    Invoke-RestMethod -Method PATCH -Headers $header -Body $data -ContentType application/json -Uri $api

    SSL Certificate Problem

    Self-Signed certificates may produce an error around SSL Certificates.  Please act accordingly, based uponby the script output,

  • The date is being supplied as a variable to addressensure this.

    the current time is pushed back with the API JSON data
  • This command is referencing 'device_id' in the URL path