DSCResources/cIniFile/cIniFile.psm1
Enum Ensure{ Absent Present } function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [parameter(Mandatory = $false)] [ValidateSet("Present","Absent")] [System.String] $Ensure = 'Present', [parameter(Mandatory = $true)] [System.String] $Path, [parameter(Mandatory = $true)] [AllowEmptyString()] [System.String] $Key, [parameter(Mandatory = $true)] [AllowEmptyString()] [System.String] $Value, [parameter(Mandatory = $true)] [AllowEmptyString()] [System.String] $Section = '_ROOT_', [parameter()] [Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding] $Encoding = 'UTF8' ) if(-not $Section){$Section = '_ROOT_'} [string]$tmpValue = '' # check file exists if(-not (Test-Path $Path -PathType Leaf)){ Write-Verbose ('File "{0}" not found.' -f $Path) $Ensure = [Ensure]::Absent } else{ #Load ini file $Ini = Get-IniFile -Path $Path -Encoding $Encoding # if $key is empty, only check section if(-not $Key){ if($Ini.$Section){ Write-Verbose ('Desired Section found ([{0}])' -f $Section) $Ensure = [Ensure]::Present } else{ Write-Verbose ('Desired Section NOT found ([{0}])' -f $Section) $Ensure = [Ensure]::Absent } } # check section and key exists elseif($tmpValue = $Ini.$Section.$key){ # check value Write-Verbose ('Current KVP (Key:"{0}"; Value:"{1}"; Section:"{2}")' -f $Key, $tmpValue, $Section) if($Value -ceq $tmpValue){ $Ensure = [Ensure]::Present } else{ $Ensure = [Ensure]::Absent } } else{ Write-Verbose ('Desired Key or Section not found.') $Ensure = [Ensure]::Absent } } $returnValue = @{ Ensure = $Ensure Path = $Path Key = $Key Value = $tmpValue Section = $PSBoundParameters.Section } $returnValue } # end of Get-TargetResource function Set-TargetResource { param ( [parameter(Mandatory = $false)] [ValidateSet("Present","Absent")] [System.String] $Ensure = 'Present', [parameter(Mandatory = $true)] [System.String] $Path, [parameter(Mandatory = $true)] [AllowEmptyString()] [System.String] $Key, [parameter(Mandatory = $true)] [AllowEmptyString()] [System.String] $Value, [parameter(Mandatory = $true)] [AllowEmptyString()] [System.String] $Section = '_ROOT_', [parameter()] [Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding] $Encoding = 'UTF8' ) if(-not $Section){$Section = '_ROOT_'} # Ensure = "Absent" if($Ensure -eq [Ensure]::Absent){ if(Test-Path $Path){ Write-Verbose ("Remove Key:{0}; Section:{1} from '{2}'" -f $Key, $Section, $Path) $content = Get-IniFile -Path $Path -Encoding $Encoding | Remove-IniKey -Key $Key -Section $Section -PassThru | Out-IniString $content | Out-File -FilePath $Path -Encoding $Encoding -Force } } else{ # Ensure = "Present" $Ini = [ordered]@{} if(Test-Path $Path){ $Ini = Get-IniFile -Path $Path -Encoding $Encoding } else{ Write-Verbose ("Create new file '{0}'" -f $Path) New-Item $Path -ItemType File -Force } $content = $Ini | Set-IniKey -Key $Key -Value $Value -Section $Section -PassThru | Out-IniString $content | Out-File -FilePath $Path -Encoding $Encoding -Force } } # end of Set-TargetResource function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [parameter(Mandatory = $false)] [ValidateSet("Present","Absent")] [System.String] $Ensure = 'Present', [parameter(Mandatory = $true)] [System.String] $Path, [parameter(Mandatory = $true)] [AllowEmptyString()] [System.String] $Key, [parameter(Mandatory = $true)] [AllowEmptyString()] [System.String] $Value, [parameter(Mandatory = $true)] [AllowEmptyString()] [System.String] $Section = '_ROOT_', [parameter()] [Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding] $Encoding = 'UTF8' ) if(-not $Section){$Section = '_ROOT_'} $cState = (Get-TargetResource @PSBoundParameters) $ret = $cState.Ensure -eq $Ensure if($ret){ Write-Verbose ('Test Passed. Nothing needs to do') } else{ Write-Verbose "Test NOT Passed." } return $ret } # end of Test-TargetResource function Get-IniFile { [CmdletBinding()] param ( # Set Target full path to INI [Parameter(Position = 0, Mandatory, ValueFromPipeline)] [validateScript({Test-Path $_})] [Alias('File')] [string] $Path, # specify file encoding [Parameter()] [Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding] $Encoding = "ASCII" ) process { # Write-Verbose ("Loading file from {0}" -f $Path) $Content = Get-Content -Path $Path -Encoding $Encoding $CurrentSection = '_ROOT_' [System.Collections.Specialized.OrderedDictionary]$IniHash = [ordered]@{} $IniHash.Add($CurrentSection, [ordered]@{}) foreach($line in $Content){ $line = $line.Trim() if($line -match '^;'){ # Write-Verbose ("Comment") $line = ($line.split(';')[0]).Trim() } if($line -match '^\[(.+)\]'){ # Section $CurrentSection = $Matches[1] if(-not $IniHash.Contains($CurrentSection)){ # Write-Verbose ('Add Section. Section: {0}' -f $Matches[1]) $IniHash.Add($CurrentSection, [ordered]@{}) } } elseif($line -match '='){ #KeyValuePair $idx = $line.IndexOf('=') [string]$key = $line.Substring(0,$idx) [string]$value = $line.Substring($idx+1) # Write-Verbose ('Add KVP. Key: {0}, Value: {1}, Section: {2}' -f $key,$value,$CurrentSection) $IniHash.$CurrentSection.$key = $value } } $IniHash } } function Out-IniString { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory, ValueFromPipeline)] [System.Collections.Specialized.OrderedDictionary] $InputObject ) Process{ [string[]]$IniString = @() if($InputObject.Contains('_ROOT_')){ if($InputObject.'_ROOT_' -as [hashtable]){ $private:Keys = $InputObject.'_ROOT_' $Keys.Keys.ForEach({ $IniString += ('{0}={1}' -f $_, $Keys.$_) }) } } foreach($Section in $InputObject.keys){ if(-not ($Section -eq '_ROOT_')){ if($InputObject.$Section -as [hashtable]){ $IniString += ('[{0}]' -f $Section) $private:Keys = $InputObject.$Section $Keys.Keys.ForEach({ $IniString += ('{0}={1}' -f $_, $Keys.$_) }) } } } $IniString } } function Set-IniKey { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory, ValueFromPipeline)] [System.Collections.Specialized.OrderedDictionary] $InputObject, [Parameter(Mandatory)] [AllowEmptyString()] [string]$Key, [Parameter(Mandatory)] [AllowEmptyString()] [string]$Value, [Parameter()] [string]$Section = '_ROOT_', [switch]$PassThru ) Process{ if($InputObject.Contains($Section)){ if($Key){ if($InputObject.$Section.Contains($Key)){ Write-Verbose ("Update value. Key:'{0}'; Value:'{1}'; Section:'{2}'" -f $key, $Value, $Section) $InputObject.$Section.$Key = $Value } else{ Write-Verbose ("Set value. Key:'{0}'; Value:'{1}'; Section:'{2}'" -f $key, $Value, $Section) $InputObject.$Section.Add($Key, $Value) } } } else{ $InputObject.Add($Section, [System.Collections.Specialized.OrderedDictionary]@{}) if($Key){ Write-Verbose ("Set value. Key:'{0}'; Value:'{1}'; Section:'{2}'" -f $key, $Value, $Section) $InputObject.$Section.Add($Key, $Value) } } if($PassThru){ $InputObject } } } function Remove-IniKey { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory, ValueFromPipeline)] [System.Collections.Specialized.OrderedDictionary] $InputObject, [parameter(Mandatory)] [AllowEmptyString()] [string]$Key, [parameter()] [string]$Section = '_ROOT_', [switch]$PassThru ) Process{ if($InputObject.Contains($Section)){ if($Key){ if($InputObject.$Section.Contains($Key)){ $InputObject.$Section.Remove($key) } } else{ $InputObject.Remove($Section) } } if($PassThru){ $InputObject } } } Export-ModuleMember -Function *-TargetResource |