Created
December 2, 2023 14:14
-
-
Save PanosGreg/76f85323296d2a453d1f7a31523143a3 to your computer and use it in GitHub Desktop.
Microsoft.Extensions.Configuration in PowerShell
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## Drilling down into the Microsoft.Extensions.Configuration namespace from a PowerShell point-of-view | |
## Note: the inspiration for this came up by watching a .net video about configuration from Chris Ayers | |
# [.NET Configuration In Depth | .NET Conf 2023](https://www.youtube.com/watch?v=aOXaBZFB0-0) | |
## How to load a .dll which has some dependencies | |
## you just have to get the package from nuget which will also retrieve all of the dependencies | |
## We'll be using the Microsoft.Extensions.Configuration namespace | |
## by default the namespace and its classes, don't exist in the current session | |
## so we need to load it, but from where ? | |
## in this case we can simply just create a new CS class project and add the package | |
## and then compile it. This will give us the .dlls we need to load in PowerShell | |
## for example | |
cd D:\Temp | |
cd (md scratch) | |
dotnet new classlib | |
dotnet add package Microsoft.Extensions.Configuration.Json | |
dotnet publish | |
Add-Type -Path D:\Temp\scratch\bin\Debug\net7.0\publish\Microsoft.Extensions.Configuration.dll | |
Add-Type -Path D:\Temp\scratch\bin\Debug\net7.0\publish\Microsoft.Extensions.Configuration.Json.dll | |
# or whatever target framework (the net7.0) is just an example in my case when I run that command | |
# instantiate the builder class | |
$bld = [Microsoft.Extensions.Configuration.ConfigurationBuilder]::new() | |
# source: https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.configurationbuilder?view=dotnet-plat-ext-8.0 | |
# create a json file as an example | |
[pscustomobject]@{Name='aa';Count=10} | ConvertTo-Json | Out-File test.json | |
# create a file provider class, with the current folder (where our json file is located) | |
$FileProv = [Microsoft.Extensions.FileProviders.PhysicalFileProvider]::new($PWD.Path) | |
# instantiate a source | |
$JsonSrc = [Microsoft.Extensions.Configuration.Json.JsonConfigurationSource]::new() | |
# configure the json source | |
$JsonSrc.FileProvider = $FileProv | |
$JsonSrc.Path = 'test.json' | |
# we can even tell it to automatically reload the config when the json file changes | |
$JsonSrc.ReloadOnChange = $true | |
# add the source to the configuration builder | |
$bld.Add($JsonSrc) | |
# Another way to do the above is like so: | |
[Microsoft.Extensions.Configuration.JsonConfigurationExtensions]::AddJsonFile($bld,'.\test.json') | |
# there are also more overloads for the constructur as seen here: | |
# source: https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.jsonconfigurationextensions.addjsonfile | |
[Microsoft.Extensions.Configuration.JsonConfigurationExtensions]::AddJsonFile($bld,'.\test.json',$false,$true) | |
# .AddJsonFile(ConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) | |
# reloadOnChange: Whether the configuration should be reloaded if the file changes. | |
# optional: Whether the file is optional. | |
# finally build the configuration | |
$cfg = $bld.Build() | |
# show all the property items | |
$cfg.GetChildren() | |
# you can save that into an array, so you can index into it | |
$array = $cfg.GetChildren().ToArray() | |
$array[2] | |
# Note: the .ToArray() method comes from this: (2 ways to get it) | |
Write-Output $cfg.GetChildren() -NoEnumerate | gm | |
, $cfg.GetChildren() | gm | |
# get a property | |
$cfg['name'] | |
$cfg['count'] | |
# now let's update the config json | |
[pscustomobject]@{ | |
Name = 'bb' | |
Count = 20 | |
Version = [version]'1.0.1' | |
} | ConvertTo-Json | Out-File test.json -Force | |
# and then update the config as well | |
$cfg.Reload() | |
# let's check that we have the updated values in the config | |
$cfg['name'] | |
$cfg.GetSection('name').Value | |
# and now let's access a nested property | |
$cfg['version:major'] | |
# Note: we use a colon as the separator for the tree structure | |
# we can also retrieve values with the .Item() method like so: | |
$cfg.Item('name') | |
$cfg.Item('version:major') | |
# you can check the properties of a nested property | |
($cfg.GetChildren() | where Key -eq Version).GetChildren() | |
# show which providers are loading which values | |
# (as-in see where is your configuration coming from, so you can troubleshoot if needed) | |
[Microsoft.Extensions.Configuration.ConfigurationRootExtensions]::GetDebugView($cfg) | |
# once you're done you can (and should) dispose the type | |
$cfg.Dispose() | |
# Again, this is a great video about .NET configuration | |
# https://www.youtube.com/watch?v=aOXaBZFB0-0 | |
## Some key points and benefits: | |
# 1) you can have live reloads of your configuration for your application | |
# since this allows for the reloadOnChange method and/or property, or just .reload() method | |
# 2) you can have multiple different sources for your config, like: | |
# json, env vars, azure key vault, azure app config, ini files, xml, custom source, or even a stream | |
# But in the end, you'll be working with one common API once you build the config | |
# (I mean API for get/set the values, reload, etc) | |
## Another idea, is that you could have metadata on your variables | |
# and then apply different configs based on that metadata | |
# for example, we get a VM object as input, and then we tag it (via an attribute) as either an Azure or AWS VM | |
# and then when you're going to do something during runtime (as-in when the script runs), you'll pick a different config | |
# based on that tag. | |
# Note: in PS we can attach a custom attribute to a variable or to a scriptblock or function, which essentially tags the variable/function |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment