diff --git a/Examples/IniConfigDemo.ps1 b/Examples/IniConfigDemo.ps1 new file mode 100644 index 0000000..cf85d79 --- /dev/null +++ b/Examples/IniConfigDemo.ps1 @@ -0,0 +1,12 @@ + +# Load the default configuration file in INI format +$Config = Get-ScriptConfig -Format INI + +# Access the configuration settings +Write-Host "String :" $Config.MyString +Write-Host "Integer Positive :" $Config.MyIntegerPositive +Write-Host "Integer Negative :" $Config.MyIntegerNegative +Write-Host "Boolean True :" $Config.MyBooleanTrue +Write-Host "Boolean False :" $Config.MyBooleanFalse +Write-Host "Array :" "@(" (($Config.MyArray | ForEach-Object { '"{0}"' -f $_ }) -join ', ') ")" +Write-Host "Hashtable :" "@{" (($Config.MyHashtable.GetEnumerator() | ForEach-Object { '{0} = "{1}"' -f $_.Name, $_.Value }) -join '; ') "}" diff --git a/Examples/IniConfigDemo.ps1.config b/Examples/IniConfigDemo.ps1.config new file mode 100644 index 0000000..e6d35c4 --- /dev/null +++ b/Examples/IniConfigDemo.ps1.config @@ -0,0 +1,9 @@ +MyString=This is a test INI config file! +MyIntegerPositive=42 +MyIntegerNegative=-153 +MyBooleanTrue=True +MyBooleanFalse=False +MyArray[]=Lorem +MyArray[]=Ipsum +MyHashtable[Foo]=Bar +MyHashtable[Hello]=World diff --git a/Examples/JsonConfigDemo.ps1 b/Examples/JsonConfigDemo.ps1 new file mode 100644 index 0000000..48d12c6 --- /dev/null +++ b/Examples/JsonConfigDemo.ps1 @@ -0,0 +1,12 @@ + +# Load the default configuration file in JSON format +$Config = Get-ScriptConfig -Format JSON + +# Access the configuration settings +Write-Host "String :" $Config.MyString +Write-Host "Integer Positive :" $Config.MyIntegerPositive +Write-Host "Integer Negative :" $Config.MyIntegerNegative +Write-Host "Boolean True :" $Config.MyBooleanTrue +Write-Host "Boolean False :" $Config.MyBooleanFalse +Write-Host "Array :" "@(" (($Config.MyArray | ForEach-Object { '"{0}"' -f $_ }) -join ', ') ")" +Write-Host "Hashtable :" "@{" (($Config.MyHashtable.GetEnumerator() | ForEach-Object { '{0} = "{1}"' -f $_.Name, $_.Value }) -join '; ') "}" diff --git a/Examples/JsonConfigDemo.ps1.config b/Examples/JsonConfigDemo.ps1.config new file mode 100644 index 0000000..1853b4f --- /dev/null +++ b/Examples/JsonConfigDemo.ps1.config @@ -0,0 +1,15 @@ +{ + "MyString": "This is a test JSON config file!", + "MyIntegerPositive": 42, + "MyIntegerNegative": -153, + "MyBooleanTrue": true, + "MyBooleanFalse": false, + "MyArray": [ + "Lorem", + "Ipsum" + ], + "MyHashtable": { + "Foo": "Bar", + "Hello": "World" + } +} diff --git a/Examples/XmlConfigDemo.ps1 b/Examples/XmlConfigDemo.ps1 new file mode 100644 index 0000000..20429e9 --- /dev/null +++ b/Examples/XmlConfigDemo.ps1 @@ -0,0 +1,12 @@ + +# Load the default configuration file in XML format +$Config = Get-ScriptConfig -Format XML + +# Access the configuration settings +Write-Host "String :" $Config.MyString +Write-Host "Integer Positive :" $Config.MyIntegerPositive +Write-Host "Integer Negative :" $Config.MyIntegerNegative +Write-Host "Boolean True :" $Config.MyBooleanTrue +Write-Host "Boolean False :" $Config.MyBooleanFalse +Write-Host "Array :" "@(" (($Config.MyArray | ForEach-Object { '"{0}"' -f $_ }) -join ', ') ")" +Write-Host "Hashtable :" "@{" (($Config.MyHashtable.GetEnumerator() | ForEach-Object { '{0} = "{1}"' -f $_.Name, $_.Value }) -join '; ') "}" diff --git a/Examples/XmlConfigDemo.ps1.config b/Examples/XmlConfigDemo.ps1.config new file mode 100644 index 0000000..bf3720a --- /dev/null +++ b/Examples/XmlConfigDemo.ps1.config @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/Functions/ConvertFrom-ScriptConfigIni.ps1 b/Functions/ConvertFrom-ScriptConfigIni.ps1 new file mode 100644 index 0000000..64742f2 --- /dev/null +++ b/Functions/ConvertFrom-ScriptConfigIni.ps1 @@ -0,0 +1,99 @@ +<# +.SYNOPSIS + Convert the INI file content to a hashtable containing the configuration. + +.DESCRIPTION + Convert the INI file content to a hashtable containing the configuration. + +.PARAMETER Content + An array of strings with the INI file content. Each array item is a line. + +.EXAMPLE + C:\> Get-Content -Path 'config.ini' | ConvertFrom-ScriptConfigIni + Use the pipeline input to parse the INI file content. +#> + +function ConvertFrom-ScriptConfigIni +{ + [CmdletBinding()] + param + ( + [Parameter(Position=0, + Mandatory=$true, + ValueFromPipeline=$true)] + [AllowEmptyString()] + [String[]] $Content + ) + + Write-Verbose "Parse script configuration file as INI format ..." + + $Config = @{} + + try + { + # Iterating each line and parse the setting + foreach ($Line in $Content) + { + switch -Wildcard ($Line) + { + # Comment + ';*' { + + break + } + + # Array + '*`[`]=*'{ + $Key = $Line.Split('[]=', 4)[0] + $Value = $Line.Split('[]=', 4)[3] + + if ($null -eq $Config[$Key]) + { + $Config[$Key] = @() + } + + $Config[$Key] += $Value + + break + } + + # Hashtable + '*`[*`]=*' { + $Key = $Line.Split('[]=', 4)[0] + $Hash = $Line.Split('[]=', 4)[1] + $Value = $Line.Split('[]=', 4)[3] + + if ($null -eq $Config[$Key]) + { + $Config[$Key] = @{} + } + + $Config[$Key][$Hash] = $Value + + break + } + + # String, Integer or Boolean + '*=*' { + $Key = $Line.Split('=', 2)[0] + $Value = $Line.Split('=', 2)[1] + + try { $Value = [Int32]::Parse($Value) } catch { } + + if ('True'.Equals($Value)) { $Value = $true } + if ('False'.Equals($Value)) { $Value = $false } + + $Config[$Key] = $Value + + break + } + } + } + + Write-Output $Config + } + catch + { + throw "The configuration file content was in an invalid format: $_" + } +} diff --git a/Functions/ConvertFrom-ScriptConfigJson.ps1 b/Functions/ConvertFrom-ScriptConfigJson.ps1 new file mode 100644 index 0000000..2558775 --- /dev/null +++ b/Functions/ConvertFrom-ScriptConfigJson.ps1 @@ -0,0 +1,70 @@ +<# +.SYNOPSIS + Convert the JSON file content to a hashtable containing the configuration. + +.DESCRIPTION + Convert the JSON file content to a hashtable containing the configuration. + +.PARAMETER Content + An array of strings with the JSON file content. Each array item is a line. + +.EXAMPLE + C:\> Get-Content -Path 'config.json' | ConvertFrom-ScriptConfigJson + Use the pipeline input to parse the JSON file content. +#> + +function ConvertFrom-ScriptConfigJson +{ + [CmdletBinding()] + param + ( + [Parameter(Position=0, + Mandatory=$true, + ValueFromPipeline=$true)] + [AllowEmptyString()] + [String[]] $Content + ) + + Write-Verbose "Parse script configuration file as JSON format ..." + + $Config = @{} + + try + { + # Join all lines into one string + $Content = $Content -join '' + + # Parse the JSON content + $JsonContent = $Content | ConvertFrom-Json + + # Extract all propeties from the json content + $JsonNodes = $JsonContent | Get-Member -MemberType NoteProperty + + foreach ($JsonNode in $JsonNodes) + { + $Key = $JsonNode.Name + $Value = $JsonContent.$Key + + # Hashtable / Other + if ($Value -is [System.Management.Automation.PSCustomObject]) + { + $Config[$Key] = @{} + + foreach ($Property in $Value.PSObject.Properties) + { + $Config[$Key][$Property.Name] = $Property.Value + } + } + else + { + $Config[$Key] = $Value + } + } + + Write-Output $Config + } + catch + { + throw "The configuration file content was in an invalid format: $_" + } +} diff --git a/Functions/ConvertFrom-ScriptConfigXml.ps1 b/Functions/ConvertFrom-ScriptConfigXml.ps1 new file mode 100644 index 0000000..0850cb1 --- /dev/null +++ b/Functions/ConvertFrom-ScriptConfigXml.ps1 @@ -0,0 +1,85 @@ +<# +.SYNOPSIS + Convert the XML file content to a hashtable containing the configuration. + +.DESCRIPTION + Convert the XML file content to a hashtable containing the configuration. + +.PARAMETER Content + An array of strings with the XML file content. Each array item is a line. + +.EXAMPLE + C:\> Get-Content -Path 'config.xml' | ConvertFrom-ScriptConfigXml + Use the pipeline input to parse the XML file content. +#> + +function ConvertFrom-ScriptConfigXml +{ + [CmdletBinding()] + param + ( + [Parameter(Position=0, + Mandatory=$true, + ValueFromPipeline=$true)] + [AllowEmptyString()] + [String[]] $Content + ) + + Write-Verbose "Parse script configuration file as XML format ..." + + $Config = @{} + + try + { + # Try to cast the content into an XmlDocument + $XmlContent = [Xml] $Content + + # Extract all setting objects + $Settings = $XmlContent.Configuration.Settings.Setting + + foreach ($Setting in $Settings) + { + switch ($Setting.Type) + { + # String + 'string' { + $Config[$Setting.Key] = $Setting.Value + } + + # Integer + 'integer' { + $Config[$Setting.Key] = [Int32]::Parse($Setting.Value) + } + + # Boolean + 'boolean' { + $Config[$Setting.Key] = 'True' -eq $Setting.Value + } + + # Array + 'array' { + $Config[$Setting.Key] = @() + foreach ($Item in $Setting.Item) + { + $Config[$Setting.Key] += $Item.Value + } + } + + # Hashtable + 'hashtable' { + $Config[$Setting.Key] = @{} + foreach ($Item in $Setting.Item) + { + $Config[$Setting.Key][$Item.Key] = $Item.Value + } + } + } + } + + Write-Output $Config + } + catch + { + throw "The configuration file content was in an invalid format: $_" + } +} diff --git a/Functions/Get-ScriptConfig.ps1 b/Functions/Get-ScriptConfig.ps1 new file mode 100644 index 0000000..0a0ae15 --- /dev/null +++ b/Functions/Get-ScriptConfig.ps1 @@ -0,0 +1,73 @@ +<# +.SYNOPSIS + Load a script configuration from a config file. + +.DESCRIPTION + Load a script configuration from a config file. By default, the config file + next to the script is loaded. So for the script MyScript.ps1, the config + file MyScript.ps1.config will be loaded. By default, the script should be + in XML format. + +.PARAMETER Path + You can override the default dynamic config file path with this parameter. + +.PARAMETER Format + The default format is XML. You can override the format with this parameter. + +.EXAMPLE + C:\> $Config = Get-ScriptConfig + Loads the default XML formatted configuration file. + +.EXAMPLE + C:\> $Config = Get-ScriptConfig -Path 'C:\MyApp\global.config' + Loads a custom configuration file, with default XML format. + +.EXAMPLE + C:\> $Config = Get-ScriptConfig -Format JSON + Loads the default configuration file but in JSON format. +#> + +function Get-ScriptConfig +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory=$false)] + [ValidateScript({Test-Path -Path $_})] + $Path = $Global:MyInvocation.MyCommand.Definition.Trim() + '.config', + + [Parameter(Mandatory=$false)] + [ValidateSet('XML', 'JSON', 'INI')] + $Format = 'XML' + ) + + # Only work with absolute path, makes error handling easier + $Path = (Resolve-Path -Path $Path).Path + + Write-Verbose "Load script configuration from file $Path ..." + + # Load raw content, parse it later + $Content = Get-Content -Path $Path -ErrorAction Stop + + # Use custom functions to parse the files + switch ($Format) + { + 'XML' { + $ConfigHashtable = ConvertFrom-ScriptConfigXml -Content $Content + } + + 'JSON' { + $ConfigHashtable = ConvertFrom-ScriptConfigJson -Content $Content + } + + 'INI' { + $ConfigHashtable = ConvertFrom-ScriptConfigIni -Content $Content + } + } + + # Create a config object with a custom type + $Config = New-Object -TypeName PSObject -Property $ConfigHashtable + $Config.PSTypeNames.Insert(0, 'ScriptConfig.Configuration') + + Write-Output $Config +} diff --git a/README.md b/README.md index fe777cc..a7288a0 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,117 @@ -# ScriptConfig -PowerShell Module to handle configuration files for PowerShell Controller Scripts. +[![Build status](https://ci.appveyor.com/api/projects/status/48di0b0ml0aesj45/branch/master?svg=true)](https://ci.appveyor.com/project/claudiospizzi/scriptconfig/branch/master) [![Build status](https://ci.appveyor.com/api/projects/status/48di0b0ml0aesj45/branch/dev?svg=true)](https://ci.appveyor.com/project/claudiospizzi/scriptconfig/branch/dev) + +# ScriptConfig PowerShell Module +PowerShell Module to handle configuration files for PowerShell controller scripts. + + +## Introduction + +With the ScriptConfig module, configuration data can be loaded into a PowerShell script from a file. Thanks to the module, it is no longer necessary to hardcode or paramter-pass the configuration data. Especialy usefull for scripts, which run unattended. The module support `XML`, `JSON` and `INI` formatted config files. + + +## Requirenments + +The following minimum requirenments are necessary to use the module: + +* Windows PowerShell 3.0 +* Windows Server 2008 R2 / Windows 7 + + +## Installation + +Install the module automatically from the [PowerShell Gallery](https://www.powershellgallery.com/packages/ScriptConfig): + +```powershell +Install-Module ScriptConfig +``` + +To install the module mannually, perform the following steps: + +1. Download the latest release ([here](https://github.com/claudiospizzi/ScriptConfig/releases)) +2. Extract the downloaded module into one of the module paths (e.g. `C:\Users\[Usermame]\Documents\WindowsPowerShell\Modules`) + + +## Cmdlets + +Currently, the module has just one single cmdlet, to load the configuration file: + +| Cmdlet | Description | +| -------------------- | --------------------------------------------- | +| `Get-ScriptConfig` | Loads the configuration from a config file. | + + +## Supported Types + +The cmdlet supports multiple types. Depending on the used format, the types have to be specified differently inside the config file. + +| Type | Description | +| ----------- | -------------------------------------------------------------------- | +| String | Default: A settings is stored as a simple string. | +| Integer | If the setting is an integer, it will be casted this type. | +| Boolean | If you specify True or False, it will be casted to a boolean type. | +| Array | An array of strings can be specified. | +| Hashtable | A dictionary of key-value-pairs is supported too, both setings. | + + +## Supportet Formats + +The following formats are suppoted: `XML`, `JSON` and `INI`. + +### XML + +```xml + + + + + + + + + + + + + + + + + + + +``` + +### JSON + +```json +{ + "MyString": "This is a test JSON config file!", + "MyIntegerPositive": 42, + "MyIntegerNegative": -153, + "MyBooleanTrue": true, + "MyBooleanFalse": false, + "MyArray": [ + "Lorem", + "Ipsum" + ], + "MyHashtable": { + "Foo": "Bar", + "Hello": "World" + } +} + +``` + +### INI + +```ini +MyString=This is a test INI config file! +MyIntegerPositive=42 +MyIntegerNegative=-153 +MyBooleanTrue=True +MyBooleanFalse=False +MyArray[]=Lorem +MyArray[]=Ipsum +MyHashtable[Foo]=Bar +MyHashtable[Hello]=World +``` diff --git a/ScriptConfig.psd1 b/ScriptConfig.psd1 new file mode 100644 index 0000000..64ae0da Binary files /dev/null and b/ScriptConfig.psd1 differ diff --git a/ScriptConfig.psm1 b/ScriptConfig.psm1 new file mode 100644 index 0000000..9ac8cd3 --- /dev/null +++ b/ScriptConfig.psm1 @@ -0,0 +1,6 @@ + +# Dot source all nested functions (.ps1 files) inside the \Functions folder +Split-Path -Path $PSCommandPath | + Join-Path -ChildPath 'Functions' | + Get-ChildItem -Include '*.ps1' -Exclude '*.Tests.*' -Recurse | + ForEach-Object { . $_.FullName; } diff --git a/ScriptConfig.pssproj b/ScriptConfig.pssproj new file mode 100644 index 0000000..93c4149 --- /dev/null +++ b/ScriptConfig.pssproj @@ -0,0 +1,57 @@ + + + + Debug + 2.0 + {6cafc0c6-a428-4d30-a9f9-700e829fea51} + Exe + MyApplication + MyApplication + ScriptConfig + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ScriptConfig.sln b/ScriptConfig.sln new file mode 100644 index 0000000..84793a0 --- /dev/null +++ b/ScriptConfig.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F5034706-568F-408A-B7B3-4D38C6DB8A32}") = "ScriptConfig", "ScriptConfig.pssproj", "{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EFAC8665-F634-4593-8058-38DD51604FC9}" + ProjectSection(SolutionItems) = preProject + appveyor.yml = appveyor.yml + LICENSE = LICENSE + README.md = README.md + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Scripts/build.ps1 b/Scripts/build.ps1 new file mode 100644 index 0000000..e924e10 --- /dev/null +++ b/Scripts/build.ps1 @@ -0,0 +1,22 @@ + +# Definition for build +$Module = 'ScriptConfig' +$Source = "C:\Projects\$Module" +$Target = "C:\Program Files\WindowsPowerShell\Modules\$Module" + +# Create target module folder +New-Item -Path $Target -ItemType Directory | Out-Null + +# Copy all module items +Copy-Item -Path "$Source\Examples" -Destination $Target -Recurse +Copy-Item -Path "$Source\Functions" -Destination $Target -Recurse +Copy-Item -Path "$Source\Tests" -Destination $Target -Recurse +Copy-Item -Path "$Source\$Module.psd1" -Destination $Target +Copy-Item -Path "$Source\$Module.psm1" -Destination $Target + +# Extract module version +$ModuleVersion = (Invoke-Expression -Command (Get-Content -Path "$Target\$Module.psd1" -Raw)).ModuleVersion + +# Push appveyor artifacts +Compress-Archive -Path $Target -DestinationPath "$Source\$Module-$ModuleVersion-$env:APPVEYOR_BUILD_VERSION.zip" +Push-AppveyorArtifact -Path "$Source\$Module-$ModuleVersion-$env:APPVEYOR_BUILD_VERSION.zip" -DeploymentName $Module diff --git a/Scripts/test.ps1 b/Scripts/test.ps1 new file mode 100644 index 0000000..e1b4382 --- /dev/null +++ b/Scripts/test.ps1 @@ -0,0 +1,18 @@ + +# Definition for test +$Module = 'ScriptConfig' +$Output = "C:\Projects\$Module\TestsResults.xml" +$Target = "C:\Program Files\WindowsPowerShell\Modules\$Module" + +# Execute tests +$TestResults = Invoke-Pester -Path $Target -OutputFormat NUnitXml -OutputFile $Output -PassThru + +# Upload test result +$WebClient = New-Object -TypeName 'System.Net.WebClient' +$WebClient.UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", $Output) + +# Throw error if tests are failed +if ($TestResults.FailedCount -gt 0) +{ + throw "$($TestResults.FailedCount) tests failed." +} diff --git a/Tests/ConvertFrom-ScriptConfigIni.Tests.ps1 b/Tests/ConvertFrom-ScriptConfigIni.Tests.ps1 new file mode 100644 index 0000000..13a0bd5 --- /dev/null +++ b/Tests/ConvertFrom-ScriptConfigIni.Tests.ps1 @@ -0,0 +1,87 @@ + +# Load module +if ($Env:APPVEYOR -eq 'True') +{ + $Global:TestRoot = (Get-Module ScriptConfig -ListAvailable).ModuleBase + + Import-Module ScriptConfig -Force +} +else +{ + $Global:TestRoot = (Split-Path -Parent $MyInvocation.MyCommand.Path | Join-Path -ChildPath '..' | Resolve-Path).Path + + Import-Module "$Global:TestRoot\ScriptConfig.psd1" -Force +} + +# Execute tests +InModuleScope ScriptConfig { + + Describe 'ConvertFrom-ScriptConfigIni' { + + $ResultString = 'This is a test INI config file!' + $ResultIntegerPositive = 42 + $ResultIntegerNegative = -153 + $ResultBooleanTrue = $true + $ResultBooleanFalse = $false + $ResultArray = @( 'Lorem', 'Ipsum' ) + $ResultHashtable = @{ Foo = 'Bar'; Hello = 'World' } + + $Content = Get-Content -Path "$Global:TestRoot\Examples\IniConfigDemo.ps1.config" + + It 'should be able to convert the example config file' { + + $Config = ConvertFrom-ScriptConfigIni -Content $Content + + $Config | Should Not BeNullOrEmpty + } + + It 'shloud be able to parse a string' { + + $Config = ConvertFrom-ScriptConfigIni -Content $Content + + $Config.MyString | Should Be $ResultString + $Config.MyString.GetType() | Should Be ([System.String]) + } + + It 'shloud be able to parse an integer' { + + $Config = ConvertFrom-ScriptConfigIni -Content $Content + + $Config.MyIntegerPositive | Should Be $ResultIntegerPositive + $Config.MyIntegerPositive.GetType() | Should Be ([System.Int32]) + + $Config.MyIntegerNegative | Should Be $ResultIntegerNegative + $Config.MyIntegerNegative.GetType() | Should Be ([System.Int32]) + } + + It 'shloud be able to parse an boolean' { + + $Config = ConvertFrom-ScriptConfigIni -Content $Content + + $Config.MyBooleanTrue | Should Be $ResultBooleanTrue + $Config.MyBooleanTrue.GetType() | Should Be ([System.Boolean]) + + $Config.MyBooleanFalse | Should Be $ResultBooleanFalse + $Config.MyBooleanFalse.GetType() | Should Be ([System.Boolean]) + } + + It 'shloud be able to parse an array' { + + $Config = ConvertFrom-ScriptConfigIni -Content $Content + + $Config.MyArray | Should Not BeNullOrEmpty + $Config.MyArray | Should Be $ResultArray + $Config.MyArray.GetType() | Should Be ([System.Object[]]) + } + + It 'shloud be able to parse an hashtable' { + + $Config = ConvertFrom-ScriptConfigIni -Content $Content + + $Config.MyHashtable | Should Not BeNullOrEmpty + $Config.MyHashtable.Keys | Should Be $ResultHashtable.Keys + $Config.MyHashtable.Values | Should Be $ResultHashtable.Values + $Config.MyHashtable.GetType() | Should Be ([System.Collections.Hashtable]) + } + } +} diff --git a/Tests/ConvertFrom-ScriptConfigJson.Tests.ps1 b/Tests/ConvertFrom-ScriptConfigJson.Tests.ps1 new file mode 100644 index 0000000..bc0c511 --- /dev/null +++ b/Tests/ConvertFrom-ScriptConfigJson.Tests.ps1 @@ -0,0 +1,87 @@ + +# Load module +if ($Env:APPVEYOR -eq 'True') +{ + $Global:TestRoot = (Get-Module ScriptConfig -ListAvailable).ModuleBase + + Import-Module ScriptConfig -Force +} +else +{ + $Global:TestRoot = (Split-Path -Parent $MyInvocation.MyCommand.Path | Join-Path -ChildPath '..' | Resolve-Path).Path + + Import-Module "$Global:TestRoot\ScriptConfig.psd1" -Force +} + +# Execute tests +InModuleScope ScriptConfig { + + Describe 'ConvertFrom-ScriptConfigJson' { + + $ResultString = 'This is a test JSON config file!' + $ResultIntegerPositive = 42 + $ResultIntegerNegative = -153 + $ResultBooleanTrue = $true + $ResultBooleanFalse = $false + $ResultArray = @( 'Lorem', 'Ipsum' ) + $ResultHashtable = @{ Foo = 'Bar'; Hello = 'World' } + + $Content = Get-Content -Path "$Global:TestRoot\Examples\JsonConfigDemo.ps1.config" + + It 'should be able to convert the example config file' { + + $Config = ConvertFrom-ScriptConfigJson -Content $Content + + $Config | Should Not BeNullOrEmpty + } + + It 'shloud be able to parse a string' { + + $Config = ConvertFrom-ScriptConfigJson -Content $Content + + $Config.MyString | Should Be $ResultString + $Config.MyString.GetType() | Should Be ([System.String]) + } + + It 'shloud be able to parse an integer' { + + $Config = ConvertFrom-ScriptConfigJson -Content $Content + + $Config.MyIntegerPositive | Should Be $ResultIntegerPositive + $Config.MyIntegerPositive.GetType() | Should Be ([System.Int32]) + + $Config.MyIntegerNegative | Should Be $ResultIntegerNegative + $Config.MyIntegerNegative.GetType() | Should Be ([System.Int32]) + } + + It 'shloud be able to parse an boolean' { + + $Config = ConvertFrom-ScriptConfigJson -Content $Content + + $Config.MyBooleanTrue | Should Be $ResultBooleanTrue + $Config.MyBooleanTrue.GetType() | Should Be ([System.Boolean]) + + $Config.MyBooleanFalse | Should Be $ResultBooleanFalse + $Config.MyBooleanFalse.GetType() | Should Be ([System.Boolean]) + } + + It 'shloud be able to parse an array' { + + $Config = ConvertFrom-ScriptConfigJson -Content $Content + + $Config.MyArray | Should Not BeNullOrEmpty + $Config.MyArray | Should Be $ResultArray + $Config.MyArray.GetType() | Should Be ([System.Object[]]) + } + + It 'shloud be able to parse an hashtable' { + + $Config = ConvertFrom-ScriptConfigJson -Content $Content + + $Config.MyHashtable | Should Not BeNullOrEmpty + $Config.MyHashtable.Keys | Should Be $ResultHashtable.Keys + $Config.MyHashtable.Values | Should Be $ResultHashtable.Values + $Config.MyHashtable.GetType() | Should Be ([System.Collections.Hashtable]) + } + } +} diff --git a/Tests/ConvertFrom-ScriptConfigXml.Tests.ps1 b/Tests/ConvertFrom-ScriptConfigXml.Tests.ps1 new file mode 100644 index 0000000..3716426 --- /dev/null +++ b/Tests/ConvertFrom-ScriptConfigXml.Tests.ps1 @@ -0,0 +1,87 @@ + +# Load module +if ($Env:APPVEYOR -eq 'True') +{ + $Global:TestRoot = (Get-Module ScriptConfig -ListAvailable).ModuleBase + + Import-Module ScriptConfig -Force +} +else +{ + $Global:TestRoot = (Split-Path -Parent $MyInvocation.MyCommand.Path | Join-Path -ChildPath '..' | Resolve-Path).Path + + Import-Module "$Global:TestRoot\ScriptConfig.psd1" -Force +} + +# Execute tests +InModuleScope ScriptConfig { + + Describe 'ConvertFrom-ScriptConfigXml' { + + $ResultString = 'This is a test XML config file!' + $ResultIntegerPositive = 42 + $ResultIntegerNegative = -153 + $ResultBooleanTrue = $true + $ResultBooleanFalse = $false + $ResultArray = @( 'Lorem', 'Ipsum' ) + $ResultHashtable = @{ Foo = 'Bar'; Hello = 'World' } + + $Content = Get-Content -Path "$Global:TestRoot\Examples\XmlConfigDemo.ps1.config" + + It 'should be able to convert the example config file' { + + $Config = ConvertFrom-ScriptConfigXml -Content $Content + + $Config | Should Not BeNullOrEmpty + } + + It 'shloud be able to parse a string' { + + $Config = ConvertFrom-ScriptConfigXml -Content $Content + + $Config.MyString | Should Be $ResultString + $Config.MyString.GetType() | Should Be ([System.String]) + } + + It 'shloud be able to parse an integer' { + + $Config = ConvertFrom-ScriptConfigXml -Content $Content + + $Config.MyIntegerPositive | Should Be $ResultIntegerPositive + $Config.MyIntegerPositive.GetType() | Should Be ([System.Int32]) + + $Config.MyIntegerNegative | Should Be $ResultIntegerNegative + $Config.MyIntegerNegative.GetType() | Should Be ([System.Int32]) + } + + It 'shloud be able to parse an boolean' { + + $Config = ConvertFrom-ScriptConfigXml -Content $Content + + $Config.MyBooleanTrue | Should Be $ResultBooleanTrue + $Config.MyBooleanTrue.GetType() | Should Be ([System.Boolean]) + + $Config.MyBooleanFalse | Should Be $ResultBooleanFalse + $Config.MyBooleanFalse.GetType() | Should Be ([System.Boolean]) + } + + It 'shloud be able to parse an array' { + + $Config = ConvertFrom-ScriptConfigXml -Content $Content + + $Config.MyArray | Should Not BeNullOrEmpty + $Config.MyArray | Should Be $ResultArray + $Config.MyArray.GetType() | Should Be ([System.Object[]]) + } + + It 'shloud be able to parse an hashtable' { + + $Config = ConvertFrom-ScriptConfigXml -Content $Content + + $Config.MyHashtable | Should Not BeNullOrEmpty + $Config.MyHashtable.Keys | Should Be $ResultHashtable.Keys + $Config.MyHashtable.Values | Should Be $ResultHashtable.Values + $Config.MyHashtable.GetType() | Should Be ([System.Collections.Hashtable]) + } + } +} diff --git a/Tests/Get-ScriptConfig.Tests.ps1 b/Tests/Get-ScriptConfig.Tests.ps1 new file mode 100644 index 0000000..8a810a7 --- /dev/null +++ b/Tests/Get-ScriptConfig.Tests.ps1 @@ -0,0 +1,107 @@ + +# Load module +if ($Env:APPVEYOR -eq 'True') +{ + $Global:TestRoot = (Get-Module ScriptConfig -ListAvailable).ModuleBase + + Import-Module ScriptConfig -Force +} +else +{ + $Global:TestRoot = (Split-Path -Parent $MyInvocation.MyCommand.Path | Join-Path -ChildPath '..' | Resolve-Path).Path + + Import-Module "$Global:TestRoot\ScriptConfig.psd1" -Force +} + +# Execute tests +Describe 'Get-ScriptConfig' { + + Context 'Result' { + + $ResultStringIni = 'This is a test INI config file!' + $ResultStringJson = 'This is a test JSON config file!' + $ResultStringXml = 'This is a test XML config file!' + $ResultIntegerPositive = 42 + $ResultIntegerNegative = -153 + $ResultBooleanTrue = $true + $ResultBooleanFalse = $false + $ResultArray = @( 'Lorem', 'Ipsum' ) + $ResultHashtable = @{ Foo = 'Bar'; Hello = 'World' } + + It 'shloud be able to load a valid INI configuration file' { + + $Config = Get-ScriptConfig -Path "$Global:TestRoot\Examples\IniConfigDemo.ps1.config" -Format INI + + $Config | Should Not BeNullOrEmpty + + $Config.MyString | Should Be $ResultStringIni + $Config.MyIntegerPositive | Should Be $ResultIntegerPositive + $Config.MyIntegerNegative | Should Be $ResultIntegerNegative + $Config.MyBooleanTrue | Should Be $ResultBooleanTrue + $Config.MyBooleanFalse | Should Be $ResultBooleanFalse + $Config.MyArray | Should Be $ResultArray + $Config.MyHashtable.Keys | Should Be $ResultHashtable.Keys + $Config.MyHashtable.Values | Should Be $ResultHashtable.Values + } + + It 'shloud be able to load a valid JSON configuration file' { + + $Config = Get-ScriptConfig -Path "$Global:TestRoot\Examples\JsonConfigDemo.ps1.config" -Format JSON + + $Config | Should Not BeNullOrEmpty + + $Config.MyString | Should Be $ResultStringJson + $Config.MyIntegerPositive | Should Be $ResultIntegerPositive + $Config.MyIntegerNegative | Should Be $ResultIntegerNegative + $Config.MyBooleanTrue | Should Be $ResultBooleanTrue + $Config.MyBooleanFalse | Should Be $ResultBooleanFalse + $Config.MyArray | Should Be $ResultArray + $Config.MyHashtable.Keys | Should Be $ResultHashtable.Keys + $Config.MyHashtable.Values | Should Be $ResultHashtable.Values + } + + It 'shloud be able to load a valid XML configuration file' { + + $Config = Get-ScriptConfig -Path "$Global:TestRoot\Examples\XmlConfigDemo.ps1.config" -Format XML + + $Config | Should Not BeNullOrEmpty + + $Config.MyString | Should Be $ResultStringXml + $Config.MyIntegerPositive | Should Be $ResultIntegerPositive + $Config.MyIntegerNegative | Should Be $ResultIntegerNegative + $Config.MyBooleanTrue | Should Be $ResultBooleanTrue + $Config.MyBooleanFalse | Should Be $ResultBooleanFalse + $Config.MyArray | Should Be $ResultArray + $Config.MyHashtable.Keys | Should Be $ResultHashtable.Keys + $Config.MyHashtable.Values | Should Be $ResultHashtable.Values + } + } + + Context 'Format' { + + Mock ConvertFrom-ScriptConfigIni { return @{} } -ModuleName ScriptConfig + Mock ConvertFrom-ScriptConfigJson { return @{} } -ModuleName ScriptConfig + Mock ConvertFrom-ScriptConfigXml { return @{} } -ModuleName ScriptConfig + + It 'should call the INI function if INI foramt is specified' { + + $Config = Get-ScriptConfig -Path "$Global:TestRoot\Examples\IniConfigDemo.ps1.config" -Format INI + + Assert-MockCalled 'ConvertFrom-ScriptConfigIni' -ModuleName ScriptConfig -Times 1 -Exactly + } + + It 'should call the JSON function if JSON foramt is specified' { + + $Config = Get-ScriptConfig -Path "$Global:TestRoot\Examples\JsonConfigDemo.ps1.config" -Format JSON + + Assert-MockCalled 'ConvertFrom-ScriptConfigJson' -ModuleName ScriptConfig -Times 1 -Exactly + } + + It 'should call the XML function if XML foramt is specified' { + + $Config = Get-ScriptConfig -Path "$Global:TestRoot\Examples\XmlConfigDemo.ps1.config" -Format XML + + Assert-MockCalled 'ConvertFrom-ScriptConfigXml' -ModuleName ScriptConfig -Times 1 -Exactly + } + } +} diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..1022ac5 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,21 @@ + +# PowerShell 5.0 Image +os: WMF 5 + +# Clone Directory +clone_folder: C:\Projects\ScriptConfig + +# Install Pester +install: + - cinst -y pester --version 3.3.14 + +# Build Number +version: '{build}' + +# Execute build script +build_script: +- ps: .\Scripts\build.ps1 + +# Execute test script +test_script: +- ps: .\Scripts\test.ps1