366 lines
27 KiB
PowerShell
366 lines
27 KiB
PowerShell
Function Read-ConfigFile2 {
|
||
|
||
<#
|
||
.SYNOPSIS
|
||
Function will read the given ConfigFile, and returns a HashTable with all Keys and Values.
|
||
|
||
.DESCRIPTION
|
||
This Function will get Script configurations from a ASCII/ANSI based ConfigFile (INI).
|
||
The important criterion is, that every Value the should be read, has to look like this: ConfigLabel = ConfigValue
|
||
The ConfigFile should be formated within UTF8 and every Line in a ConfigFile which is beginning with a "#", will be ignored!
|
||
The Return Value of this Function will be a HashTable Object, with two columns (key column and value/values column).
|
||
Every Value in the Value column will be saved as Array value, even there is only one value.
|
||
For every line in the ConfigFile, there will be an additional line in HashTable, which says how many line (profiles) where read.
|
||
|
||
.REQUIREMENT General
|
||
PowerShell V3
|
||
|
||
.REQUIREMENT Assembly
|
||
<NONE>
|
||
|
||
.REQUIREMENT Variables
|
||
Counter1, Counter2, ConfigFile, ConfigLabels, ConfigFileLine, ConfigFileLines, ConfigValue, ConfigValues, ConfigFileLineKey, ConfigLinesValue, ConfigLinesValues, ConfigLinesValueSeparator, ConfigFileLineValuesTEMP, HashTable_MetaData
|
||
|
||
.REQUIREMENT Variables preSet
|
||
<NONE>
|
||
|
||
.REQUIREMENT Functions
|
||
<NONE>
|
||
|
||
.VERSION
|
||
Number: 1.2.0.0 / Date: 23.02.2024
|
||
|
||
.PARAMETER ConfigFile
|
||
Optional Parameter. Give the full path to the ConfigFile (eg. <ScriptName>_Settings.ini). (Default: If you dont give it, Function will try the retrieve ConfigFile (Path and Name) from the Global Variables, set by the calling Script.)
|
||
|
||
.PARAMETER ConfigLabels
|
||
Optional Parameter. Give the ConfigLabels (Seperate with a ",") which are very mandatory for a working Script. Script will exit, if one or more are missing or have no Values.
|
||
|
||
.PARAMETER ConfigLinesDelimiter
|
||
Optional Parameter. Set the Delimiter which is in between the ConfigLabel and ConfigValue(s) in the ConfigFile (Default: "=").
|
||
|
||
.PARAMETER ConfigLinesValueSeparator
|
||
Optional Parameter. Set the symbol or character for Value separation (Default: ";"). Please Mask with a "\", if you want that Separator ignored (e.g in a RegEx).
|
||
|
||
.PARAMETER RemoveMaskingOfConfigLinesValueSeparator
|
||
Optional Parameter. Enable or disable, if the masking ("\") mark for ConfigLinesValueSeparator, should be removed after reading it (Default: $False).
|
||
|
||
.EXAMPLE
|
||
Read-ConfigFile2 -ConfigFile <Path>\<ScriptName>_Settings.ini
|
||
|
||
.EXAMPLE
|
||
Read-ConfigFile2 -ConfigFile <Path>\<ScriptName>_Settings.ini -ConfigLabels LogPath
|
||
|
||
.EXAMPLE
|
||
Read-ConfigFile2 -ConfigFile <Path>\<ScriptName>_Settings.ini -ConfigLabels LogPath, LogKeepTime -RemoveMaskingOfConfigLinesValueSeparator
|
||
|
||
#>
|
||
|
||
Param (
|
||
|
||
[Parameter(Position=0,Mandatory=$False,HelpMessage='Optional Parameter. Give the full path to the ConfigFile (eg. <ScriptName>_Settings.ini). (Default: If you dont give it, Function will try the retrieve ConfigFile (Path and Name) from the Global Variables, set by the calling Script.)')]
|
||
[ValidateNotNullOrEmpty()]
|
||
[STRING]$ConfigFile=(Get-Variable -Name ConfigFile -Scope Global -ValueOnly),
|
||
|
||
[Parameter(Position=1,Mandatory=$False,HelpMessage='Optional Parameter. Give the ConfigLabels (Seperate with a ",") which are very mandatory for a working Script. Script will exit, if one or more are missing or have no Values.')]
|
||
[ValidateNotNullOrEmpty()]
|
||
[ARRAY]$ConfigLabels=@(),
|
||
|
||
[Parameter(Position=2,Mandatory=$False,HelpMessage='Optional Parameter. Set the Delimiter which is in between the ConfigLabel and ConfigValue(s) in the ConfigFile (Default: "=").')]
|
||
[ValidateNotNullOrEmpty()]
|
||
[STRING]$ConfigLinesDelimiter='=',
|
||
|
||
[Parameter(Position=3,Mandatory=$False,HelpMessage='Optional Parameter. Set the symbol or character for Value separation (Default: ";"). Please Mask with a "\", if you want that Separator ignored (e.g in a RegEx).')]
|
||
[ValidateNotNullOrEmpty()]
|
||
[STRING]$ConfigLinesValueSeparator=';',
|
||
|
||
[Parameter(Position=4,Mandatory=$False,HelpMessage='Optional Parameter. Enable or disable, if the masking ("\") mark for ConfigLinesValueSeparator, should be removed after reading it (Default: $False).')]
|
||
[ValidateNotNullOrEmpty()]
|
||
[SWITCH]$RemoveMaskingOfConfigLinesValueSeparator=$False
|
||
|
||
) #end param
|
||
|
||
#Clear Error Variable
|
||
$error.clear()
|
||
|
||
#Check if ConfigFile exists
|
||
IF ((Test-Path -Path $ConfigFile -PathType Leaf -ErrorAction Stop) -eq $true) {
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Module begins reading of ConfigFile:"
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: $ConfigFile"
|
||
|
||
Try {
|
||
|
||
#Prepare Variables
|
||
[INT]$Counter1 = 0
|
||
[INT]$Counter2 = 0
|
||
[ARRAY]$ConfigFileLine = @()
|
||
[ARRAY]$ConfigFileLines = (Select-String -Path $ConfigFile -Pattern "$ConfigLinesDelimiter" -ErrorAction Stop | Where-Object {-not($_-match ":[0-9]{1,}:#")})
|
||
[STRING]$ConfigFileLineKey = $NULL
|
||
[STRING]$ConfigFileLineValue = $NULL
|
||
[ARRAY]$ConfigFileLineValues = @()
|
||
[System.Collections.ArrayList]$ConfigFileLineValuesTEMP = @()
|
||
[ARRAY]$HashTable_MetaData = @($($ConfigFile),$(Get-Date -Format 'ddMMyyyy_HHmmssffff'))
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Found $($ConfigFileLines.count) relevant Lines in ConfigFile!"
|
||
|
||
#Prepare HashTable incl. Fallback to PowerShell Version 2 compatibility
|
||
Try {
|
||
|
||
$ConfigFileTable = [ordered]@{}
|
||
|
||
} #end try
|
||
|
||
Catch {
|
||
|
||
$ConfigFileTable = New-Object [System.Collections.Specialized.OrderedDictionary]([System.StringComparer]::OrdinalIgnoreCase) -ErrorAction Stop
|
||
|
||
Try {
|
||
|
||
$ConfigFileTable = New-Object [System.Collections.Specialized.OrderedDictionary] -ErrorAction Stop
|
||
|
||
} #end try
|
||
|
||
Catch {
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Cannot create HashTable for Config Values!"
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Exiting, because of this Issue."
|
||
Write-Host $Error
|
||
EXIT
|
||
|
||
} #end catch
|
||
|
||
} #end catch
|
||
|
||
#First Key and Value in HashTable was about its own Metadata Informations
|
||
$ConfigFileTable.Add("HashTable_MetaData",$HashTable_MetaData)
|
||
Write-Host ""
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: HashTable Key with name: HashTable_MetaData,"
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: got this Value: $HashTable_MetaData)"
|
||
|
||
} #end try
|
||
|
||
Catch {
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Module cannot read ConfigFile:"
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: $ConfigFile"
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Exiting, because of this Issue."
|
||
Write-Host $Error
|
||
EXIT
|
||
|
||
} #end catch
|
||
|
||
DO {
|
||
|
||
#Loop for each Line in ConfigFile
|
||
$ConfigFileLine = ($ConfigFileLines.SyncRoot[$Counter1]).line
|
||
|
||
IF ([INT](([REGEX]::Matches($ConfigFileLine,"$ConfigLinesDelimiter")).count) -gt 1) {
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Multiple ConfigLinesDelimiters found $((([REGEX]::Matches($ConfigFileLine,"$ConfigLinesDelimiter")).count)) "
|
||
$ConfigFileLine = ($ConfigFileLine -split "$ConfigLinesDelimiter",2)
|
||
|
||
} #end elseif
|
||
|
||
ELSE {
|
||
|
||
$ConfigFileLine = ($ConfigFileLine -split "$ConfigLinesDelimiter")
|
||
|
||
} #end else
|
||
|
||
$Counter1++ | Out-Null
|
||
Write-Host ""
|
||
|
||
#The Key is easy to determ
|
||
($ConfigFileLine[0]) = ($ConfigFileLine[0].TrimStart())
|
||
($ConfigFileLine[0]) = ($ConfigFileLine[0].TrimEnd())
|
||
($ConfigFileLineKey) = ($ConfigFileLine[0])
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: HashTable Key with name: $($ConfigFileLine[0]),"
|
||
|
||
#The Value is more work - first we have to check if Value is empty and if Failsave Value is available
|
||
IF (([String]::IsNullOrEmpty($ConfigFileLine[1])) -or ([String]::IsNullOrWhiteSpace($ConfigFileLine[1]))) {
|
||
|
||
Try {
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: $($ConfigFileLine[0]) has no Value, trying to get FailSafe Value from main Script!"
|
||
($ConfigFileLine[1]) = (Get-Variable -Name $($ConfigFileLine[0]) -Scope Global -ValueOnly -ErrorAction Stop)
|
||
|
||
#If a object returns, set Array value back to an empty string,
|
||
#because this happens if a config line in the ini file is empty (like: Profile = )
|
||
If ($ConfigFileLine[1].gettype() -is [System.Object]) {
|
||
$ConfigFileLine[1] = [String]$Null
|
||
} #end if
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: FailSafe Value returnd and set!"
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Got this Value: $($ConfigFileLine[1])"
|
||
|
||
} #end try
|
||
|
||
Catch {
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: FailSafe cannot be found, leaving empty!"
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: ... could be a Issue, if the ConfigLabel was mandatory set by function call!"
|
||
|
||
} #end catch
|
||
|
||
} #end if
|
||
|
||
ELSE {
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: got this Value: $($ConfigFileLine[1])"
|
||
|
||
} #end else
|
||
|
||
#If the Value line includes the ValueSeperator, split the Value! Except ValueSeperator is escaped/masked by a "\", like its standard in a RegEx
|
||
IF ($($ConfigFileLine[1]) | Where-Object {($_-match "$ConfigLinesValueSeparator")} | Where-Object {-not($_-match "\\$ConfigLinesValueSeparator")}) {
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Found ConfigLinesValueSeparator in Value from $($ConfigFileLine[0])"
|
||
($ConfigFileLineValues) = ($ConfigFileLine[1] -split "$ConfigLinesValueSeparator")
|
||
|
||
FOREACH ($ConfigFileLineValue in $ConfigFileLineValues) {
|
||
|
||
$ConfigFileLineValue = ($ConfigFileLineValue.TrimStart())
|
||
$ConfigFileLineValue = ($ConfigFileLineValue.TrimEnd())
|
||
|
||
$ConfigFileLineValuesTEMP.Add($ConfigFileLineValue) | Out-Null
|
||
|
||
} #end foreach
|
||
|
||
$ConfigFileLineValues = @($ConfigFileLineValuesTEMP)
|
||
$ConfigFileLineValuesTEMP = @()
|
||
|
||
} #end if
|
||
|
||
ELSE {
|
||
|
||
#Maybe you want the remove the "\", because ConfigLinesValueSeparator was set but for one line or case not used
|
||
IF ($RemoveMaskingOfConfigLinesValueSeparator -eq $True) {
|
||
|
||
($ConfigFileLine[1]) = ($ConfigFileLine[1].Replace("\$ConfigLinesValueSeparator","$ConfigLinesValueSeparator"))
|
||
|
||
} #end if
|
||
|
||
($ConfigFileLine[1]) = ($ConfigFileLine[1].TrimStart())
|
||
($ConfigFileLine[1]) = ($ConfigFileLine[1].TrimEnd())
|
||
($ConfigFileLineValues) = ($ConfigFileLine[1])
|
||
|
||
} #end else
|
||
|
||
#Finally fill keys and values into the HashTable
|
||
Try {
|
||
|
||
#If the Key is first time inserting
|
||
IF (($ConfigFileTable.Contains($ConfigFileLineKey)) -eq $False) {
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Inserting a single line Value into the HashTable!"
|
||
|
||
$Counter2++ | Out-Null
|
||
$ConfigFileTable.Add($ConfigFileLineKey,$($Counter2,"Profile(s)"))
|
||
$ConfigFileTable.Add(($ConfigFileLineKey+'_'+$Counter2),$ConfigFileLineValues)
|
||
$Counter2=0 | Out-Null
|
||
|
||
} #end if
|
||
|
||
#If the Key is second and more time(s) inserting, like its used in profiles
|
||
ELSE {
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Inserting multi line Values into the HashTable!"
|
||
|
||
DO {
|
||
|
||
$Counter2++ | Out-Null
|
||
|
||
} #end do
|
||
|
||
UNTIL (($ConfigFileTable.Contains($ConfigFileLineKey+'_'+$Counter2)) -eq $False)
|
||
|
||
$ConfigFileTable.$ConfigFileLineKey = @($Counter2,"Profile(s)")
|
||
$ConfigFileTable.Add(($ConfigFileLineKey+'_'+$Counter2),$ConfigFileLineValues)
|
||
$Counter2=0 | Out-Null
|
||
|
||
} #end elseif
|
||
|
||
} #end try
|
||
|
||
#Getting last Exeption Message or Code: $Error[0] | fl * -Force
|
||
Catch {
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Error inserting into HashTable!"
|
||
Write-Host $Error
|
||
|
||
} #end catch
|
||
|
||
} #end do
|
||
|
||
UNTIL ($Counter1 -eq ($ConfigFileLines.Count))
|
||
|
||
Write-Host ""
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Set $($ConfigFileTable.Count) lines in HashTable!"
|
||
|
||
#Check for mandatory Keys and Values! Exit whole Script if something is missing!
|
||
IF ($ConfigLabels.count -gt 0) {
|
||
|
||
FOREACH ($ConfigLabel in $ConfigLabels) {
|
||
|
||
Write-Host ""
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Checking if mandatory ConfigLabel: $ConfigLabel - exists in HashTable"
|
||
IF ($ConfigFileTable.Contains($ConfigLabel) -eq $True) {
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Yes, ConfigLabel exisits!"
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Checking if mandatory ConfigLabel: $ConfigLabel - has a Value"
|
||
IF (!([String]::IsNullOrEmpty($ConfigFileTable.Get_Item($ConfigLabel))) -or (![String]::IsNullOrWhiteSpace($ConfigFileTable.Get_Item($ConfigLabel)))) {
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Yes, value for ConfigLabel exisits!"
|
||
|
||
} #end if
|
||
|
||
ELSE {
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: No, value for ConfigLabel does exisit!"
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Exiting, because of this Issue."
|
||
Write-Host $Error
|
||
EXIT
|
||
|
||
} #end else
|
||
|
||
} #end if
|
||
|
||
ELSE {
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: No, ConfigLabel does not exisit!"
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Exiting, because of this Issue."
|
||
Write-Host $Error
|
||
EXIT
|
||
|
||
} #end else
|
||
|
||
} #end foreach
|
||
|
||
} #end if
|
||
|
||
ELSE {
|
||
|
||
Write-Host ""
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: No mandatory ConfigLabels are set!"
|
||
|
||
} #end else
|
||
|
||
#Show the whole HashTable in GUI - for Debug reasons
|
||
#$ConfigFileTable | Out-GridView
|
||
|
||
#Return the whole HashTable
|
||
Return $ConfigFileTable
|
||
|
||
} #end try
|
||
|
||
ELSE {
|
||
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Module cannot get content of ConfigFile:"
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: $ConfigFile"
|
||
Write-Host "DEBUG Info - Read-ConfigFile2: Exiting, because of this Issue."
|
||
Write-Host $Error
|
||
EXIT
|
||
|
||
} #end catch
|
||
|
||
} #end function |