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