Skip to content

Commit

Permalink
Merged PR 952120: Add security daemon installation script for Windows
Browse files Browse the repository at this point in the history
This adds a security daemon installation script for Windows devices which is designed to simplify the IoT Edge set-up process. This script automates the steps found [here](https://docs.microsoft.com/en-us/azure/iot-edge/how-to-install-iot-edge-windows-with-windows).

###Usage
* ```Install-SecurityDaemon.ps1 -Manual -DeviceConnectionString "<connection string>"```
* ```Install-SecurityDaemon.ps1 -Dps -ScopeId "<scope id>" -RegistrationId "<registration id>"```

### Validation
This script has been validated against the following:
* ```-Manual``` deployment on RS4 Windows 10 Desktop and IoT Core
* Validation of generated config.yaml and registry entries for DPS code path on RS4 IoT Core
  • Loading branch information
makroeze-msft committed Jul 11, 2018
1 parent 20143fa commit dea9cfc
Show file tree
Hide file tree
Showing 2 changed files with 312 additions and 0 deletions.
5 changes: 5 additions & 0 deletions scripts/windows/setup/Initialize-IotCoreDevice.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
& {

<#
# Installs the IoT Edge runtime on RS3 Windows.
#>

$ErrorActionPreference = "Stop"
Set-StrictMode -Version 5

Expand Down
307 changes: 307 additions & 0 deletions scripts/windows/setup/Install-SecurityDaemon.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,307 @@
<#
# Installs the IoT Edge Security Daemon on RS4 Windows.
#>

#requires -Version 5
#requires -RunAsAdministrator

[CmdletBinding()]
param (
[Parameter(ParameterSetName = "Manual")]
[Switch] $Manual,

[Parameter(ParameterSetName = "DPS")]
[Switch] $Dps,

[Parameter(Mandatory = $true, ParameterSetName = "Manual")]
[String] $DeviceConnectionString,

[Parameter(Mandatory = $true, ParameterSetName = "DPS")]
[String] $ScopeId,

[Parameter(Mandatory = $true, ParameterSetName = "DPS")]
[String] $RegistrationId
)

$ErrorActionPreference = "Stop"
Set-StrictMode -Version 5

function Install-SecurityDaemon {
if (-not (Test-IsDockerRunning) -or -not (Test-IsKernelValid)) {
Write-Host ("The prerequisites for installation of the IoT Edge Security daemon are not met. " +
"Please fix all known issues before rerunning this script.") `
-ForegroundColor "Red"
return
}

Get-SecurityDaemon
Set-Path
Get-VcRuntime
Initialize-IotEdgeService
Add-FirewallExceptions
Add-IotEdgeRegistryKey

Set-ProvisioningMode
Set-Hostname
Set-GatewayAddress
Set-MobyNetwork
Restart-IotEdgeService

Write-Host ("`nThis device is now provisioned with the IoT Edge runtime.`n" +
"Check the status of the IoT Edge service with `"Get-Service iotedge`"`n" +
"List running modules with `"iotedge list`"`n" +
"Display logs from the last five minutes in chronological order with`n" +
" Get-WinEvent -ea SilentlyContinue -FilterHashtable @{ProviderName=`"iotedged`";LogName=`"application`";StartTime=[datetime]::Now.AddMinutes(-5)} |`n" +
" Select TimeCreated, Message |`n" +
" Sort-Object @{Expression=`"TimeCreated`";Descending=`$false}") `
-ForegroundColor "Green"
}

function Test-IsDockerRunning {
if ((Get-Service "Docker").Status -eq "Running") {
Write-Host "Docker is running." -ForegroundColor "Green"
return $true
}
else {
Write-Host "Docker is not running." -ForegroundColor "Red"
if ((Get-Item "HKLM:\Software\Microsoft\Windows NT\CurrentVersion").GetValue("EditionID") -eq "IoTUAP") {
Write-Host ("Please visit https://docs.microsoft.com/en-us/azure/iot-edge/how-to-install-iot-core " +
"for assistance with installing Docker on IoT Core.") `
-ForegroundColor "Red"
}
else {
Write-Host ("You can use Docker for Windows for development and testing. " +
"Please visit https://www.docker.com/docker-windows for additional information.") `
-ForegroundColor "Red"
}
return $false
}
}

function Test-IsKernelValid {
$SupportedBuilds = @(17134)
$CurrentBuild = (Get-Item "HKLM:\Software\Microsoft\Windows NT\CurrentVersion").GetValue("CurrentBuild")
if ((Invoke-Native "docker info --format {{.Isolation}}" -Passthru) -match "hyperv") {
Write-Host "Hyper-V isolation is enabled." -ForegroundColor "Green"
return $true
}
else {
Write-Host "Process isolation is enabled." -ForegroundColor "Green"
if ($SupportedBuilds -contains $CurrentBuild) {
Write-Host "The container host is on supported build version $CurrentBuild." -ForegroundColor "Green"
return $true
}
else {
Write-Host ("The container host is on unsupported build version $CurrentBuild. " +
"Please use a container host with one of the following supported build versions:`n" +
($SupportedBuilds -join "`n")) `
-ForegroundColor "Red"
return $false
}
}
}

function Get-SecurityDaemon {
try {
Invoke-WebRequest `
-Uri "https://aka.ms/iotedged-windows-latest" `
-OutFile "$env:TEMP\iotedged-windows.zip" `
-UseBasicParsing
Expand-Archive "$env:TEMP\iotedged-windows.zip" "C:\ProgramData\iotedge" -Force
Copy-Item "C:\ProgramData\iotedge\iotedged-windows\*" "C:\ProgramData\iotedge" -Force
Write-Host "Downloaded security daemon." -ForegroundColor "Green"
}
finally {
Remove-Item "C:\ProgramData\iotedge\iotedged-windows" -Recurse -Force -ErrorAction "SilentlyContinue"
Remove-Item "$env:TEMP\iotedged-windows.zip" -Force -ErrorAction "SilentlyContinue"
}
}

function Set-Path {
if ($env:PATH -notlike "*C:\ProgramData\iotedge*") {
$env:PATH += ";C:\ProgramData\iotedge"
Invoke-Native "setx /M PATH `"$env:PATH`""
Write-Host "Updated system PATH." -ForegroundColor "Green"
}
else {
Write-Host "System PATH does not require an update." -ForegroundColor "Green"
}
}

function Get-VcRuntime {
if ((Get-Item "HKLM:\Software\Microsoft\Windows NT\CurrentVersion").GetValue("EditionID") -eq "IoTUAP") {
Write-Host "Skipped vcruntime download on IoT Core." -ForegroundColor "Green"
return
}

try {
Invoke-WebRequest `
-Uri "https://download.microsoft.com/download/0/6/4/064F84EA-D1DB-4EAA-9A5C-CC2F0FF6A638/vc_redist.x64.exe" `
-OutFile "$env:TEMP\vc_redist.exe" `
-UseBasicParsing
Invoke-Native "$env:TEMP\vc_redist.exe /quiet /norestart"
Write-Host "Downloaded vcruntime." -ForegroundColor "Green"
}
catch {
if ($LASTEXITCODE -eq 1638) {
Write-Host "Skipping vcruntime installation because a newer version is already installed." -ForegroundColor "Green"
}
else {
throw $_
}
}
finally {
Remove-Item "$env:TEMP\vc_redist.exe" -Force -Recurse -ErrorAction "SilentlyContinue"
}
}

function Initialize-IotEdgeService {
New-Service -Name "iotedge" -BinaryPathName "C:\ProgramData\iotedge\iotedged.exe -c C:\ProgramData\iotedge\config.yaml" | Out-Null
Start-Service iotedge
Write-Host "Initialized the IoT Edge service." -ForegroundColor "Green"
}

function Add-FirewallExceptions {
New-NetFirewallRule `
-DisplayName "iotedged allow inbound 15580,15581" `
-Direction "Inbound" `
-Action "Allow" `
-Protocol "TCP" `
-LocalPort "15580-15581" `
-Program "C:\programdata\iotedge\iotedged.exe" `
-InterfaceType "Any" | Out-Null
Write-Host "Added firewall exceptions for ports used by the IoT Edge service." -ForegroundColor "Green"
}

function Add-IotEdgeRegistryKey {
$RegistryContent = @(
"Windows Registry Editor Version 5.00",
"",
"[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application\iotedged]"
"`"CustomSource`"=dword:00000001"
"`"EventMessageFile`"=`"C:\\ProgramData\\iotedge\\iotedged.exe`""
"`"TypesSupported`"=dword:00000007")
try {
$RegistryContent | Set-Content "$env:TEMP\iotedge.reg" -Force
Invoke-Native "reg import $env:TEMP\iotedge.reg"
Write-Host "Added IoT Edge registry key." -ForegroundColor "Green"
}
finally {
Remove-Item "$env:TEMP\iotedge.reg" -Force -ErrorAction "SilentlyContinue"
}
}

function Set-ProvisioningMode {
$ConfigurationYaml = Get-Content "C:\ProgramData\iotedge\config.yaml" -Raw
if ($Manual) {
$SelectionRegex = "(?:[^\S\n]*#[^\S\n]*)?provisioning:\s*#?\s*source:\s*`".*`"\s*#?\s*device_connection_string:\s*`".*`""
$ReplacementContent = @(
"provisioning:",
" source: `"manual`"",
" device_connection_string: `"$DeviceConnectionString`"")
($ConfigurationYaml -replace $SelectionRegex, ($ReplacementContent -join "`n")) | Set-Content "C:\ProgramData\iotedge\config.yaml" -Force
Write-Host "Configured device for manual provisioning." -ForegroundColor "Green"
}
else {
$SelectionRegex = "(?:[^\S\n]*#[^\S\n]*)?provisioning:\s*#?\s*source:\s*`".*`"\s*#?\s*global_endpoint:\s*`".*`"\s*#?\s*scope_id:\s*`".*`"\s*#?\s*registration_id:\s`".*`""
$ReplacementContent = @(
"provisioning:",
" source: `"dps`"",
" global_endpoint: `"https://global.azure-devices-provisioning.net`"",
" scope_id: `"$ScopeId`"",
" registration_id: `"$RegistrationId`"")
$ConfigurationYaml = $ConfigurationYaml -replace $SelectionRegex, ($ReplacementContent -join "`n")

$SelectionRegex = "(?:[^\S\n]*#[^\S\n]*)?provisioning:\s*#?\s*source:\s*`".*`"\s*#?\s*device_connection_string:\s*`".*`""
$ReplacementContent = ""
($ConfigurationYaml -replace $SelectionRegex, ($ReplacementContent -join "`n")) | Set-Content "C:\ProgramData\iotedge\config.yaml" -Force

New-Item "HKLM:\SYSTEM\CurrentControlSet\Services\iotedge" -Force | Out-Null
New-ItemProperty `
-Path "HKLM:\SYSTEM\CurrentControlSet\Services\iotedge" `
-Name "Environment" `
-PropertyType "MultiString" `
-Value "IOTEDGE_USE_TPM_DEVICE=ON" `
-Force | Out-Null

Write-Host "Configured device for DPS provisioning." -ForegroundColor "Green"
}
}

function Set-Hostname {
$ConfigurationYaml = Get-Content "C:\ProgramData\iotedge\config.yaml" -Raw
$Hostname = (Invoke-Native "hostname" -Passthru).Trim()
$SelectionRegex = "hostname:\s*`".*`""
$ReplacementContent = "hostname: `"$Hostname`""
($ConfigurationYaml -replace $SelectionRegex, ($ReplacementContent -join "`n")) | Set-Content "C:\ProgramData\iotedge\config.yaml" -Force
Write-Host "Configured device with hostname `"$Hostname`"." -ForegroundColor "Green"
}

function Set-GatewayAddress {
$ConfigurationYaml = Get-Content "C:\ProgramData\iotedge\config.yaml" -Raw
$GatewayAddress = (Get-NetIpAddress |
Where-Object {$_.InterfaceAlias -like "*vEthernet (nat)*" -and $_.AddressFamily -like "IPv4"}).IPAddress

$SelectionRegex = "connect:\s*management_uri:\s*`".*`"\s*workload_uri:\s*`".*`""
$ReplacementContent = @(
"connect:",
" management_uri: `"http://${GatewayAddress}:15580`"",
" workload_uri: `"http://${GatewayAddress}:15581`"")
$ConfigurationYaml = $ConfigurationYaml -replace $SelectionRegex, ($ReplacementContent -join "`n")

$SelectionRegex = "listen:\s*management_uri:\s*`".*`"\s*workload_uri:\s*`".*`""
$ReplacementContent = @(
"listen:",
" management_uri: `"http://${GatewayAddress}:15580`"",
" workload_uri: `"http://${GatewayAddress}:15581`"")
$ConfigurationYaml = $ConfigurationYaml -replace $SelectionRegex, ($ReplacementContent -join "`n")

[Environment]::SetEnvironmentVariable("IOTEDGE_HOST", "http://${GatewayAddress}:15580")
Invoke-Native "setx /M IOTEDGE_HOST `"http://${GatewayAddress}:15580`""

$ConfigurationYaml | Set-Content "C:\ProgramData\iotedge\config.yaml" -Force
Write-Host "Configured device with gateway address `"$GatewayAddress`"." -ForegroundColor "Green"
}

function Set-MobyNetwork {
$ConfigurationYaml = Get-Content "C:\ProgramData\iotedge\config.yaml" -Raw
$SelectionRegex = "moby_runtime:\s*uri:\s*`".*`"\s*#?\s*network:\s*`".*`""
$ReplacementContent = @(
"moby_runtime:",
" docker_uri: `"npipe://./pipe/docker_engine`"",
" network: `"nat`"")
($ConfigurationYaml -replace $SelectionRegex, ($ReplacementContent -join "`n")) | Set-Content "C:\ProgramData\iotedge\config.yaml" -Force
Write-Host "Set the Moby runtime network to NAT." -ForegroundColor "Green"
}

function Restart-IotEdgeService {
Stop-Service iotedge -NoWait
Start-Sleep 5
Start-Service iotedge
}

function Invoke-Native {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[String] $Command,

[Switch] $Passthru
)

process {
Write-Verbose "Executing native Windows command '$Command'..."
$out = cmd /c "($Command) 2>&1" 2>&1 | Out-String
Write-Verbose $out
Write-Verbose "Exit code: $LASTEXITCODE"

if ($LASTEXITCODE) {
throw $out
}
elseif ($Passthru) {
$out
}
}
}

Install-SecurityDaemon

0 comments on commit dea9cfc

Please sign in to comment.