A wizard always has secrets
Shhhh...

It will not surprise anyone that commiting secrets to GitHub is a bad thing.

When developing my goofball this-will-never-get-committed scripts, I want zero-risk for my secrets - things like logins to azure, connection strings for databases, how I secretly like hawiian pizza, and anything I don’t want the world to know.

I have spent minutes looking on the googles, and I haven’t found the exact equivalent of the dotnet user secrets for powershell.

I have made this workaround with the expectation that there is probably a better solution, but I wasn’t going to let that stop me from making sure my secrets are safe while I am playing with other code.

UPDATE: Naturally there is an alpha release of the Microsoft.Powershell.SecretsManagement a couple of days after I publish this.
I’ll be using this as soon as it comes out of prerelease… I’ll update this post when this happens.


TOC


Add CurrentUserAllHosts profile

I’m intending to use this for my Azure CLI learnin’, so I want this secrets stuff available to me all the time.

This is in my Powershell Snippets article, but here it is again…

if (!(Test-Path $Profile.CurrentUserAllHosts)) {
    New-Item -Type file -Path $Profile.CurrentUserAllHosts -Force }

Set-MyDevSecret and Get-MyDevSecret

These functions are using the Windows DPAPI.
This uses the Windows Indentity as keys (etc) to encrypt the secrets as files on the hard drive, so they can only be decrypted by the person logged in who created them.

And as the secrets should be stored well away from the github folder, I put the encrypted files on some rando non-home drive.

On my PC this is at D:\Users\Jon\Documents\WindowsPowerShell\profile.ps1

Set-StrictMode -Version Latest

# ---------------------------------------------------
# User Secrets
# http://www.finnangelo.com/powershell/2020/02/02/Powershell_Secrets.html

function Set-MyDevSecret([String] $key, [String] $secret) {
    $filePath = "G:\MyDevSecret\$key.txt"
    $secureString = $secret | ConvertTo-SecureString -AsPlainText -Force 
    $secureStringText = $secureString | ConvertFrom-SecureString

    New-Item -Path $filePath -Type file -Force
    Set-Content -Path $filePath -Value $secureStringText
}

function Set-MyDevSecretFromSecureString([String] $key, [secureString] $secureSecret) {
    $filePath = "G:\MyDevSecret\$key.txt"

    $secureStringText = $secureSecret | ConvertFrom-SecureString

    New-Item -Path $filePath -Type file -Force
    Set-Content -Path $filePath -Value $secureStringText
}

function Get-MyDevSecret($key) {  
    $filePath = "G:\MyDevSecret\$key.txt"
    $secureStringText = Get-Content $filePath
    $secureString = $secureStringText | ConvertTo-SecureString
    $secret = (New-Object PSCredential "user", $secureString).GetNetworkCredential().Password
    return $secret
}

Using the MyDevSecret functions

Describe "Explore Setting Secrets for Powershell Modules" {

    Context "Check setting a secret" {
        It "When Set-MyDevSecret, Then there is a new file" {
            #given
            $secret = "Howdy! I'm a secret!"
            $key = [System.DateTime]::Now.ToString("yyyy-MM-dd+HH-mm-ss-ffff")

            #when
            Set-MyDevSecret $key $secret

            #then
            $result = Test-Path "G:\MyDevSecret\$key.txt"
            $result | Should Be True
        }
    }

    Context "Check getting a secret" {
        It "When Get-MyDevSecret, Then the secret comes from a file" {
            #given
            $key = [System.DateTime]::Now.ToString("yyyy-MM-dd+HH-mm-ss-ffff")        
            $secret = "Howdy! I'm a secret! I was set at $key!"
            Set-MyDevSecret $key $secret

            #when
            $result = Get-MyDevSecret $key

            #then
            $result | Should Be $secret
        }
    }
}

And here is our pester tests passing:

Running 'Explore Setting Secrets for Powershell Modules' with success


Credits

If you find this useful, go be nice to someone. Pay it forward.

Cheers!