mirror of
https://github.com/Icinga/icinga-powershell-framework.git
synced 2025-12-20 23:00:35 -05:00
Fixes config and file writer corruption
This commit is contained in:
parent
21f2f26c1e
commit
59830d9b01
23 changed files with 172 additions and 96 deletions
|
|
@ -23,6 +23,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic
|
||||||
* [#335](https://github.com/Icinga/icinga-powershell-framework/pull/335) Fixes Icinga Director Self-Service Zones and CA config for legacy installation wizard
|
* [#335](https://github.com/Icinga/icinga-powershell-framework/pull/335) Fixes Icinga Director Self-Service Zones and CA config for legacy installation wizard
|
||||||
* [#343](https://github.com/Icinga/icinga-powershell-framework/pull/343) Fixes freeze within Icinga Management Console, in case commands which previously existed were removed/renamed or the user applied an invalid configuration with unknown commands as install file or install command
|
* [#343](https://github.com/Icinga/icinga-powershell-framework/pull/343) Fixes freeze within Icinga Management Console, in case commands which previously existed were removed/renamed or the user applied an invalid configuration with unknown commands as install file or install command
|
||||||
* [#345](https://github.com/Icinga/icinga-powershell-framework/pull/345) Fixes Framework environment variables like `$IcingaEnums` not working with v1.6.0
|
* [#345](https://github.com/Icinga/icinga-powershell-framework/pull/345) Fixes Framework environment variables like `$IcingaEnums` not working with v1.6.0
|
||||||
|
* [#351](https://github.com/Icinga/icinga-powershell-framework/pull/351) Fixes file writer which could cause corruption on parallel read/write events on the same file
|
||||||
|
|
||||||
### Enhancements
|
### Enhancements
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
FunctionsToExport = @( '*' )
|
FunctionsToExport = @( '*' )
|
||||||
CmdletsToExport = @( '*' )
|
CmdletsToExport = @( '*' )
|
||||||
VariablesToExport = '*'
|
VariablesToExport = '*'
|
||||||
AliasesToExport = @( 'icinga' )
|
AliasesToExport = @( '*' )
|
||||||
PrivateData = @{
|
PrivateData = @{
|
||||||
PSData = @{
|
PSData = @{
|
||||||
Tags = @( 'icinga', 'icinga2', 'IcingaPowerShellFramework', 'IcingaPowerShell', 'IcingaforWindows', 'IcingaWindows')
|
Tags = @( 'icinga', 'icinga2', 'IcingaPowerShellFramework', 'IcingaPowerShell', 'IcingaforWindows', 'IcingaWindows')
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ function Write-IcingaFrameworkCodeCache()
|
||||||
$CacheContent += "`r`n";
|
$CacheContent += "`r`n";
|
||||||
}
|
}
|
||||||
|
|
||||||
$CacheContent += "Export-ModuleMember -Function @( '*' )";
|
$CacheContent += "Export-ModuleMember -Function @( '*' ) -Alias @( '*' ) -Variable @( '*' )";
|
||||||
Set-Content -Path $CacheFile -Value $CacheContent;
|
Set-Content -Path $CacheFile -Value $CacheContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,7 +157,7 @@ function Publish-IcingaEventlogDocumentation()
|
||||||
if ([string]::IsNullOrEmpty($OutFile)) {
|
if ([string]::IsNullOrEmpty($OutFile)) {
|
||||||
Write-Output $DocContent;
|
Write-Output $DocContent;
|
||||||
} else {
|
} else {
|
||||||
Set-Content -Path $OutFile -Value $DocContent;
|
Write-IcingaFileSecure -File $OutFile -Value $DocContent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,22 +17,24 @@ function Read-IcingaPowerShellConfig()
|
||||||
{
|
{
|
||||||
$ConfigDir = Get-IcingaPowerShellConfigDir;
|
$ConfigDir = Get-IcingaPowerShellConfigDir;
|
||||||
$ConfigFile = Join-Path -Path $ConfigDir -ChildPath 'config.json';
|
$ConfigFile = Join-Path -Path $ConfigDir -ChildPath 'config.json';
|
||||||
|
$ConfigObject = (New-Object -TypeName PSObject);
|
||||||
|
[string]$Content = Read-IcingaFileSecure -File $ConfigFile -ExitOnReadError;
|
||||||
|
|
||||||
if ($global:IcingaDaemonData.FrameworkRunningAsDaemon) {
|
if ([string]::IsNullOrEmpty($Content) -eq $FALSE) {
|
||||||
if ($global:IcingaDaemonData.ContainsKey('Config')) {
|
try {
|
||||||
return $global:IcingaDaemonData.Config;
|
$ConfigObject = (ConvertFrom-Json -InputObject $Content -ErrorAction Stop);
|
||||||
|
} catch {
|
||||||
|
New-Item -ItemType Directory -Path (Join-Path -Path $ConfigDir -ChildPath 'corrupt') -ErrorAction SilentlyContinue;
|
||||||
|
$NewConfigFile = Join-Path -Path $ConfigDir -ChildPath ([string]::Format('corrupt/config_broken_{0}.json', (Get-Date -Format "yyyy-MM-dd-HH-mm-ss-ffff")));
|
||||||
|
Move-Item -Path $ConfigFile -Destination $NewConfigFile -ErrorAction SilentlyContinue;
|
||||||
|
New-Item -ItemType File -Path $ConfigFile -ErrorAction SilentlyContinue;
|
||||||
|
|
||||||
|
Write-IcingaEventMessage -EventId 1100 -Namespace 'Framework' -Objects $ConfigFile, $Content;
|
||||||
|
Write-IcingaConsoleError -Message 'Your configuration file "{0}" was corrupt and could not be read. It was moved to "{1}" for review and a new plain file has been created' -Objects $ConfigFile, $NewConfigFile;
|
||||||
|
|
||||||
|
$ConfigObject = (New-Object -TypeName PSObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-Not (Test-Path $ConfigFile)) {
|
return $ConfigObject;
|
||||||
return (New-Object -TypeName PSObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
[string]$Content = Read-IcingaFileContent -File $ConfigFile;
|
|
||||||
|
|
||||||
if ([string]::IsNullOrEmpty($Content)) {
|
|
||||||
return (New-Object -TypeName PSObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (ConvertFrom-Json -InputObject $Content);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,16 +25,10 @@ function Write-IcingaPowerShellConfig()
|
||||||
$ConfigFile = Join-Path -Path $ConfigDir -ChildPath 'config.json';
|
$ConfigFile = Join-Path -Path $ConfigDir -ChildPath 'config.json';
|
||||||
|
|
||||||
if (-Not (Test-Path $ConfigDir)) {
|
if (-Not (Test-Path $ConfigDir)) {
|
||||||
New-Item -Path $ConfigDir -ItemType Directory | Out-Null;
|
New-Item -Path $ConfigDir -ItemType Directory -ErrorAction SilentlyContinue | Out-Null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$Content = ConvertTo-Json -InputObject $Config -Depth 100;
|
$Content = ConvertTo-Json -InputObject $Config -Depth 100;
|
||||||
|
|
||||||
Set-Content -Path $ConfigFile -Value $Content;
|
Write-IcingaFileSecure -File $ConfigFile -Value $Content;
|
||||||
|
|
||||||
if ($global:IcingaDaemonData.FrameworkRunningAsDaemon) {
|
|
||||||
if ($global:IcingaDaemonData.ContainsKey('Config')) {
|
|
||||||
$global:IcingaDaemonData.Config = $Config;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
lib/core/cache/Get-IcingaCacheData.psm1
vendored
2
lib/core/cache/Get-IcingaCacheData.psm1
vendored
|
|
@ -40,7 +40,7 @@ function Get-IcingaCacheData()
|
||||||
return $null;
|
return $null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$Content = Read-IcingaFileContent -File $CacheFile;
|
$Content = Read-IcingaFileSecure -File $CacheFile;
|
||||||
|
|
||||||
if ([string]::IsNullOrEmpty($Content)) {
|
if ([string]::IsNullOrEmpty($Content)) {
|
||||||
return $null;
|
return $null;
|
||||||
|
|
|
||||||
9
lib/core/cache/Set-IcingaCacheData.psm1
vendored
9
lib/core/cache/Set-IcingaCacheData.psm1
vendored
|
|
@ -53,17 +53,12 @@ function Set-IcingaCacheData()
|
||||||
$KeyName = $Value
|
$KeyName = $Value
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
if ($cacheData.PSobject.Properties.Name -ne $KeyName) {
|
if ($cacheData.PSObject.Properties.Name -ne $KeyName) {
|
||||||
$cacheData | Add-Member -MemberType NoteProperty -Name $KeyName -Value $Value -Force;
|
$cacheData | Add-Member -MemberType NoteProperty -Name $KeyName -Value $Value -Force;
|
||||||
} else {
|
} else {
|
||||||
$cacheData.$KeyName = $Value;
|
$cacheData.$KeyName = $Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
Write-IcingaFileSecure -File $CacheFile -Value (ConvertTo-Json -InputObject $cacheData -Depth 100);
|
||||||
Set-Content -Path $CacheFile -Value (ConvertTo-Json -InputObject $cacheData -Depth 100) | Out-Null;
|
|
||||||
} catch {
|
|
||||||
Exit-IcingaThrowException -InputString $_.Exception -CustomMessage (Get-IcingaCacheDir) -StringPattern 'System.UnauthorizedAccessException' -ExceptionType 'Permission' -ExceptionThrown $IcingaExceptions.Permission.CacheFolder;
|
|
||||||
Exit-IcingaThrowException -CustomMessage $_.Exception -ExceptionType 'Unhandled' -Force;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -35,6 +35,6 @@ function Find-IcingaAgentObjects()
|
||||||
if ([string]::IsNullOrEmpty($OutFile)) {
|
if ([string]::IsNullOrEmpty($OutFile)) {
|
||||||
Write-Output $Result;
|
Write-Output $Result;
|
||||||
} else {
|
} else {
|
||||||
Set-Content -Path $OutFile -Value $Result;
|
Write-IcingaFileSecure -File $OutFile -Value $Result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -279,7 +279,7 @@ function Copy-IcingaAgentCACertificate()
|
||||||
$Index,
|
$Index,
|
||||||
$response.RawContent.Length - $Index
|
$response.RawContent.Length - $Index
|
||||||
);
|
);
|
||||||
Set-Content -Path (Join-Path $Desination -ChildPath 'ca.crt') -Value $CAContent;
|
Write-IcingaFileSecure -File (Join-Path $Desination -ChildPath 'ca.crt') -Value $CAContent;
|
||||||
Write-IcingaConsoleNotice ([string]::Format('Downloaded ca.crt from "{0}" to "{1}', $CAPath, $Desination))
|
Write-IcingaConsoleNotice ([string]::Format('Downloaded ca.crt from "{0}" to "{1}', $CAPath, $Desination))
|
||||||
} catch {
|
} catch {
|
||||||
Write-IcingaConsoleError 'Failed to load any provided ca.crt ressource';
|
Write-IcingaConsoleError 'Failed to load any provided ca.crt ressource';
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ function Set-IcingaAgentNodeName()
|
||||||
$ConfigContent = $NewConfigContent;
|
$ConfigContent = $NewConfigContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set-Content -Path $ConstantsConf -Value $ConfigContent;
|
Write-IcingaFileSecure -File $ConstantsConf -Value $ConfigContent;
|
||||||
|
|
||||||
Write-IcingaConsoleNotice ([string]::Format('Your hostname was successfully changed to "{0}"', $Hostname));
|
Write-IcingaConsoleNotice ([string]::Format('Your hostname was successfully changed to "{0}"', $Hostname));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ function Set-IcingaAgentServicePermission()
|
||||||
$NewSystemContent += $line;
|
$NewSystemContent += $line;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set-Content -Path "$SystemPermissions.inf" -Value $NewSystemContent;
|
Write-IcingaFileSecure -File "$SystemPermissions.inf" -Value $NewSystemContent;
|
||||||
|
|
||||||
$SystemOutput = Start-IcingaProcess -Executable 'secedit.exe' -Arguments ([string]::Format('/import /cfg "{0}.inf" /db "{0}.sdb"', $SystemPermissions));
|
$SystemOutput = Start-IcingaProcess -Executable 'secedit.exe' -Arguments ([string]::Format('/import /cfg "{0}.inf" /db "{0}.sdb"', $SystemPermissions));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,6 @@ function Write-IcingaAgentApiConfig()
|
||||||
|
|
||||||
$ApiConf = $ApiConf.Substring(0, $ApiConf.Length - 4);
|
$ApiConf = $ApiConf.Substring(0, $ApiConf.Length - 4);
|
||||||
|
|
||||||
Set-Content -Path (Join-Path -Path (Get-IcingaAgentConfigDirectory) -ChildPath 'features-available\api.conf') -Value $ApiConf;
|
Write-IcingaFileSecure -File (Join-Path -Path (Get-IcingaAgentConfigDirectory) -ChildPath 'features-available\api.conf') -Value $ApiConf;
|
||||||
Write-IcingaConsoleNotice 'Api configuration has been written successfully';
|
Write-IcingaConsoleNotice 'Api configuration has been written successfully';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,5 +10,5 @@ function Write-IcingaAgentObjectList()
|
||||||
|
|
||||||
$ObjectList = Get-IcingaAgentObjectList;
|
$ObjectList = Get-IcingaAgentObjectList;
|
||||||
|
|
||||||
Set-Content -Path $Path -Value $ObjectList;
|
Write-IcingaFileSecure -File $Path -Value $ObjectList;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,6 @@ function Write-IcingaAgentZonesConfig()
|
||||||
|
|
||||||
$ZonesConf = $ZonesConf.Substring(0, $ZonesConf.Length - 4);
|
$ZonesConf = $ZonesConf.Substring(0, $ZonesConf.Length - 4);
|
||||||
|
|
||||||
Set-Content -Path (Join-Path -Path (Get-IcingaAgentConfigDirectory) -ChildPath 'zones.conf') -Value $ZonesConf;
|
Write-IcingaFileSecure -File (Join-Path -Path (Get-IcingaAgentConfigDirectory) -ChildPath 'zones.conf') -Value $ZonesConf;
|
||||||
Write-IcingaConsoleNotice 'Icinga Agent zones.conf has been written successfully';
|
Write-IcingaConsoleNotice 'Icinga Agent zones.conf has been written successfully';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ function Install-Icinga()
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([string]::IsNullOrEmpty($InstallFile) -eq $FALSE) {
|
if ([string]::IsNullOrEmpty($InstallFile) -eq $FALSE) {
|
||||||
$InstallCommand = Read-IcingaFileContent -File $InstallFile;
|
$InstallCommand = Read-IcingaFileSecure -File $InstallFile -ExitOnReadError;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Use our install command to configure everything
|
# Use our install command to configure everything
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ function Export-IcingaForWindowsManagementConsoleInstallationAnswerFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Test-Path ($FilePath)) {
|
if (Test-Path ($FilePath)) {
|
||||||
Set-Content -Path (Join-Path -Path $FilePath -ChildPath 'IfW_answer.json') -Value (Get-IcingaForWindowsManagementConsoleConfigurationString);
|
Write-IcingaFileSecure -File (Join-Path -Path $FilePath -ChildPath 'IfW_answer.json') -Value (Get-IcingaForWindowsManagementConsoleConfigurationString);
|
||||||
$global:Icinga.InstallWizard.NextCommand = 'Install-Icinga';
|
$global:Icinga.InstallWizard.NextCommand = 'Install-Icinga';
|
||||||
$global:Icinga.InstallWizard.LastNotice = ([string]::Format('Answer file "IfW_answer.json" successfully exported into "{0}"', $FilePath));
|
$global:Icinga.InstallWizard.LastNotice = ([string]::Format('Answer file "IfW_answer.json" successfully exported into "{0}"', $FilePath));
|
||||||
Clear-IcingaForWindowsManagementConsolePaginationCache;
|
Clear-IcingaForWindowsManagementConsolePaginationCache;
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,24 @@ if ($null -eq $IcingaEventLogEnums -Or $IcingaEventLogEnums.ContainsKey('Framewo
|
||||||
'Details' = 'The Framework or is components can issue generic debug message in case the debug log is enabled. Please ensure to disable it, if not used. You can do so with the command "Disable-IcingaFrameworkDebugMode"';
|
'Details' = 'The Framework or is components can issue generic debug message in case the debug log is enabled. Please ensure to disable it, if not used. You can do so with the command "Disable-IcingaFrameworkDebugMode"';
|
||||||
'EventId' = 1000;
|
'EventId' = 1000;
|
||||||
};
|
};
|
||||||
|
1100 = @{
|
||||||
|
'EntryType' = 'Error';
|
||||||
|
'Message' = 'Corrupt Icinga for Windows configuration';
|
||||||
|
'Details' = 'Your Icinga for Windows configuration file was corrupt and could not be read successfully. A new configuration file was created and the old one renamed for review, to keep your settings available.';
|
||||||
|
'EventId' = 1100;
|
||||||
|
};
|
||||||
|
1101 = @{
|
||||||
|
'EntryType' = 'Warning';
|
||||||
|
'Message' = 'Unable to update Icinga for Windows file';
|
||||||
|
'Details' = 'Icinga for Windows could not update the specified file after several attempts, because another process is locking it. Modifications made on the file have not been persisted.';
|
||||||
|
'EventId' = 1101;
|
||||||
|
};
|
||||||
|
1102 = @{
|
||||||
|
'EntryType' = 'Warning';
|
||||||
|
'Message' = 'Unable to read Icinga for Windows content file';
|
||||||
|
'Details' = 'Icinga for Windows could not read the specified file after several attempts, because another process is locking the file. Icinga for Windows terminated itself to prevent damage to this file.';
|
||||||
|
'EventId' = 1102;
|
||||||
|
};
|
||||||
1500 = @{
|
1500 = @{
|
||||||
'EntryType' = 'Error';
|
'EntryType' = 'Error';
|
||||||
'Message' = 'Failed to securely establish a communication between this server and the client';
|
'Message' = 'Failed to securely establish a communication between this server and the client';
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ function New-IcingaRepositoryFile()
|
||||||
$IcingaRepository.Info.RepoHash = Get-IcingaRepositoryHash -Path $Path;
|
$IcingaRepository.Info.RepoHash = Get-IcingaRepositoryHash -Path $Path;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set-Content -Path $RepoPath -Value (ConvertTo-Json -InputObject $IcingaRepository -Depth 100);
|
Write-IcingaFileSecure -File $RepoPath -Value (ConvertTo-Json -InputObject $IcingaRepository -Depth 100);
|
||||||
|
|
||||||
return $IcingaRepository;
|
return $IcingaRepository;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,7 @@ function Sync-IcingaRepository()
|
||||||
$JsonRepo.Info.RemoteSource = $RemotePath;
|
$JsonRepo.Info.RemoteSource = $RemotePath;
|
||||||
$JsonRepo.Info.Updated = ((Get-Date).ToUniversalTime().ToString('yyyy\/MM\/dd HH:mm:ss'));
|
$JsonRepo.Info.Updated = ((Get-Date).ToUniversalTime().ToString('yyyy\/MM\/dd HH:mm:ss'));
|
||||||
|
|
||||||
Set-Content -Path $RepoFile -Value (ConvertTo-Json -InputObject $JsonRepo -Depth 100);
|
Write-IcingaFileSecure -File $RepoFile -Value (ConvertTo-Json -InputObject $JsonRepo -Depth 100);
|
||||||
|
|
||||||
if ($UseSCP -eq $FALSE) { # Windows target
|
if ($UseSCP -eq $FALSE) { # Windows target
|
||||||
$Success = Remove-Item -Path $RemovePath -Recurse -Force;
|
$Success = Remove-Item -Path $RemovePath -Recurse -Force;
|
||||||
|
|
|
||||||
|
|
@ -408,7 +408,7 @@ function Get-IcingaCheckCommandConfig()
|
||||||
if ($IcingaConfig) {
|
if ($IcingaConfig) {
|
||||||
Write-IcingaPlainConfigurationFiles -Content $Basket -OutDirectory $ConfigDirectory -FileName $FileName;
|
Write-IcingaPlainConfigurationFiles -Content $Basket -OutDirectory $ConfigDirectory -FileName $FileName;
|
||||||
} else {
|
} else {
|
||||||
Set-Content -Path $OutDirectory -Value $output;
|
Write-IcingaFileSecure -File $OutDirectory -Value $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Output-Text
|
# Output-Text
|
||||||
|
|
@ -571,8 +571,8 @@ function Write-IcingaPlainConfigurationFiles()
|
||||||
$PowerShellBase += [string]::Format(' timeout = 3m{0}', (New-IcingaNewLine));
|
$PowerShellBase += [string]::Format(' timeout = 3m{0}', (New-IcingaNewLine));
|
||||||
$PowerShellBase += '}';
|
$PowerShellBase += '}';
|
||||||
|
|
||||||
Set-Content -Path (Join-Path -Path $ConfigDirectory -ChildPath 'PowerShell_Base.conf') -Value $PowerShellBase;
|
Write-IcingaFileSecure -File (Join-Path -Path $ConfigDirectory -ChildPath 'PowerShell_Base.conf') -Value $PowerShellBase;
|
||||||
Set-Content -Path $OutDirectory -Value $IcingaConfig;
|
Write-IcingaFileSecure -File $OutDirectory -Value $IcingaConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Add-PowerShellDataList()
|
function Add-PowerShellDataList()
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
Reads content of a file in read-only mode, ensuring no data corruption is happening
|
|
||||||
.DESCRIPTION
|
|
||||||
Reads content of a file in read-only mode, ensuring no data corruption is happening
|
|
||||||
.FUNCTIONALITY
|
|
||||||
Reads content of a file in read-only mode, ensuring no data corruption is happening
|
|
||||||
.EXAMPLE
|
|
||||||
PS>Read-IcingaFileContent -File 'config.json';
|
|
||||||
.OUTPUTS
|
|
||||||
System.Object
|
|
||||||
.LINK
|
|
||||||
https://github.com/Icinga/icinga-powershell-framework
|
|
||||||
#>
|
|
||||||
|
|
||||||
function Read-IcingaFileContent()
|
|
||||||
{
|
|
||||||
param (
|
|
||||||
[string]$File
|
|
||||||
);
|
|
||||||
|
|
||||||
if ((Test-Path $File) -eq $FALSE) {
|
|
||||||
return $null;
|
|
||||||
}
|
|
||||||
|
|
||||||
[System.IO.FileStream]$FileStream = [System.IO.File]::Open(
|
|
||||||
$File,
|
|
||||||
[System.IO.FileMode]::Open,
|
|
||||||
[System.IO.FileAccess]::Read,
|
|
||||||
[System.IO.FileShare]::Read
|
|
||||||
);
|
|
||||||
|
|
||||||
$ReadArray = New-Object Byte[] $FileStream.Length;
|
|
||||||
$UTF8Encoding = New-Object System.Text.UTF8Encoding $TRUE;
|
|
||||||
$FileContent = '';
|
|
||||||
|
|
||||||
while ($FileStream.Read($ReadArray, 0 , $ReadArray.Length)) {
|
|
||||||
$FileContent = [System.String]::Concat($FileContent, $UTF8Encoding.GetString($ReadArray));
|
|
||||||
}
|
|
||||||
|
|
||||||
$FileStream.Dispose();
|
|
||||||
|
|
||||||
return $FileContent;
|
|
||||||
}
|
|
||||||
71
lib/core/tools/Read-IcingaFileSecure.psm1
Normal file
71
lib/core/tools/Read-IcingaFileSecure.psm1
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Reads content of a file in read-only mode, ensuring no data corruption is happening
|
||||||
|
.DESCRIPTION
|
||||||
|
Reads content of a file in read-only mode, ensuring no data corruption is happening
|
||||||
|
.FUNCTIONALITY
|
||||||
|
Reads content of a file in read-only mode, ensuring no data corruption is happening
|
||||||
|
.EXAMPLE
|
||||||
|
PS>Read-IcingaFileSecure -File 'config.json';
|
||||||
|
.EXAMPLE
|
||||||
|
PS>Read-IcingaFileSecure -File 'config.json' -ExitOnReadError;
|
||||||
|
.OUTPUTS
|
||||||
|
System.Object
|
||||||
|
.LINK
|
||||||
|
https://github.com/Icinga/icinga-powershell-framework
|
||||||
|
#>
|
||||||
|
|
||||||
|
function Read-IcingaFileSecure()
|
||||||
|
{
|
||||||
|
param (
|
||||||
|
[string]$File,
|
||||||
|
[switch]$ExitOnReadError = $FALSE
|
||||||
|
);
|
||||||
|
|
||||||
|
if ([string]::IsNullOrEmpty($File) -Or (Test-Path $File) -eq $FALSE) {
|
||||||
|
return $null;
|
||||||
|
}
|
||||||
|
|
||||||
|
[int]$WaitTicks = 0;
|
||||||
|
[bool]$ConfigRead = $FALSE;
|
||||||
|
|
||||||
|
# Lets wait 5 seconds before cancelling reading
|
||||||
|
while ($WaitTicks -lt (($WaitTicks + 1) * 50)) {
|
||||||
|
try {
|
||||||
|
[System.IO.FileStream]$FileStream = [System.IO.File]::Open(
|
||||||
|
$File,
|
||||||
|
[System.IO.FileMode]::Open,
|
||||||
|
[System.IO.FileAccess]::Read,
|
||||||
|
[System.IO.FileShare]::Read
|
||||||
|
);
|
||||||
|
|
||||||
|
$ReadArray = New-Object Byte[] $FileStream.Length;
|
||||||
|
$UTF8Encoding = New-Object System.Text.UTF8Encoding $TRUE;
|
||||||
|
$FileContent = '';
|
||||||
|
|
||||||
|
while ($FileStream.Read($ReadArray, 0 , $ReadArray.Length)) {
|
||||||
|
$FileContent = [System.String]::Concat($FileContent, $UTF8Encoding.GetString($ReadArray));
|
||||||
|
}
|
||||||
|
|
||||||
|
$FileStream.Dispose();
|
||||||
|
$ConfigRead = $TRUE;
|
||||||
|
break;
|
||||||
|
} catch {
|
||||||
|
# File is still locked, wait for lock to vanish
|
||||||
|
}
|
||||||
|
|
||||||
|
$WaitTicks += 1;
|
||||||
|
Start-Sleep -Milliseconds 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ConfigRead -eq $FALSE -And $ExitOnReadError) {
|
||||||
|
Write-IcingaEventMessage -EventId 1102 -Namespace 'Framework' -Objects $ConfigFile, $Content;
|
||||||
|
Write-IcingaConsoleWarning -Message 'Your file "{0}" could not be read, as another process is locking it. Icinga for Windows will terminate itself after 5 seconds to prevent damage to this file.' -Objects $File;
|
||||||
|
Start-Sleep -Seconds 5;
|
||||||
|
exit 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $FileContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set-Alias -Name 'Read-IcingaFileContent' -Value 'Read-IcingaFileSecure';
|
||||||
39
lib/core/tools/Write-IcingaFileSecure.psm1
Normal file
39
lib/core/tools/Write-IcingaFileSecure.psm1
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
function Write-IcingaFileSecure()
|
||||||
|
{
|
||||||
|
param (
|
||||||
|
[string]$File,
|
||||||
|
$Value
|
||||||
|
);
|
||||||
|
|
||||||
|
[int]$WaitTicks = 0;
|
||||||
|
[bool]$FileUpdated = $FALSE;
|
||||||
|
|
||||||
|
# Lets wait 5 seconds before cancelling writing
|
||||||
|
while ($WaitTicks -lt (($WaitTicks + 1) * 50)) {
|
||||||
|
try {
|
||||||
|
[System.IO.FileStream]$FileStream = [System.IO.File]::Open(
|
||||||
|
$File,
|
||||||
|
[System.IO.FileMode]::Truncate,
|
||||||
|
[System.IO.FileAccess]::Write,
|
||||||
|
[System.IO.FileShare]::Read
|
||||||
|
);
|
||||||
|
|
||||||
|
$ContentBytes = [System.Text.Encoding]::UTF8.GetBytes($Value);
|
||||||
|
$FileStream.Write($ContentBytes, 0, $ContentBytes.Length);
|
||||||
|
$FileStream.Dispose();
|
||||||
|
$FileUpdated = $TRUE;
|
||||||
|
break;
|
||||||
|
} catch {
|
||||||
|
Exit-IcingaThrowException -InputString $_.Exception -CustomMessage $File -StringPattern 'System.UnauthorizedAccessException' -ExceptionType 'Permission' -ExceptionThrown $IcingaExceptions.Permission.CacheFolder;
|
||||||
|
# File is still locked, wait for lock to vanish
|
||||||
|
}
|
||||||
|
|
||||||
|
$WaitTicks += 1;
|
||||||
|
Start-Sleep -Milliseconds 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($FileUpdated -eq $FALSE) {
|
||||||
|
Write-IcingaEventMessage -EventId 1101 -Namespace 'Framework' -Objects $File, $Value;
|
||||||
|
Write-IcingaConsoleWarning -Message 'Your file "{0}" could not be updated with your changes, as another process is locking it.' -Objects $File;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue