-
Notifications
You must be signed in to change notification settings - Fork 462
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merged PR 952120: Add security daemon installation script for Windows
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
1 parent
20143fa
commit dea9cfc
Showing
2 changed files
with
312 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |