The CSV command allows you to utilize a CSV file and create multiple instances of Node.js to perform the same operation iterating through the CSV file.

The text inside the ~~ should correspond with the headers in the CSV file. Be aware that the headers are case sensative.

sam csv "path/to/csv/file.csv" - hardware patch byid ~~id~~ --notes ~~notes~~

This will not solve all of the issues that the script below solves since there are other tasks being performed but will allow for a much faster execution.

You can control the number of instances that will be created when using the csv command by adjusting your api_throttle. The api_throttle sets the upper limit of the number of spawned instances that can be active at one time.

# Max of 30 instances may be created at one time. Default is 120.
sam config profile update byname "profileName" --api_throttle 30

If you have spaces in the heading then you will need to surround the field in quotes.

sam csv "path/to/csv/file.csv" - hardware patch byid ~~id~~ --name "~~Asset Name~~" --notes ~~notes~~

ALTERNATIVE: You can utilize a script to iterate through a CSV file and make the changes. See below for an example. This process is very slow and may take a very long time to complete. It would be far faster to peform the script actions and save them into a new CSV file that would be used like the examples above.

# Linux/macOS
# This will iterate through the entire CSV file, excluding the heading row, and attempt to
# update the hardware by the ID



# Replace heading1 heading2, etc. with the names that you prefer or that make more sense to you.
# You must include ALL headings or this will fail since the last heading you reference will
# contain the remaining.
# It is recommended to surround most heading variables in quotes in case there are any spaces
# in the CSV.
sed 1d $CSV | while IFS=, read -r heading1 heading2 heading3
  sam hardware patch byid $heading1 --name "$heading2" --expected_checking "$heading3"

A real world example for Linux/macOS. In this scenario we are going to use GAM to download all of our relevant Google Chromebook data that I want to update in our Snipe-IT instance. Since this is largely going to be using the custom fields you may want to read Snipe-IT: Custom Fields for more information because each instance will be different.

Since we are using the patch method we will not pollute our history of the device since changes are only made if there is an actual difference (ie. change, addition, or removal).


# This requires setup and installation before you are able to utilize it.
# If you have some other way of monitoring devices and gathering data that
# provides some sort of export then you can adjust this as needed.
gam print cros fields deviceId,status,annotatedAssetId,osVersion,macAddress,orgUnitPath,systemRamTotal,autoUpdateExpiration > ~/Desktop/chromebooks.csv


# The command "sed 1d $CSV" remove the first line from the file to avoid errors since
# they are just the headers. If you CSV file does not have headers then you will want
# to exclude the "sed" command.
sed 1d $CSV | while IFS=, read -r deviceId status assetTag osVersion macAddress orgUnit systemRamtotal autoUpdateExpire
  # The MAC address needs to be adjusted to be formatted correctly for Snipe-IT preset
  # MAC address regex.
  # I can't take credit for this conversion but I don't recall where I found it at this point.
  # This will split the file and automatically insert the ":" appropriately
  macFormatted=$(echo $macAddress | sed -e 's/\([0-9A-Fa-f]\{2\}\)/\1:/g' -e 's/\(.*\):$/\1/')

  # I placed a regex on our custom field for our RAM so that all are in the format of
  # regex:/^[0-9]* [A-Z]{2}$/
  ramInMB="$(($systemRamtotal / 1000000)) MB" # ie. 4000 MB

  # Be aware that this is not being rounded to the nearest thousandth so if the RAM calculates
  # to 3999 it will be 3 GB.
  # ramInGB="$(($systemRamtotal / 1000000000)) GB" # 4 GB

  # Since we don't have a the ID that corresponds with our Snipe-IT instance we will need
  # to use the annotatedAssetId, which in this case is the same as our asset tag.
  # We will query only the ID field and then parse it out to be used below.
  assetId=$(sam hardware get bytag $assetTag --fields id | cut -d' ' -f2)

  # Now we can actually perform the updates...
  # The order of the options does not matter, I just wanted to place them numerically.
  # The "&" at the end is important because it allows the command to be run in the background
  # allowing the script to continue without waiting for this response.
  sam hardware patch byid $assetId \
    --_snipeit_mac_address_1 "$macFormatted" \
    --_snipeit_auto_update_policy_5 "$autoUpdateExpire" \
    --_snipeit_chrome_device_id_12 "$deviceId" \
    --_snipeit_os_version_13 "$osVersion" \
    --_snipeit_chrome_status_14 "$status" \
    --_snipeit_ram_15 "$ramInMB" &

  # If you are utilizing a self hosted version of Snipe-IT then you may run into a
  # throttling issue. A solution has not been implemented to handle this at this time
  # but there are plans to implement such a feature in the future. Please see
  # https://snipe-it.readme.io/reference#api-throttling. If this is the case
  # then you may want to uncomment the sleep command below.
  #sleep 0.2 # This should be enough of a delay to prevent going over the throttling limit.