Marcel
Marcel That's me: Marcel

Creating devices for Azure IoT Hub with SAS token automatically

Creating devices for Azure IoT Hub with SAS token automatically

A few weeks ago, I started an IoT project with a company responsible for a huge amount of different buildings around the world. We deployed several virtual and physical sensors in Azure IoT Hub. Doing this we had three challenges:

  • Deploy new IoT devices in Azure IoT hub in a batch
  • Generate SAS tokens for these IoT devices
  • Generate SAS tokens even if a device still exist in Azure IoT Hub

The requirement of batch processing avoids the use of the Device Explorer to generate SAS token. Therefore, I wrote a short PowerShell script:

function New-SASToken
{
PARAM(
[Parameter(Mandatory=$True)]
[string]$ResourceUri,
[Parameter(Mandatory=$True)]
[string]$Key,
[string]$KeyName="",
[int]$TokenTimeOut=1800 # in seconds
)
[Reflection.Assembly]::LoadWithPartialName("System.Web")| out-null
$Expires=([DateTimeOffset]::Now.ToUnixTimeSeconds())+$TokenTimeOut
#Building Token
$SignatureString=[System.Web.HttpUtility]::UrlEncode($ResourceUri)+ "`n" + [string]$Expires
$HMAC = New-Object System.Security.Cryptography.HMACSHA256
$HMAC.key = [Convert]::FromBase64String($Key)
$Signature = $HMAC.ComputeHash([Text.Encoding]::ASCII.GetBytes($SignatureString))
$Signature = [Convert]::ToBase64String($Signature)
$SASToken = "SharedAccessSignature sr=" + [System.Web.HttpUtility]::UrlEncode($ResourceUri) + "&sig=" + [System.Web.HttpUtility]::UrlEncode($Signature) + "&se=" + $Expires
if ($KeyName -ne"")
{
$SASToken=$SASToken+"&skn=$KeyName"
}
return $SASToken
}
function New-IoTDevice
{
PARAM(
[Parameter(Mandatory=$True)]
[string]$IoTHubConnectionString,
[Parameter(Mandatory=$True)]
[string]$DeviceId
)
[Reflection.Assembly]::LoadWithPartialName("System.Web")| out-null
$strings=$IoTHubConnectionString.split(";")
$keys =@{}
for ($i=0; $i -lt $strings.count; $i++)
{
$keys[$strings[$i].split("=")[0]]=$strings[$i].split("=")[1]
}
$keys["SharedAccessKey"]=$keys["SharedAccessKey"]+"="
$body='{deviceId:"'+$DeviceId+'"}'
try
{
$webRequest=Invoke-WebRequest -Method PUT -Uri "https://$($keys["HostName"])/devices/$([System.Web.HttpUtility]::UrlEncode($DeviceId))?api-version=2018-06-30" -ContentType "application/json" -Header @{ Authorization = (New-SASToken -ResourceUri $keys["HostName"] -Key $keys["SharedAccessKey"] -KeyName $keys["SharedAccessKeyName"])} -Body $body -UseBasicParsing
} catch [System.Net.WebException]
{
if ($_.Exception.Response.StatusCode.value__ -eq 409)
{
write-host "Device exists. Getting data from IoT hub"
$webRequest=Invoke-WebRequest -Method GET -Uri "https://$($keys["HostName"])/devices/$([System.Web.HttpUtility]::UrlEncode($DeviceId))?api-version=2018-06-30" -ContentType "application/json" -Header @{ Authorization = (New-SASToken -ResourceUri $keys["HostName"] -Key $keys["SharedAccessKey"] -KeyName $keys["SharedAccessKeyName"])} -UseBasicParsing
}
else
{
Write-Error "An exception was caught: $($_.Exception.Message)"
}
}
return ConvertFrom-Json $webRequest.Content
}
function Send-IoTDeviceTestString
{
PARAM(
[Parameter(Mandatory=$True)]
[string]$sasToken
)
[Reflection.Assembly]::LoadWithPartialName("System.Web")| out-null
$t1=[System.Web.HttpUtility]::UrlDecode($sasToken)
$t2=$t1.Split("=")
$t3=$t2[1].Split("&")[0]
$deviceId=$t3.Split("/")[2]
$iotHubDeviceHost=$t3

$iotHubRestURI = "https://$($iotHubDeviceHost)/messages/events?api-version=2018-04-01"
#$iotHubRestURI
$Headers = @{"Authorization" = $sasToken; "Content-Type" = "application/json"}
# Message Payload
$datetime = get-date
$body = @{
datetime = $datetime
deviceId = $deviceId
Message = "Sending data to iot hub"
}
$body = $body | ConvertTo-Json
return Invoke-RestMethod -Uri $iotHubRestURI -Headers $Headers -Method Post -Body $body
}

#
$iotHubName = "Workshop-IoT" # host name of the iot hub
$iotManagementConnectionString="HostName=Workshop-IoT.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # insert the connection string of your iot hub

# name of the new devices
$array = @(
"TestDev1",
"SEPAGO_HBS2.0_DE_Cologne_HQ_VDEV_ISP08-IO0",
"SEPAGO_HBS2.0_DE_Cologne_HQ_VDEV_ISP08-RTU"
)

foreach ($deviceId in $array){
Write-Host "New device created: $($deviceId)"
$device=New-IoTDevice -IoTHubConnectionString $iotManagementConnectionString -DeviceId $deviceId
$sasToken=New-SASToken -ResourceUri "$($iotHubName).azure-devices.net/devices/$([System.Web.HttpUtility]::UrlEncode($device.deviceId))" -Key $device.authentication.symmetricKey.primaryKey

write-host "DeviceId:",$device.deviceId
write-host "SASToken:",$sasToken
$deviceConfig
Send-IoTDeviceTestString -sasToken $sasToken
write-host("--------------------------")
}

Feel free to use it in your projects.

Feedback welcome

img

First published on: https://www.sepago.de/blog/creating-devices-for-azure-iot-hub-with-sas-token-automatically/