Add an IoT Edge Device on Windows with EFLOW
Azure IoT Edge for Linux on Windows (EFLOW) runs a lightweight, Microsoft-maintained Linux virtual machine directly on Windows. The IoT Edge runtime and the Datalogic Connect modules run inside that VM, unlike the Ubuntu setup where they run natively on the host.
The installation script install-iot-edge.ps1 prepares the Windows host and the EFLOW VM: it creates the Hyper-V external switch, installs EFLOW, deploys the VM with a static IP address, provisions IoT Edge and registers the auto-start task. No manual module configuration is required. Broker, storage, certificate and telemetry settings are delivered to the device by the Connect deployment manifest when the device is enrolled.
Prerequisites
Before you begin
-
Create an Edge Device in Device Visibility. The Serial Number you enter here becomes the Edge Device ID. The Device IP must be the static IP address you will assign to the EFLOW VM, because the ProvisioningModule issues the server certificate for that address.
-
Check the hardware requirements before deploying EFLOW. The CPU, RAM and disk you assign to the VM are reserved for it and are no longer available to Windows, so make sure the host has enough capacity for the VM and its other workloads.
-
Use Windows PowerShell as Administrator. The installation script requires PowerShell 5.1.
-
Log on with the local account that will remain on the machine. The
AzureEFLOWmodule only works from the account that deployed the VM, and theEFLOW Auto-Startself-repair task is registered under that account. -
Optional pre-check: verify that Hyper-V and hardware virtualization are available on the host. If Hyper-V is missing, the script can enable it and request a reboot.
-
Open the device's Overview page in Connect. From here you download the installation script and, if you need it, the credentials file.
Start with Authentication.
Provisioning values
The installer needs only the following three values. When you download the script from the device's Overview page, Connect embeds all three, so you normally do not have to supply them yourself.
| Value | Where it comes from | Where it is used |
|---|---|---|
| Scope ID | scope in the Get Credentials JSON export | DPS id_scope in /etc/aziot/config.toml |
| Primary Key | primaryKey in the Get Credentials JSON export | DPS symmetric_key in /etc/aziot/config.toml |
| Edge Device ID | The Serial Number you entered when creating the device. It is not part of the export. | DPS registration_id in /etc/aziot/config.toml |
Supported OS
| OS | Architecture | Status |
|---|---|---|
| Windows 11 | x86_64 | ✅ Verified |
| Windows 10 (version 1809, build 17763 or later) | x86_64 | ⚠️ Compatible, not tested |
| Windows Server 2025 | x86_64 | ✅ Verified |
| Windows Server 2022 | x86_64 | ⚠️ Compatible, not tested |
On Windows desktop editions, Hyper-V is not available in the Home edition. Use the Pro (recommended) or Enterprise edition. Windows Server supports Hyper-V through the Hyper-V server role.
ARM64 support is experimental in this EFLOW setup and has not been validated in our test matrix. Use it only for evaluation and verify compatibility in your own environment before production use.
Network requirements
The EFLOW VM must be able to reach the outbound endpoints listed under Cloud Endpoints and, for the install script, under Installation Endpoints.
If the host is behind a corporate firewall, allow all the outbound endpoints above. The IoT Edge runtime selects the best available upstream protocol, MQTT TLS on port 8883 or HTTPS on port 443. Field devices also need to reach the VM on the local network: see Add the inbound firewall rules and the full list in Network Requirements.
Quick install
The installation is automated and assigns the VM a static IP address.
1. Download the installation archive
Open the device's Overview page in Connect, click Install script and choose Windows. The archive contains install-iot-edge.ps1, its SHA-256 checksum and a README.
Extract the archive into a folder on the Windows host and verify the checksum:
$expected = ((Get-Content .\install-iot-edge.ps1.sha256 -TotalCount 1) -split "\s+")[0].ToLower()
$actual = (Get-FileHash .\install-iot-edge.ps1 -Algorithm SHA256).Hash.ToLower()
if ($actual -eq $expected) { "OK" } else { "Not OK" }
The command prints ok when the checksum matches. If it prints not ok, download the archive again.
2. Open Windows PowerShell as Administrator
Open Windows PowerShell as Administrator with the account described in Before you begin, then change to the folder that contains the script. The script will automatically set Windows PowerShell 5.1 version if it is not already in use.
3. Set the execution policy
The following setting applies to the current session only:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force
4. Run the installer
The script downloaded from Connect already contains the Scope ID, the Edge Device ID and the Primary Key of the device:
.\install-iot-edge.ps1 `
-EflowIp "<IP_ADDRESS>" `
-CpuCount <CPU_COUNT> `
-MemoryInMB <RAM_SIZE_IN_MB> `
-VmDataSize <DISK_SIZE_IN_GB>
Replace <IP_ADDRESS> with the actual Edge IP address.
For the virtual hardware values (<CPU_COUNT>, <RAM_SIZE_IN_MB> and <DISK_SIZE_IN_GB>) consult the hardware requirements.
Please, note that the EflowIp is not the Windows host IP address and must be different. Check before the installation that the IP address chosen to be the Edge one is available and reserved by your IT department.
You can also edit and configure network parameter available for the EFLOW virtual adapter, like so:
.\install-iot-edge.ps1 `
-EflowIp "192.168.1.50" `
-PrefixLength 24 `
-GatewayIp "192.168.1.1" `
-DnsServer @("192.168.1.1") `
-AdapterName "Ethernet" `
-CpuCount 2 `
-MemoryInMB 4096 `
-VmDataSize 50
The values above are for example only.
For more, consult the parameter table below.
Inside the VM, /var/srv is the only persistent path and /srv is a bind mount of it. The configuration phase creates the volume directories under /var/srv with the ownership below.
| UID | Directories | Used by |
|---|---|---|
1000 | redis, MqttTranslationModule/*, DeviceHubModule/*, StorageModule/log, ProvisioningModule/log, shared/download, edgeAgent, edgeHub, all under /var/srv | Gateway modules, Redis, edgeAgent and edgeHub storage |
1001 | /var/srv/shared/certs, /var/srv/shared/certs/server | Shared certificates, written by ProvisioningModule and read by nanomq |
The installation script creates the directories of the base edge gateway manifest. The Smart Vision manifest, which also needs the local blob storage directories, is not covered on EFLOW.
The configuration phase stops IoT Edge, removes the module containers and clears /var/srv inside the EFLOW VM before recreating the volume directories. It does not ask for confirmation. Do not run the script on a VM that holds data you need under that path.
Supplying the values yourself
If the script does not contain the provisioning values, for example because you obtained it from another source, you can supply them in two ways.
-
Credentials file next to the script. Download the Get Credentials JSON export from the device's Overview page, save it as
edge-credentials.jsonin the same folder as the script and pass the serial number with-DeviceId. The script detects the file and reads the Scope ID and the Primary Key from it. -
All three values on the command line. Pass
-ScopeId,-DeviceIdand-PrimaryKeytogether with the network parameters.
Any value not supplied is asked interactively. Command-line values take precedence over the credentials file, which takes precedence over the configuration saved by a previous run in C:\EFLOW\install-edge.env.
Parameter table
The installation script accepts the following parameters. Run Get-Help .\install-iot-edge.ps1 -Full to print the same list.
| Parameter | Mandatory | Description | Notes |
|---|---|---|---|
-Phase | ❌ | Phase to run: All, CreateSwitch, InstallEflow, DeployVm, ConfigureVm or SetupAutoStart | Default All. Use a single phase to repeat one step, for example -Phase SetupAutoStart. |
-CredentialsFile | ❌ | Path to the Get Credentials JSON export. Supplies the Scope ID and the Primary Key. | If omitted, edge-credentials.json next to the script is used. |
-ScopeId | ❌ | DPS ID Scope. | Overrides the value read from the credentials file. |
-DeviceId | ❌ | Edge Device ID, that is the Serial Number of the device. | Not part of the credentials export. -SerialNumber and -EdgeDeviceId are aliases. |
-PrimaryKey | ❌ | DPS symmetric primary key. | Overrides the value read from the credentials file. |
-AdapterName | ❌ | Name of the physical network adapter bound to the external switch. | If omitted, the script lists the active adapters and asks you to choose. |
-EflowIp | ✅ | Static IPv4 address of the EFLOW VM. | Must be in the same subnet as the gateway, unused, and equal to the Device IP set in Connect. |
-GatewayIp | ❌ | Default gateway IPv4 address. | Detected from the host if omitted. -Ip4GatewayAddress is an alias. |
-PrefixLength | ❌ | IPv4 subnet prefix length. | Range 1 to 32. Detected from the host if omitted. |
-DnsServer | ❌ | One or two DNS server IPv4 addresses. | Example: @("DNS_1", "DNS_2"). Uses the host DNS servers if omitted, then the gateway. |
-CpuCount | ❌ | Number of CPU cores assigned to the VM. | Range 1 to 8. Default 2. |
-MemoryInMB | ❌ | RAM assigned to the VM, in MB. | Range 2048 to 32768. Default 4096. |
-VmDataSize | ❌ | Size of the EFLOW VM data disk, in GB. | Range 16 to 200. Default 50. Can be expanded later. |
-ConfigFile | ❌ | Path to the configuration saved by a previous run. | Default C:\EFLOW\install-edge.env. Contains the network settings, the VM size and the provisioning values. |
-VmDataSize defines the EFLOW data disk quota, not the total VHDX capacity shown by Hyper-V. In Hyper-V, Get-VHD may report a larger Size, for example around 68 GB for -VmDataSize 50, because EFLOW adds its own system partitions. FileSize is the space currently consumed on the host disk, which is often lower than Size because the VHDX is dynamic.
5. Add the inbound firewall rules
The script does not change the Windows or Hyper-V firewall rules: the VM has its own static IP address on the external Hyper-V switch, so the rules below must be Hyper-V firewall rules, added before you enroll mobile devices with an enrollment token.
| Port | Service | Purpose |
|---|---|---|
8098 | ProvisioningModule | Device certificate provisioning |
9883 | MQTT over TLS | Authenticated mobile connection |
Without these rules the mobile device cannot reach the ProvisioningModule. Enrollment with an enrollment token fails, while enrollment without a token still succeeds on port 1883.
Run the following commands in Windows PowerShell as Administrator:
New-NetFirewallHyperVRule -Name 'DatalogicConnect-EFLOW-Provisioning-8098' -DisplayName 'Datalogic Connect EFLOW Provisioning (8098)' -Direction Inbound -Protocol TCP -LocalPorts 8098
New-NetFirewallHyperVRule -Name 'DatalogicConnect-EFLOW-MqttTls-9883' -DisplayName 'Datalogic Connect EFLOW MQTT TLS (9883)' -Direction Inbound -Protocol TCP -LocalPorts 9883
Verify the installation
After the enrollment, Connect applies the deployment manifest and the modules are pulled. Wait at least two minutes, then open a shell in the VM:
Connect-EflowVm
Inside the VM, list the IoT Edge modules:
sudo iotedge list
All modules should reach the running state:
NAME STATUS DESCRIPTION CONFIG
DeviceHubModule running Up 2 hours crsolinfraprodeuw.azurecr.io/device-hub-module:2.0.11-amd64.debug
MqttTranslationModule running Up 2 hours crsolinfraprodeuw.azurecr.io/mqtt-translation-module:1.0.0-amd64.debug
ProvisioningModule running Up 2 hours crsolinfraprodeuw.azurecr.io/provisioning-module:1.0.1-amd64.debug
StorageModule running Up 2 hours crsolinfraprodeuw.azurecr.io/storage-module:1.1.1-amd64.debug
edgeAgent running Up 2 hours crsolinfraprodeuw.azurecr.io/azureiotedge-agent:1.5.40
edgeHub running Up 2 hours crsolinfraprodeuw.azurecr.io/azureiotedge-hub:1.5.40
nanomq running Up 2 hours crsolinfraprodeuw.azurecr.io/nanomq:0.24.14-slim
otelcollector running Up 2 hours crsolinfraprodeuw.azurecr.io/opentelemetry-collector-contrib:0.155.0
redis running Up 2 hours crsolinfraprodeuw.azurecr.io/redis:8.8.0-alpine
The module set and the image tags come from the manifest selected as Active manifest when the device was created. The listing above belongs to the base edge gateway manifest.
If a module stays in failed or keeps restarting, inspect it:
sudo iotedge logs <module-name>
The installation log is available on the host at C:\EFLOW\logs\setup.log.
Resize the EFLOW VM disk
If you need more disk space after the initial deployment, for logs, container images or data, you can expand the VM disk.
Only expansion is supported. The disk cannot be shrunk. The VM must be stopped during the resize, so expect about 2 to 3 minutes of downtime.
-
On the host, stop the EFLOW VM:
Stop-EflowVm -
On the host, find the VHDX and resize it. Replace
<NEW_SIZE>with the target size, for example100GB:$vm = Get-VM -Name '*EFLOW*'$vhdx = ($vm.HardDrives | Where-Object { $_.Path -like '*EFLOW*.vhdx' }).PathResize-VHD -Path $vhdx -SizeBytes <NEW_SIZE> -
On the host, start the VM and open a shell in it:
Start-EflowVmConnect-EflowVm -
Inside the VM, expand the partition and the file system, then check the result:
sudo growpart /dev/sda 2sudo resize2fs /dev/sda2df -h /exit
Uninstall
The following commands undo what install-iot-edge.ps1 did: they remove the auto-start tasks, the EFLOW VM, the Azure IoT Edge installation, the working folder, the firewall rules and the Hyper-V switch. The Hyper-V role stays enabled. Run them in Windows PowerShell as Administrator, with the same account you used to install.
Step 2 deletes the EFLOW VM together with everything it holds, including the volume directories under /var/srv. Step 4 causes a brief network interruption on the host. The Edge Device in Connect is not affected: see step 5.
1. Remove the auto-start tasks
Do this first, otherwise the EFLOW Auto-Start task restarts the VM while you remove it.
Stop-ScheduledTask -TaskName 'EFLOW Auto-Start' -ErrorAction SilentlyContinue
Unregister-ScheduledTask -TaskName 'EFLOW Auto-Start' -Confirm:$false
Unregister-ScheduledTask -TaskName 'EFLOW-Rotate-Startup-Log' -Confirm:$false
2. Stop the EFLOW VM
Stop-EflowVm
3. Uninstall Azure IoT Edge and remove the leftover files
$code = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' | Where-Object DisplayName -like 'Azure IoT Edge*').PSChildName
(Start-Process msiexec.exe -ArgumentList "/x $code /qn /norestart" -Wait -PassThru).ExitCode
Remove-Item -Recurse -Force "$env:SystemDrive\EFLOW", "$env:ProgramFiles\Azure IoT Edge", "$env:TEMP\AzureIoTEdge.msi", "$env:TEMP\eflow-startup-fallback.log" -ErrorAction SilentlyContinue
Remove-EventLog -Source 'EFLOW Startup' -ErrorAction SilentlyContinue
Exit code 0 means the MSI is gone. Exit code 3010 means Windows Installer completes the removal, including the Azure IoT Edge folder, at the next reboot: reboot the host before you run the installer again. You can also uninstall Azure IoT Edge LTS from Settings > Apps instead of running the first two lines.
This will also delete the EFLOW VM.
4. Remove the firewall rules and the Hyper-V switch
Skip the last line if other VMs use vEflowSwitch.
Remove-NetFirewallHyperVRule -Name 'DatalogicConnect-EFLOW-Provisioning-8098' -ErrorAction SilentlyContinue
Remove-NetFirewallHyperVRule -Name 'DatalogicConnect-EFLOW-MqttTls-9883' -ErrorAction SilentlyContinue
Remove-VMSwitch -Name 'vEflowSwitch' -Force
5. Delete the device in Connect
The host is now clean, but the Edge Device still exists in the portal. If you are not going to reinstall it, delete it from the Device List.