Skip to content

Commit

Permalink
More Windows installer changes (#592)
Browse files Browse the repository at this point in the history
- Add new `-InvokeWebRequestParameters` parameter. This can be used to specify
  extra options for all `Invoke-WebRequest` calls, like `-Proxy` and
  `-ProxyCredentials`. The `-Proxy` parameter to the installer function itself
  is left for backward-compatibility.

- Add new `-OfflineInstallationPath` parameter for offline installs.
  This should be set to a directory that contains one or more files.
  For each component that the installer downloads (iotedged, Moby Engine,
  Moby CLI, VC Runtime), it first checks if the corresponding file is already
  present in this directory. If the file is there, it uses that instead of
  downloading from the internet.

- Change Moby CLI from opt-in to opt-out. `-WithMobyCli` is renamed to
  `-SkipMobyCli`

- Disable iotedge service before stopping it. If the service crashes while
  being stopped, Windows restarts it instead of leaving it stopped.

- Skip VC Runtime installation if `system32\vcruntime140.dll` exists.

- Change all references to "Moby Runtime" to "Moby Engine", except for the
  key in `config.yaml`

Fixes #565
  • Loading branch information
arsing authored Dec 3, 2018
1 parent 86de05e commit 8cec3d5
Showing 1 changed file with 123 additions and 58 deletions.
181 changes: 123 additions & 58 deletions scripts/windows/setup/IotEdgeSecurityDaemon.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,13 @@ function Install-SecurityDaemon {

[ContainerOs] $ContainerOs = 'Linux',

# Proxy URI
# Proxy URI used for all Invoke-WebRequest calls. To specify other proxy-related options like -ProxyCredential, see -InvokeWebRequestParameters
[Uri] $Proxy,

# Local path to iotedged zip file
[String] $ArchivePath,
# If set to a directory, the installer prefers to use iotedged zip, moby Engine zip, moby CLI zip and VC Runtime MSI files from inside this directory
# over downloading them from the internet. Thus placing all four files in this directory can be used to have a completely offline install,
# or a specific subset can be placed to override the online versions of those specific components.
[String] $OfflineInstallationPath,

# IoT Edge Agent image to pull
[String] $AgentImage,
Expand All @@ -68,13 +70,32 @@ function Install-SecurityDaemon {
# Password to pull IoT Edge Agent image
[SecureString] $Password,

# Also install the Moby CLI (docker.exe) to $MobyInstallDirectory. Only takes affect for `-ContainerOs Windows`
[Switch] $WithMobyCli
# Splatted into every Invoke-WebRequest invocation. Can be used to set extra options.
#
# If -Proxy is also specified, it overrides the `-Proxy` key set in this hashtable, if any.
#
# Example:
# Install-SecurityDaemon -InvokeWebRequestParameters @{ '-Proxy' = 'http://localhost:8888'; '-ProxyCredential' = (Get-Credential).GetNetworkCredential() }
[HashTable] $InvokeWebRequestParameters,

# Don't install the Moby CLI (docker.exe) to $MobyInstallDirectory. Only takes effect for `-ContainerOs Windows`
[Switch] $SkipMobyCli,

# Local path to iotedged zip file. Only kept for backward compatibility. Prefer to set -OfflineInstallationPath instead.
[String] $ArchivePath
)

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

if ($InvokeWebRequestParameters -eq $null) {
$InvokeWebRequestParameters = @{}
}

if ($Proxy -ne $null) {
$InvokeWebRequestParameters['-Proxy'] = $Proxy
}

if (Test-EdgeAlreadyInstalled) {
Write-HostRed
Write-HostRed 'IoT Edge is already installed. To reinstall, run `Uninstall-SecurityDaemon` first.'
Expand All @@ -83,7 +104,7 @@ function Install-SecurityDaemon {

if (Test-MobyAlreadyInstalled) {
Write-HostRed
Write-HostRed 'IoT Edge Moby Runtime is already installed. To reinstall, run `Uninstall-SecurityDaemon` first.'
Write-HostRed 'IoT Edge Moby Engine is already installed. To reinstall, run `Uninstall-SecurityDaemon` first.'
return
}

Expand Down Expand Up @@ -155,7 +176,7 @@ function Install-SecurityDaemon {
if ($ContainerOs -eq 'Linux') {
Set-GatewayAddress
}
Set-MobyRuntimeParameters
Set-MobyEngineParameters

# Register services
Set-SystemPath
Expand Down Expand Up @@ -311,60 +332,64 @@ function Get-ExternalDockerServerOs {

function Get-SecurityDaemon {
try {
# If we create the iotedge archive ourselves, then delete it when we're done
# If we create these archives ourselves, then delete them when we're done
$deleteMobyEngineArchive = $false
$deleteMobyCliArchive = $false
$deleteEdgeArchive = $false

$mobyRuntimeArchivePath = "$env:TEMP\iotedge-moby-runtime.zip"
$mobyCliArchivePath = "$env:TEMP\iotedge-moby-cli.zip"

if ($ContainerOs -eq 'Windows') {
# Get moby runtime

Write-Host 'Downloading the latest version of Moby runtime...'
New-Item -Type Directory $MobyInstallDirectory | Out-Null
Remove-BuiltinWritePermissions $MobyInstallDirectory
Invoke-WebRequest `
-Uri 'https://aka.ms/iotedge-moby-engine-win-amd64-latest' `
-OutFile $mobyRuntimeArchivePath `
-UseBasicParsing `
-Proxy $Proxy
Write-HostGreen 'Downloaded Moby runtime.'
Expand-Archive $mobyRuntimeArchivePath $MobyInstallDirectory -Force
$mobyEngineArchivePath =
Download-File `
-Description 'Moby Engine' `
-Url 'https://aka.ms/iotedge-moby-engine-win-amd64-latest' `
-DownloadFilename 'iotedge-moby-engine.zip' `
-LocalCacheGlob '*moby-engine*.zip' `
-Delete ([ref] $deleteMobyEngineArchive)
Expand-Archive $mobyEngineArchivePath $MobyInstallDirectory -Force

New-Item -Type Directory $MobyDataRootDirectory | Out-Null
Remove-BuiltinWritePermissions $MobyDataRootDirectory

if ($WithMobyCli) {
Write-Host 'Downloading the latest version of Moby CLI...'
Invoke-WebRequest `
-Uri 'https://aka.ms/iotedge-moby-cli-win-amd64-latest' `
-OutFile $mobyCliArchivePath `
-UseBasicParsing `
-Proxy $Proxy
Write-HostGreen 'Downloaded Moby CLI.'

if (-not ($SkipMobyCli)) {
$mobyCliArchivePath =
Download-File `
-Description 'Moby CLI' `
-Url 'https://aka.ms/iotedge-moby-cli-win-amd64-latest' `
-DownloadFilename 'iotedge-moby-cli.zip' `
-LocalCacheGlob '*moby-cli*.zip' `
-Delete ([ref] $deleteMobyCliArchive)
Expand-Archive $mobyCliArchivePath $MobyInstallDirectory -Force
}
}

if (-not "$ArchivePath") {
$ArchivePath = "$env:TEMP\iotedged-windows.zip"
$deleteEdgeArchive = $true
Write-Host 'Downloading the latest version of IoT Edge security daemon...'
Invoke-WebRequest `
-Uri 'https://aka.ms/iotedged-windows-latest' `
-OutFile $ArchivePath `
-UseBasicParsing `
-Proxy $Proxy
Write-HostGreen 'Downloaded security daemon.'
# Historically the `-ArchivePath` parameter pointed to the zip / directory of iotedged.
# This is now better handled through `-OfflineInstallationPath`, but `-ArchivePath` is still allowed
# for backward compatibility.
if ($ArchivePath -ne '') {
$edgeArchivePath = $ArchivePath
$deleteEdgeArchive = $false
}
if ((Get-Item $ArchivePath).PSIsContainer) {
else {
# The -LocalCacheGlob value here *intentionally* doesn't check for .zip extension,
# so that an expanded directory of the same name will match
$edgeArchivePath =
Download-File `
-Description 'IoT Edge security daemon' `
-Url 'https://aka.ms/iotedged-windows-latest' `
-DownloadFilename 'iotedged-windows.zip' `
-LocalCacheGlob '*iotedged-windows*' `
-Delete ([ref] $deleteEdgeArchive)
}

if ((Get-Item $edgeArchivePath).PSIsContainer) {
New-Item -Type Directory $EdgeInstallDirectory | Out-Null
Copy-Item "$ArchivePath\*" $EdgeInstallDirectory -Force
Copy-Item "$edgeArchivePath\*" $EdgeInstallDirectory -Force
}
else {
New-Item -Type Directory $EdgeInstallDirectory | Out-Null
Expand-Archive $ArchivePath $EdgeInstallDirectory -Force
Expand-Archive $edgeArchivePath $EdgeInstallDirectory -Force
Copy-Item "$EdgeInstallDirectory\iotedged-windows\*" $EdgeInstallDirectory -Force -Recurse
}

Expand Down Expand Up @@ -419,11 +444,16 @@ function Get-SecurityDaemon {
Remove-Item "$EdgeInstallDirectory\iotedged-windows" -Recurse -Force -ErrorAction SilentlyContinue

if ($deleteEdgeArchive) {
Remove-Item $ArchivePath -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item $edgeArchivePath -Recurse -Force -ErrorAction SilentlyContinue
}

if ($deleteMobyEngineArchive) {
Remove-Item $mobyEngineArchivePath -Recurse -Force -ErrorAction SilentlyContinue
}

Remove-Item $mobyRuntimeArchivePath -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item $mobyCliArchivePath -Recurse -Force -ErrorAction SilentlyContinue
if ($deleteMobyCliArchive) {
Remove-Item $mobyCliArchivePath -Recurse -Force -ErrorAction SilentlyContinue
}
}
}

Expand Down Expand Up @@ -572,30 +602,41 @@ function Reset-SystemPath {

function Get-VcRuntime {
if (Test-IotCore) {
Write-HostGreen 'Skipped vcruntime download on IoT Core.'
Write-HostGreen 'Skipping VC Runtime installation on IoT Core.'
return
}

if (Test-Path 'C:\Windows\System32\vcruntime140.dll') {
Write-HostGreen 'Skipping VC Runtime installation because it is already installed.'
return
}

$deleteVcRuntimeArchive = $false

try {
Write-Host 'Downloading vcruntime...'
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 `
-Proxy $Proxy
Invoke-Native """$env:TEMP\vc_redist.exe"" /quiet /norestart"
Write-HostGreen 'Downloaded vcruntime.'
$vcRuntimeArchivePath =
Download-File `
-Description 'VC Runtime installer' `
-Url 'https://download.microsoft.com/download/0/6/4/064F84EA-D1DB-4EAA-9A5C-CC2F0FF6A638/vc_redist.x64.exe' `
-DownloadFilename 'vc_redist.x64.exe' `
-LocalCacheGlob '*vc_redist*.exe' `
-Delete ([ref] $deleteVcRuntimeArchive)

Invoke-Native """$vcRuntimeArchivePath"" /quiet /norestart"
Write-HostGreen 'Installed VC Runtime.'
}
catch {
if ($LASTEXITCODE -eq 1638) {
Write-HostGreen 'Skipping vcruntime installation because a newer version is already installed.'
Write-HostGreen 'Skipping VC Runtime installation because a newer version is already installed.'
}
else {
throw $_
}
}
finally {
Remove-Item "$env:TEMP\vc_redist.exe" -Force -Recurse -ErrorAction SilentlyContinue
if ($deleteVcRuntimeArchive) {
Remove-Item $vcRuntimeArchivePath -Recurse -Force -ErrorAction SilentlyContinue
}
}
}

Expand Down Expand Up @@ -624,6 +665,7 @@ function Install-Services {

function Uninstall-Services {
if (Get-Service $EdgeServiceName -ErrorAction SilentlyContinue) {
Set-Service -StartupType Disabled $EdgeServiceName -ErrorAction SilentlyContinue
Stop-Service -NoWait -ErrorAction SilentlyContinue -ErrorVariable cmdErr $EdgeServiceName
if ($?) {
Start-Sleep -Seconds 7
Expand Down Expand Up @@ -763,7 +805,7 @@ function Set-GatewayAddress {
Write-HostGreen "Configured device with gateway address '$gatewayAddress'."
}

function Set-MobyRuntimeParameters {
function Set-MobyEngineParameters {
$configurationYaml = Get-Content "$EdgeInstallDirectory\config.yaml" -Raw
$selectionRegex = 'moby_runtime:\s*uri:\s*".*"\s*#?\s*network:\s*".*"'
$replacementContentWindows = @(
Expand Down Expand Up @@ -886,5 +928,28 @@ function Remove-BuiltinWritePermissions([string] $Path) {
Set-Acl -Path $Path -AclObject $acl
}

function Download-File([string] $Description, [string] $Url, [string] $DownloadFilename, [string] $LocalCacheGlob, [ref] $Delete) {
if (($OfflineInstallationPath -ne '') -and (Test-Path "$OfflineInstallationPath\$LocalCacheGlob")) {
$result = (Get-Item "$OfflineInstallationPath\$LocalCacheGlob" | Select-Object -First 1).FullName

$Delete.Value = $false
}
else {
Write-Host "Downloading $Description..."

Invoke-WebRequest `
-Uri $Url `
-OutFile "$env:TEMP\$DownloadFileName" `
-UseBasicParsing `
@InvokeWebRequestParameters

$Delete.Value = $true
$result = "$env:TEMP\$DownloadFileName"
}

Write-HostGreen "Using $Description from $result"
return $result
}

Export-ModuleMember -Function Install-SecurityDaemon, Uninstall-SecurityDaemon
}

0 comments on commit 8cec3d5

Please sign in to comment.