Gears

Using ScriptConfig to enhance PowerShell Controller Scripts

If you are creating PowerShell Controller scripts, you often have to deal with constant configuration value. As an example, you create a script called “New-CorporateUser” for creating new user account, enable the mailbox and initialize the permissions on user home shares in your company. For this script, you will have two different types of input values:

  • Input values which change with every new user, like his name or employee id
  • Input values which are static for the target system over a long time, like the domain name or the mailbox servers

For input values which change with every execution, you will use the native PowerShell param() block to provide them as parameters to your script. They will be set every time you execute your script. But what about the static values – it’s not reasonable to pass them as parameters too: Hard-code them somewhere in the script? Initialize configuration variables on top of the script? Use parameters with default values?

In any case, you have to change your script, if any of the static configuration values changes. When you use version control, which you by the way should at least for scripts in production, you will end up with a new version of your script every time a static value changes. Maybe this is what you are looking for – but, if not, have a look at my ScriptConfig module.

The goal behind this ScriptConfig module is to separate the actual code and the configuration data. While the actual codes exists inside the .ps1 script file and it’s depended modules, the configuration lays right next to your controller script in a dedicated configuration file. I’ve re-used the concept of application configuration files from .NET for PowerShell, but with a different file format. The module currently contains just one simple cmdlet: Get-ScriptConfig.

Install and use ScriptConfig module

First, get the ScriptConfig module from my GitHub repo or with PowerShell 5, you can install it directly from the PowerShell Gallery:

Install-Module ScriptConfig

Now, as the ScriptConfig module is installed on your system, you are able to integrate it into your scripts. In the following code snipped, you can find an example how you can leverage a configuration file for the demo script New-CorporateUser.ps1 and use the configuration values next to the parameters for adding a new user account to the domain. I recommend the #Requires -Modules <ModuleName> statement on the top of your scripts, because then you are sure, that all depended modules are installed on the local system.

#Requires -Modules ScriptConfig, ActiveDirectory

param
(
    [Parameter(Position=0,Mandatory=$true)]
    [String] $Account,

    [Parameter(Position=1,Mandatory=$true)]
    [String] $GivenName,

    [Parameter(Position=2,Mandatory=$true)]
    [String] $Surname
)

# Load script configuration
$Config = Get-ScriptConfig -Path "$PSScriptRoot\New-CorporateUser.ps1.config" -Format JSON

# Create active diretory user
$ADUserAttribute = @{
    Name              = "{0} {1}" -f $Surname, $GivenName
    Path              = $Config.UserOU
    SamAccountName    = $Account
    UserPrincipalName = "{0}@{1}" -f $Account, $Config.UserUPN

    DisplayName       = "{0} {1}" -f $Surname, $GivenName
    GivenName         = $GivenName
    Surname           = $Surname
}
New-ADUser @ADUserAttribute 

# Add user to groups
foreach ($Group in $Config.Groups)
{
    Add-ADGroupMember -Identity $Group -Members $Account
}

The script loads the configuration on line 16 from the specified configuration file. The format of the configuration file must be specified with the -Format parameter. The function does not guess depending on the file extension, what format it should use. Afterwards, the configuration is available inside the $Config variable as a ScriptConfig.Configuration object, which is basically a simple PSCustomObject with the configuration values as note properties. You can access the configuration values by using the dot-notation.

The ScriptConfig module supports multiple types as configuration values. They are all supported with any available configration file format:

  • String
    All settings are stored as a string values by default.
  • Integer
    If the setting value is a valid integer, it will be casted into an integer.
  • Boolean
    By specifying the key words 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. The key and values will be a string.

Configuration File Formats: JSON, XML, INI

The module accepts different config file format. Currently it’s JSON, XML and INI. But it can be easily extended. To support all value types as specified in the previous list, the format is specified tightly. In the following you will find an example for each file format which matches the New-CorporateUser.ps1 script.

The XML schema is tightly specified and does not exactily match with the application configuration files from .NET. The XML config file is the safest but also must verbose option, because everything is specified including the type:

<?xml version="1.0" encoding="utf-8"?>
<Configuration>
    <Settings>
        <Setting Type="string" Key="UserOU" Value="OU=CorpUsers,DC=contoso,DC=com" />
        <Setting Type="string" Key="UserUPN" Value="contoso.com" />
        <Setting Type="array" Key="Groups">
            <Item Value="All Employees" />
            <Item Value="Intranet Access" />
        </Setting>
    </Settings>
</Configuration>

JSON config files support the different types like arrays and hashtables out of the box. Be aware, deeper configuration values are not supported

{
  "UserOU": "OU=Test,DC=spizzi,DC=work",
  "UserUPN": "spizzi.work",
  "Groups":  [
               "All Employees",
               "Intranet Access"
             ]
}

The last supported format is an INI file. Because the core INI file specification does not provide support for arrays or hashtable, I’ve introduced the use of [ and ] to support these types.

UserOU=OU=CorpUsers,DC=contoso,DC=com
UserUPN=contoso.com
Groups[]=All Employees
Groups[]=Intranet Access

Conclusion

With the ScriptConfig module you are able to separate configuration values from actual code. It’s compatible back to Windows PowerShell 3.0. Thanks to the module you can start to develop a controller script right away without bother the configuration file handling. If you need more information, have a lock at the GitHub repository: ScriptConfig.

Leave a Reply

Your email address will not be published. Required fields are marked *