Search code examples
powershellglobal-variablessettingsproject-structurepowershell-module

PowerShell project, where to put global settings?


We are building a bigger project with PowerShell (a collection of scripts/functions that helps us setup some SharePoint environments/tenants).

A lot of the functions should reuse settings that are stored in a single, central place.

I couldn't find a "best practice" of how such a settings file/location should be best created and structured.

My idea is to store global settings in a separate file (a module file), for example Settings.psm1 with content like this:

# Set vars
$global:scriptEnvironment = "SP2016HOSTINGDEV"
$global:logFileName = "z_Migration_to_SP2016.log"
$global:languageMapping = @{
    "en-US" = 1;
    "de-DE" = 2;
}
$global:oldWsps = @(
    [WspFile]@{ Filename = "comapany.solution.wsp"; IsDeployable = $true; IsGloballyDeployable = $false; FullTrustBinDeployment = $false },
    [WspFile]@{ Filename = "company.solution2.server.wsp"; IsDeployable = $true; IsGloballyDeployable = $false; FullTrustBinDeployment = $false }
)
...

And in the other modules/scripts I then could always include those settings like this:

# Set vars
$scriptDirectory = Split-Path -parent $PSCommandPath

# Module import
Import-Module (Join-Path $scriptDirectory Settings.psm1) -Force -ErrorAction Stop
Import-Module (Join-Path $scriptDirectory Functions.psm1) -Force -ErrorAction Stop

# Functions
...

So this would make me able to use the global settings like this in the functions inside other script files:

Function WriteLog
{
    param
    (
        [System.String]$LogString = "",
        [System.String]$LogLevel = ""
    )
    WriteLogToPath -LogFileName $global:logFileName -LogString $LogString -LogLevel $LogLevel
}

Is this a good approach? Or shouldn't I use module files for this and if not what kind of files should I use instead?


Solution

  • I would probably collect all your scripts/functions in a module and use the registry to store the global settings. Read the values from the registry when the module is loaded, and have variables with default values for each setting in your module so that you can write missing values to the registry.

    Something like this:

    $modulename = Split-Path $PSScriptRoot -Leaf
    
    $default_foo = 'something'
    $default_bar = 'or other'
    ...
    
    function Get-RegistrySetting($name) {
        $path = "HKCU:\Software\${script:modulename}"
    
        if (-not (Test-Path -LiteralPath $path)) {
            New-Item -Path $path -Force | Out-Null
        }
    
        try {
            Get-ItemProperty $path -Name $name -ErrorAction Stop |
                Select-Object -Expand $name
        } catch {
            $val = Get-Variable -Scope script -Name "default_${name}" -ValueOnly -ErrorAction Stop
            Set-ItemProperty $path -Name $name -Value $val
            $val
        }
    }
    
    $global:foo = Get-RegistrySetting 'foo'
    $global:bar = Get-RegistrySetting 'bar'
    ...
    

    For variables you only use inside your module you may want to use the script scope instead of the global scope.