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

Topics: Archive - Toolkit Extensions
Developer
Jul 9, 2014 at 11:53 PM
Edited Jul 31, 2014 at 3:07 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 Set-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 Set-IniValue
{
<#
    .SYNOPSIS
        Opens an ini file and sets the value of the specified section and key
    .DESCRIPTION
        Opens an ini file and sets the value of the specified section and key
    .EXAMPLE
        Set-IniValue -FilePath "$envProgramFilesX86\IBM\Notes\notes.ini" -Section "Notes" -Key "KeyFileName" -Value "MyFile.ID"
    .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 Value
        Value for the 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,
        [String] $Value, #To remove a value, set this variable to $null
        [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 SetIniValue
        {
            [DllImport("kernel32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool WritePrivateProfileString(
               string lpAppName,
               string lpKeyName,
               StringBuilder lpString, // Don't use string, as Powershell replaces $null with an empty string
               string lpFileName);
        }
"@
        If (-not ([System.Management.Automation.PSTypeName]'SetIniValue').Type)
        {
            Add-Type -TypeDefinition $source -Language CSharp
        }
    }
    Process
    {
        If (Test-Path $FilePath)
        {
            [SetIniValue]::WritePrivateProfileString($Section, $Key, $Value, $FilePath) | Out-Null
            
            Write-Log -Message "Write INI :: Section: $Section, Key: $Key, Value: $Value" -Component ${CmdletName} -Severity 1
        }
        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
    }
}