Get-IniValue: Updated function to check for custom Add-Type before adding to avoid errors

Topics: Archive - Toolkit Extensions
Developer
Jul 9, 2014 at 10:50 PM
Edited Jul 31, 2014 at 2:05 AM
If you are like me, you have one functions library and use it for all of your scripts. If you are calling one script from another or executing multiple scripts in the same PowerShell console, you will get Add-Type errors if you try to use a function that adds a custom type. The error states that the custom type already exists and cannot be added again.

I have updated the Get-IniValue function to avoid this problem. I am also using a custom logging function I wrote which is posted in another thread in this forum.
Function Get-IniValue
{
<#
    .SYNOPSIS
        Parses an ini file and returns the value of the specified section and key
    .DESCRIPTION
        Parses an ini file and returns the value of the specified section and key
    .EXAMPLE
        Get-IniValue -FilePath "$envProgramFilesX86\IBM\Notes\notes.ini" -Section "Notes" -Key "KeyFileName"
    .PARAMETER FilePath
        Path to the ini file
    .PARAMETER Section
        Section within the ini file
    .PARAMETER Key
        Key within the section of the ini file
    .PARAMETER ContinueOnError
        Continue if an error is encountered
    .NOTES
#>
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory = $true)]
        [string]$FilePath,
        [string]$Section,
        [string]$Key,
        [boolean]$ContinueOnError = $false
    )
    Begin
    {
        ${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name
        $PSParameters = New-Object -TypeName PSObject -Property $PSBoundParameters
        
        Write-Log -Message "Function Start" -Component ${CmdletName} -Severity 1
        If (-not [string]::IsNullOrEmpty($PSParameters))
        {
            Write-Log -Message "Function invoked with bound parameters [$PSParameters]" -Component ${CmdletName} -Severity 1
        }
        Else
        {
            Write-Log -Message "Function invoked without any bound parameters" -Component ${CmdletName} -Severity 1
        }
        
        $source = @"
        using System;
        using System.Text;
        using System.Runtime.InteropServices;
        
        public sealed class GetIniValue
        {
            [DllImport("kernel32.dll")]
            public static extern uint GetPrivateProfileString(
               string lpAppName,
               string lpKeyName,
               string lpDefault,
               StringBuilder lpReturnedString,
               uint nSize,
               string lpFileName);
        }
"@
        If (-not ([System.Management.Automation.PSTypeName]'GetIniValue').Type)
        {
            Add-Type -TypeDefinition $source -Language CSharp
        }
    }
    Process
    {
        If (Test-Path $FilePath)
        {
            $builder = New-Object -TypeName System.Text.StringBuilder -ArgumentList 1024
            [GetIniValue]::GetPrivateProfileString($Section, $Key, "", $builder, $builder.Capacity, $FilePath) | Out-Null
            $inivalue = $builder.ToString()
            Write-Log -Message "Read INI :: Section: $Section, Key: $Key, Value: $inivalue" -Component ${CmdletName} -Severity 1
            Return $inivalue
        }
        Else
        {
            If ($ContinueOnError -eq $true)
            {
                Write-Log -Message "File [$filePath] could not be found." -Component ${CmdletName} -Severity 3
                Continue
            }
            Else
            {
                Write-Log -Message "File [$filePath] could not be found." -Component ${CmdletName} -Severity 3
                Exit
            }
        }
    }
    End
    {
        Write-Log -Message "Function End" -Component ${CmdletName} -Severity 1
    }
}