A set of scripts for creating an Azure IoT Hub and 10 devices. A simulator is generated for each device and runs locally. Cleanup scripts are included. The scripts were generated with help from GitHub Copilot. They are designed to run from a VS Code terminal on Windows. Azure IoT Explorer is used to verify the devices are created and running. The scripts are idempotent, so they can be rerun without error.

Tip: avoid hardcoded hub names by setting an environment variable once in PowerShell:

$IOTHUB_NAME = 'my-iot-hub-137'

Update 2026-07-11

The newer C# simulator scripts support a reusable environment variable (IOTHUB_NAME) so the hub name no longer has to be hardcoded in every script call.

.\1_QuickSetup\set_iothub_env.ps1 -HubName $IOTHUB_NAME -Scope User

After that, scripts can be run without -HubName, for example:

1_QuickSetup/7_create_resource_group_and_iot_hub_b1.ps1

Repository

Azure IoT Hub Fast Setup on GitHub:  djaus2/iothub-fast-setup

Scripts

The scripts as per sections (from section 7) from this post are on GitHub at djaus2/iothub-fast-setup/1_QuickSetup

Index of scripts from this post


About

Have previously created Powershell scripts to simplify creation of an IoT Hub and related devices.
See blog category iot/
This is a set of scripts authored with help from GitHub Copilot. The scripts are designed to run from a VS Code terminal on Windows. They create a resource group, an IoT Hub, and 10 devices. They then run 10 local device emulators and open the IoT Hub in Azure IoT Explorer.

Azure IoT Hub End-to-End Setup in VS Code (Windows)

This guide shows how to do the full workflow in VS Code terminal:

  • Create Resource Group: $IOT_RG
  • Create IoT Hub: $IOTHUB_NAME
  • Create 10 devices: device1 to device10
  • Run 10 local device emulators
  • Open and verify in Azure IoT Explorer

It also includes extension upgrade/repair steps for the issue you hit.

1. Prerequisites

  1. Install VS Code.
  2. Install Azure CLI (az).
  3. Sign in to Azure from terminal.
  4. Make sure you have an active subscription with permission to create resources.
  5. Install Azure IoT Explorer desktop app.

Notes:

  • You do not need a VS Code IoT extension for this workflow.
  • You do need the Azure CLI extension named azure-iot.

2. Open VS Code Terminal

In VS Code:

  1. Open your project folder.
  2. Open Terminal > New Terminal.
  3. Use PowerShell terminal on Windows.

3. Verify Azure CLI

Run:

az version

Expected:

  • azure-cli is installed
  • extensions may or may not include azure-iot yet

If Azure CLI is missing, install it first from Microsoft docs.

4. Sign In and Select Subscription

Run:

az login --use-device-code

If you have multiple tenants:

az login --tenant <tenant-id> --use-device-code

Set active subscription:

az account set --subscription <subscription-id>
az account show --query "{user:user.name, subscription:id, name:name}" -o json

5. Install Required Azure IoT CLI Extension

Install:

az extension add --name azure-iot --upgrade

Verify:

az extension list --query "[?name=='azure-iot'].{name:name,version:version}" -o table

6. Names and Azure Naming Rules

Requested names:

  • Resource Group: My-IoT-Grp-137
  • IoT Hub: My-IoT-Hub-137
  • Devices: device1 to device10

Important:

  • IoT Hub name must be globally unique.
  • IoT Hub name must be lowercase.

So use this hub name in commands: my-iot-hub-137

If already taken globally, append a suffix, for example: my-iot-hub-137-01

7. Create Resource Group and IoT Hub (S1)

Choose location (example: australiaeast), then run:

az group create -n $IOT_RG -l australiaeast
az iot hub create -g $IOT_RG -n $IOTHUB_NAME --sku S1 --partition-count 2

Verify hub:

az iot hub show -n $IOTHUB_NAME --query "{name:name,sku:sku.name,state:properties.state,hostname:properties.hostName}" -o json

8. Create 10 Devices

PowerShell loop:

for ($i=1; $i -le 10; $i++) {
  az iot hub device-identity create -n $IOTHUB_NAME -d ("device" + $i)
}

Idempotent version (safe if rerun):

for ($i=1; $i -le 10; $i++) {
  $d = "device$i"
  az iot hub device-identity show -n $IOTHUB_NAME -d $d --query deviceId -o tsv 1>$null 2>$null
  if ($LASTEXITCODE -ne 0) {
    az iot hub device-identity create -n $IOTHUB_NAME -d $d | Out-Null
  }
}

Verify:

az iot hub device-identity list -n $IOTHUB_NAME --query "[].deviceId" -o table

9. Get Device Connection Strings

PowerShell loop:

for ($i=1; $i -le 10; $i++) {
  $d = "device$i"
  $cs = az iot hub device-identity connection-string show -n $IOTHUB_NAME -d $d --query connectionString -o tsv
  Write-Output "$d`t$cs"
}

10. Get IoT Hub Connection String for IoT Explorer

Use service policy connection string (for hub management in IoT Explorer):

az iot hub connection-string show -n $IOTHUB_NAME --policy-name iothubowner --key primary --query connectionString -o tsv

11. Open in Azure IoT Explorer

  1. Open Azure IoT Explorer desktop app.
  2. Select Add connection.
  3. Choose IoT Hub.
  4. Paste the IoT Hub connection string from step 10.
  5. Connect.
  6. Open Devices and confirm Device-1 to Device-10 are visible.
  7. Open Devices and confirm device1 to device10 are visible.

12. Run 10 Local Device Emulators from VS Code

Start all 10 simulators as background PowerShell jobs:

Important: Keep line breaks, or add ; separators if pasting as one line.

$hub=$IOTHUB_NAME; 1..10 | ForEach-Object { $d = "device$_"; Start-Job -Name "iot-$d" -ScriptBlock { param($h,$device) az iot device simulate -n $h -d $device --msg-count 1000000 --msg-interval 5 --data "Ping from $device" --only-show-errors } -ArgumentList $hub,$d | Out-Null }; Get-Job -Name 'iot-device*' | Select-Object Name,State,PSBeginTime
Get-Job -Name 'iot-device*' | Select-Object Name,State,PSBeginTime

Copy-safe one-line version:

$hub=$IOTHUB_NAME; 1..10 | ForEach-Object { $d = "device$_"; Start-Job -Name "iot-$d" -ScriptBlock { param($h,$device) az iot device simulate -n $h -d $device --msg-count 1000000 --msg-interval 5 --data "Ping from $device" --only-show-errors } -ArgumentList $hub,$d | Out-Null }; Get-Job -Name 'iot-device*' | Select-Object Name,State,PSBeginTime

Stop all simulators:

$jobs = Get-Job | Where-Object { $_.Name -like 'iot-device*' }
if ($jobs) {
  $jobs | Stop-Job -ErrorAction SilentlyContinue
  $jobs | Remove-Job -Force -ErrorAction SilentlyContinue
  'Stopped/removed jobs: ' + ($jobs.Name -join ', ')
} else {
  'No matching iot emulator jobs found.'
}

13. Troubleshooting (Upgrade/Extension Issues)

Problem: azure-iot commands fail and mention extension update/copy errors

Symptoms can include:

  • FileExistsError in cliextensions\azure-iot
  • Access denied deleting old extension folders
  • Dynamic install repeatedly trying to upgrade and failing

Fix (Windows PowerShell):

az config set extension.use_dynamic_install=no
az extension remove --name azure-iot
$extPath = Join-Path $HOME ".azure\\cliextensions\\azure-iot"
if (Test-Path $extPath) {
  attrib -r "$extPath\\*" /s /d | Out-Null
  Remove-Item -LiteralPath $extPath -Recurse -Force -ErrorAction SilentlyContinue
}
az extension add --name azure-iot --upgrade
az extension show --name azure-iot --query "{name:name,version:version}" -o json

After repair, retry device commands.

Problem: Stop-Job says “A positional parameter cannot be found that accepts argument ‘Get-Job’”

Cause:

  • Two pipelines were typed on one line without a separator, so PowerShell treated Get-Job as an argument to Stop-Job.

Correct examples:

Get-Job -Name 'iot-device*' | Stop-Job; Get-Job -Name 'iot-device*' | Remove-Job

or

Get-Job -Name 'iot-device*' | Stop-Job
Get-Job -Name 'iot-device*' | Remove-Job

14. Common Gotchas

  1. IoT Hub name must be lowercase and globally unique.
  2. Device IDs are case-sensitive.
  3. IoT Explorer uses IoT Hub service connection string, not device connection strings.
  4. If login says no subscriptions found, verify tenant and subscription selection.
  5. If operations are denied, check RBAC permissions on the subscription/resource group.

15. Optional Cleanup

Delete only emulator jobs:

$jobs = Get-Job | Where-Object { $_.Name -like 'iot-device*' }
if ($jobs) {
  $jobs | Stop-Job -ErrorAction SilentlyContinue
  $jobs | Remove-Job -Force -ErrorAction SilentlyContinue
}

What it does:

  • Stops the running emulator jobs.
  • Removes those jobs from your PowerShell session.

What it does not do:

  • It does not uninstall Azure CLI or the azure-iot extension.
  • It does not delete IoT Hub device identities in Azure.

Quick check:

Get-Job -Name iot-device*

Delete all Azure resources in this lab:

az group delete -n $IOT_RG --yes --no-wait

Azure IoT Hub Explorer

Use Azure IoT Explorer to confirm your hub is reachable and your devices exist.

Install Azure IoT Explorer

  1. Download Azure IoT Explorer from the official Microsoft GitHub releases page: Azure-iot-explorer/releases
  2. Install it using the Windows installer.
  3. Launch Azure IoT Explorer from the Start menu.

Add Your IoT Hub

  1. In Azure IoT Explorer, select Add connection.
  2. Select IoT Hub.
  3. Get the IoT Hub service connection string as per Section 10 above.
  4. Paste the IoT Hub service connection string
  5. Select Connect.

Check Devices

  1. Open the Devices tab in Azure IoT Explorer.
  2. Confirm device1 through device10 are listed.
  3. Select one device and check status fields (for example, connection state and last activity time).
  4. If your simulators are running, refresh and confirm activity updates.

If Devices Are Missing

Run this command in VS Code terminal to verify device identities in the hub:

az iot hub device-identity list -n $IOTHUB_NAME --query "[].deviceId" -o table

16. Quick Command Checklist

Run in order:

# Need environment variables for hub name and resource group
# Run 1_QuickSetup\set_iothub_env.ps1 with a unique name for your IoT Hub.
# Resource Group gets generated from that.
if ([string]::IsNullOrWhiteSpace($IOTHUB_NAME) -or [string]::IsNullOrWhiteSpace($IOT_RG)) {
  throw "Required variables missing. Set non-empty values for IOTHUB_NAME and IOT_RG before running this checklist."
}
az version
az login --use-device-code
az account set --subscription <subscription-id>
az extension add --name azure-iot --upgrade
az group create -n $IOT_RG -l australiaeast
az iot hub create -g $IOT_RG -n $IOTHUB_NAME --sku B1 --partition-count 2
for ($i=1; $i -le 10; $i++) { az iot hub device-identity create -n $IOTHUB_NAME -d ("device" + $i) }
az iot hub connection-string show -n $IOTHUB_NAME --policy-name iothubowner --key primary --query connectionString -o tsv

Addendum: Terminal Scoping for Get-Job in VS Code

If this command returns nothing:

Get-Job -Name 'iot-device*' | Select-Object Name,State,PSBeginTime

it usually means the jobs were started in a different PowerShell session.

Key point:

  • Get-Job is session-scoped (per terminal process), not system-wide.
  • In VS Code, each terminal tab can be a separate PowerShell process.
  • So one terminal can have zero jobs, while simulators still run from another terminal.

Check jobs in the same terminal tab that started them:

Get-Job | Select-Object Id,Name,State,PSBeginTime,PSEndTime

Check simulator processes system-wide (ps-style view):

Get-CimInstance Win32_Process |
  Where-Object { $_.CommandLine -match 'az iot device simulate|azure.cli|az\.cmd' } |
  Select-Object ProcessId,Name,CreationDate,CommandLine

If the original job session is open, stop cleanly from that session:

Get-Job -Name 'iot-device*' | Stop-Job
Get-Job -Name 'iot-device*' | Remove-Job

If the original session is gone, stop by process match (system-wide):

Get-CimInstance Win32_Process |
  Where-Object { $_.CommandLine -match 'az iot device simulate|azure.cli' } |
  ForEach-Object { Stop-Process -Id $_.ProcessId -Force }

Tip:

  • To avoid this confusion, keep emulator jobs and job management commands in one dedicated terminal tab.

Next: Some device code


 TopicSubtopic
  Next: > IoT Hub
<  Prev:   GitHub
   
 This Category Links 
Category:IoT Index:IoT