Skip to content

Commit

Permalink
Move Windows eventlog messages file into new standalone DLL. (#487)
Browse files Browse the repository at this point in the history
The Windows EventLog service opens the MessageFile when any process is viewing
events, such as when running `Get-WinEvent` in PS or using the Event Viewer MMC
snap-in. Before this change, the service would open `iotedged.exe`, which
in turn would prevent `Uninstall-SecurityDaemon` from deleting it and break
uninstall / reinstall / upgrade scenarios.

This change moves the message resource into a new standalone DLL
`iotedged_eventlog_messages.dll` that is installed into a separate
`ProgramData` directory.

Failing to remove this DLL in the uninstaller and failing to overwrite it in
the installer are not considered fatal errors. This is because the message IDs
don't change frequently, so a stale message file from a previous install causes
little or no harm.
  • Loading branch information
arsing authored Oct 29, 2018
1 parent 0a6a871 commit a135bdf
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 29 deletions.
8 changes: 7 additions & 1 deletion edgelet/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions edgelet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ members = [
"hyper-named-pipe",
"iotedge",
"iotedged",
"iotedged-eventlog-messages",
"iothubservice",
"management",
"provisioning",
Expand Down
12 changes: 12 additions & 0 deletions edgelet/iotedged-eventlog-messages/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "iotedged-eventlog-messages"
version = "0.1.0"
authors = ["Azure IoT Edge Devs"]
publish = false

[lib]
crate-type = ["cdylib"]

[target.'cfg(windows)'.build-dependencies]
version-compare = "0.0.6"
winreg = "0.5.1"
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (c) Microsoft. All rights reserved.

#[cfg(windows)]
extern crate version_compare;
#[cfg(windows)]
Expand All @@ -11,14 +12,12 @@ fn main() {

#[cfg(windows)]
mod windows {
use std::cmp::Ordering;
use std::env;
use std::fs;
use std::io::Result;
use std::path::{Path, PathBuf};
use std::process::Command;

use version_compare::comp_op::CompOp;
use version_compare::VersionCompare;
use winreg::enums::*;
use winreg::RegKey;
Expand Down Expand Up @@ -67,20 +66,12 @@ mod windows {
let max_version = installed_roots
.enum_keys()
.map(|v| v.unwrap())
.max_by(|v1, v2| comp_op_to_ordering(VersionCompare::compare(v1, v2).unwrap()))
.max_by(|v1, v2| VersionCompare::compare(v1, v2).unwrap().ord().unwrap())
.unwrap();

let kits_root: String = installed_roots.get_value("KitsRoot10").unwrap();
let install_root = Path::new(&kits_root);

Ok(install_root.join("bin").join(max_version).join("x64"))
}

fn comp_op_to_ordering(op: CompOp) -> Ordering {
match op {
CompOp::Eq | CompOp::Le | CompOp::Ge => Ordering::Equal,
CompOp::Lt | CompOp::Ne => Ordering::Less,
CompOp::Gt => Ordering::Greater,
}
}
}
1 change: 1 addition & 0 deletions edgelet/iotedged-eventlog-messages/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Copyright (c) Microsoft. All rights reserved.
4 changes: 0 additions & 4 deletions edgelet/iotedged/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,3 @@ win-logger = { path = "../win-logger" }
tempdir = "0.3.7"

edgelet-test-utils = { path = "../edgelet-test-utils" }

[target.'cfg(windows)'.build-dependencies]
winreg = "0.5.1"
version-compare = "0.0.6"
88 changes: 75 additions & 13 deletions scripts/windows/setup/IotEdgeSecurityDaemon.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ function Install-SecurityDaemon {
return
}

Get-SecurityDaemon
$usesSeparateDllForEventLogMessages = Get-SecurityDaemon
Set-SystemPath
Get-VcRuntime
Add-FirewallExceptions
Add-IotEdgeRegistryKey
Add-IotEdgeRegistryKey -UsesSeparateDllForEventLogMessages:$usesSeparateDllForEventLogMessages

Set-ProvisioningMode
Set-AgentImage
Expand Down Expand Up @@ -238,10 +238,52 @@ function Get-SecurityDaemon {
Copy-Item "$ArchivePath\*" "C:\ProgramData\iotedge" -Force
}
else {
Invoke-Native "mkdir C:\ProgramData\iotedge"
New-Item -Type Directory 'C:\ProgramData\iotedge' | Out-Null
Expand-Archive "$ArchivePath" "C:\ProgramData\iotedge" -Force
Copy-Item "C:\ProgramData\iotedge\iotedged-windows\*" "C:\ProgramData\iotedge" -Force
}

if (Test-Path 'C:\ProgramData\iotedge\iotedged_eventlog_messages.dll') {
# This release uses iotedged_eventlog_messages.dll as the eventlog message file

New-Item -Type Directory 'C:\ProgramData\iotedge-eventlog' -ErrorAction SilentlyContinue -ErrorVariable CmdErr | Out-Null
if ($? -or ($CmdErr.FullyQualifiedErrorId -eq 'DirectoryExist,Microsoft.PowerShell.Commands.NewItemCommand')) {
Move-Item `
'C:\ProgramData\iotedge\iotedged_eventlog_messages.dll' `
'C:\ProgramData\iotedge-eventlog\iotedged_eventlog_messages.dll' `
-Force -ErrorAction SilentlyContinue -ErrorVariable CmdErr
if ($?) {
# Copied eventlog messages DLL successfully
}
elseif (
($CmdErr.Exception -is [System.IO.IOException]) -and
($CmdErr.Exception.HResult -eq 0x800700b7) # HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)
) {
# ERROR_ALREADY_EXISTS despite Move-Item -Force likely means the DLL is held open by something,
# probably the Windows EventLog service or some other process.
#
# It's not really a problem to have an old DLL from a previous installation lying around, since the message IDs
# and format strings haven't changed. Even if they have changed, it just means some logs in the event log will
# not display correcty.
#
# Don't bother warning the user about it.
}
else {
throw $CmdErr
}
}
else {
throw $CmdErr
}

$usesSeparateDllForEventLogMessages = $true
}
else {
# This release uses iotedged.exe as the eventlog message file
$usesSeparateDllForEventLogMessages = $false
}

return $usesSeparateDllForEventLogMessages
}
finally {
Remove-Item "C:\ProgramData\iotedge\iotedged-windows" -Recurse -Force -ErrorAction "SilentlyContinue"
Expand All @@ -259,18 +301,32 @@ function Remove-SecurityDaemonResources {
Write-Verbose "$(if ($?) { "Deleted registry key '$LogKey'" } else { $CmdErr })"

$EdgePath = "C:\ProgramData\iotedge"
$EdgeEventLogMessagesPath = "C:\ProgramData\iotedge-eventlog"

Remove-Item -Recurse $EdgePath -ErrorAction SilentlyContinue -ErrorVariable CmdErr
if ($?) {
Write-Verbose "Deleted install directory '$EdgePath'"
}
else {
elseif ($CmdErr.FullyQualifiedErrorId -ne "PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand") {
Write-Verbose "$CmdErr"
if ($CmdErr.FullyQualifiedErrorId -ne "PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand") {
Write-Host ("Could not delete install directory '$EdgePath'. Please reboot " +
"your device and run Uninstall-SecurityDaemon again with '-Force'.") `
-ForegroundColor "Red"
$success = $false
}
Write-Host ("Could not delete install directory '$EdgePath'. Please reboot " +
"your device and run Uninstall-SecurityDaemon again with '-Force'.") `
-ForegroundColor "Red"
$success = $false
}

Remove-Item -Recurse $EdgeEventLogMessagesPath -ErrorAction SilentlyContinue -ErrorVariable CmdErr
if ($?) {
Write-Verbose "Deleted install directory '$EdgeEventLogMessagesPath'"
}
elseif ($CmdErr.FullyQualifiedErrorId -ne "PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand") {
Write-Warning "Could not delete '$EdgeEventLogMessagesPath'."
Write-Warning "If you're reinstalling or updating IoT Edge, then this is safe to ignore."
Write-Warning ("Otherwise, please close Event Viewer, or any PowerShell windows where you ran Get-WinEvent, " +
"then run Uninstall-SecurityDaemon again with '-Force'.")
}
else {
$success = $false
}

$success
Expand Down Expand Up @@ -374,13 +430,19 @@ function Remove-FirewallExceptions {
Write-Verbose "$(if ($?) { "Removed firewall exceptions" } else { $CmdErr })"
}

function Add-IotEdgeRegistryKey {
function Add-IotEdgeRegistryKey([switch] $UsesSeparateDllForEventLogMessages) {
if ($UsesSeparateDllForEventLogMessages) {
$messageFilePath = 'C:\ProgramData\iotedge-eventlog\iotedged_eventlog_messages.dll'
}
else {
$messageFilePath = 'C:\ProgramData\iotedge\iotedged.exe'
}
$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`""
"`"EventMessageFile`"=`"$($messageFilePath -replace '\\', '\\')`""
"`"TypesSupported`"=dword:00000007")
try {
$RegistryContent | Set-Content "$env:TEMP\iotedge.reg" -Force
Expand Down Expand Up @@ -586,4 +648,4 @@ function Invoke-Native {
}

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

0 comments on commit a135bdf

Please sign in to comment.