From 7d6412688f8942ac5f7280d0e476591b1968208e Mon Sep 17 00:00:00 2001 From: Marco Blessing Date: Tue, 22 Mar 2022 08:34:32 +0100 Subject: [PATCH] Adds ModuleBase Post (#15) --- .drone.yml | 4 +- config/_default/params.toml | 2 +- content/posts/psmodulebase/index.md | 119 ++++++++++++++++++++++++++++ content/posts/psmodulebase/note.jpg | Bin 0 -> 15035 bytes contributing.md | 57 +++++++++++++ package.json | 3 +- 6 files changed, 181 insertions(+), 4 deletions(-) create mode 100644 content/posts/psmodulebase/index.md create mode 100644 content/posts/psmodulebase/note.jpg create mode 100644 contributing.md diff --git a/.drone.yml b/.drone.yml index 4b2f371..f6ea6d9 100644 --- a/.drone.yml +++ b/.drone.yml @@ -76,7 +76,7 @@ steps: - name: "Trigger Service Update" image: ocram85/portainer-serviceupdate settings: - VERBOSE: true + #VERBOSE: true URI: "https://portainer.ocram85.com" TOKEN: from_secret: NEXT_TOKEN @@ -137,7 +137,7 @@ steps: - name: "Trigger Service Update" image: ocram85/portainer-serviceupdate settings: - VERBOSE: true + #VERBOSE: true URI: "https://portainer.ocram85.com" TOKEN: from_secret: TOKEN diff --git a/config/_default/params.toml b/config/_default/params.toml index 2c36f8b..c83a98e 100644 --- a/config/_default/params.toml +++ b/config/_default/params.toml @@ -35,7 +35,7 @@ showScrollToTop = true invertPagination = false showReadingTime = true showTableOfContents = true - showTaxonomies = false + showTaxonomies = true showWordCount = true sharingLinks = ["facebook", "twitter", "pinterest", "reddit", "linkedin", "email"] diff --git a/content/posts/psmodulebase/index.md b/content/posts/psmodulebase/index.md new file mode 100644 index 0000000..dd14edf --- /dev/null +++ b/content/posts/psmodulebase/index.md @@ -0,0 +1,119 @@ +--- +title: 'PowerShell Module Base for Config Files' +date: 2022-03-21T09:14:41+01:00 +draft: true + +categories: ['PowerShell'] +tags: ['ModuleBase', 'config'] +# lastmod: 2022-03-21T09:14:41+01:00 +# showDateUpdated: true + +# custom overrides for pages +# showDate: false +# showAuthor: false +# showWordCount: false +# showReadingTime: false +# showTableOfContents: false +# showTaxonomies: false +# showEdit: false +# sharingLinks: [null] +--- + +![note](note.jpg 'Photo by [Sigmund](https://unsplash.com/@sigmund) on [Unsplash](https://unsplash.com)') + +## 🖼️ Intro + +Sometimes you want to use a basic config file for your module. This config file should be used to define basic +settings without any user specific content. This file could be placed into your PowerShell Module folder. + +Therefore you can use the automatic variable `$MyInvocation`, especially with its properties +`$MyInvocation.MyCommand.Module.ModuleBase`. This returns the full path to your current module base folder, which +can be used to join a path for your config file. + +## 📑 `.\config.psd1` config file + +Let's assume you start a new module and you need multiple config keys to work with. So you usually create a +json or powershell data based config file: + +```powershell +{ + # Logging + OutputLevel = 'Detailed' + DefaultTarget = 'Console' + LogRetentionInWeeks = 4 + + # DataSource + CouchDBURI = 'http://localhost' + MongoDBURI = 'http://mongodb' + + # ... + # ... +} +``` + +## 🔎 `Get-ConfigValue` helper function + +Now you can use `$MyInvocation.MyCommand.Module.ModuleBase` with a helper function to parse the path to your config +file and return your needed values: + +```powershell +function Get-ConfigValue { + <# + .SYNOPSIS + Returns the value of a given config file key. + + .PARAMETER ByKey + Config file key. + + .OUTPUTS + [string] + + .EXAMPLE + Get-ConfigValue -ByKey 'OutputLevel' + + .NOTES + Private module helper function. Used by other function within your module. + #> + + [CmdletBinding()] + [OutputType([string])] + param ( + [Parameter(Mandatory = $true, HelpMessage = 'Existing key from config file.')] + [string]$ByKey + ) + + begin { } + + process { + $ModuleBase = $MyInvocation.MyCommand.Module.ModuleBase + $ConfigFile = Join-Path -Path $ModuleBase -ChildPath 'config.psd1' + + if (Test-Path -Path $ConfigFile) { + try { + $Config = Import-PowerShellDataFile -Path $ConfigFile + Write-Output $Config.$ByKey + } + catch { + Write-Error -Message $_.Exception.Message -ErrorAction Stop + } + } + else { + Write-Error -Message 'Config file not found!' -ErrorAction 'Stop' + } + } + + end { } +} +``` + +## 💭 Final Thoughts + +All you need to to is using the `Get-ConfigValue -ByKey ''` in your functions to get the any value +defined in you config file. + +As far as I know, that's the simplest way to get your module root and using it with a config file. + +{{< alert >}} +Keep in mind not to store any sensitive data in you config file. User specific data should also be stored in a user +context and not in a global module wide config. +{{< /alert >}} diff --git a/content/posts/psmodulebase/note.jpg b/content/posts/psmodulebase/note.jpg new file mode 100644 index 0000000000000000000000000000000000000000..209076c3a02c20254bf8fc3565557fbbd40232ae GIT binary patch literal 15035 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