skip to Main Content

When I run Invoke-Sqlcmd with a -Query that contains a password retrieved via Read-Host with the -AsSecureString parameter, and the value entered is too simple, it will fail without returning an exception.

When I run Invoke-Sqlcmd with a -Query that contains a password retrieved via Read-Host without the -AsSecureString parameter, and the value entered is too simple, it will return an exception, as expected:

Password validation failed. The password does not meet policy requirements because it is not complex enough.

Msg 40632, Level 16, State 1, Procedure , Line 1.

Examples

This code returns the "Msg 40632" exception when I enter 01234567 as a password, and will successfully execute when I enter 012345A! as a password:

$local:password = Read-Host ("Enter the new password for {0} on {1}" -f $local:login, $local:serverDomain)
$local:updatePasswordQuery = ("ALTER LOGIN {0} WITH PASSWORD = '{1}'" -f $local:login, $local:password)
Invoke-Sqlcmd `
    -ServerInstance ("{0}.database.windows.net" -f $local:server.name) `
    -Database "master" `
    -AccessToken $local:access_token `
    -ErrorAction Stop `
    -Query "$local:updatePasswordQuery"

This code will fail silently when I enter 01234567 as a password, and will also successfully execute when I enter 012345A! as a password:

$local:securePassword = Read-Host ("Enter the new password for {0} on {1}" -f $local:login, $local:serverDomain) `
                       -AsSecureString
$local:updatePasswordQuery = ("ALTER LOGIN {0} WITH PASSWORD = '{1}'" -f $local:login, $local:securePassword)
Invoke-Sqlcmd `
    -ServerInstance ("{0}.database.windows.net" -f $local:server.name) `
    -Database "master" `
    -AccessToken $local:access_token `
    -ErrorAction Stop `
    -Query "$local:updatePasswordQuery"

So my question is: how can I get Invoke-Sqlcmd to return an exception when I pass a secure string with a password that is not complex enough? Or is this simply impossible due to the nature of secure strings?

> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.3.0
PSEdition                      Core
GitCommitId                    7.3.0
OS                             Microsoft Windows 10.0.22000
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Imported Modules:

Az.Accounts                    2.10.3                
SqlServer                      21.1.18256            

2

Answers


  1. Chosen as BEST ANSWER

    My code was incorrect: I needed to use a ConvertFrom-SecureString with -AsPlainText when putting the value in the query:

    $local:securePassword = Read-Host ("Enter the new password for {0} on {1}" -f $local:login, $local:serverDomain) `
                           -AsSecureString
    Invoke-Sqlcmd `
        -ServerInstance ("{0}.database.windows.net" -f $local:server.name) `
        -Database "master" `
        -AccessToken $local:access_token `
        -ErrorAction Stop `
        -Query ("ALTER LOGIN {0} WITH PASSWORD = '{1}'" -f $local:login, (ConvertFrom-SecureString $local:securePassword -AsPlainText))
    

    I made this mistake because I was first testing the unhappy flow (does it fail on a too simple password) before the happy flow (does updating with a valid password actually work?).


  2. Officially SecureStrings are write only. They cannot officially be read, ergo you can’t check its complexity and in turn can’t do anything if you don’t like the password’s value.

    Yes it IS possible to turn a SecureString back into plaintext, notably if you didn’t use an explicit IV (using -Key on *-Securestring cmdlets) or if you did have access to that key.

    Of course that reduces SecureStrings ad absurdum. Unless there’s an additional point to using them, if you employ SecureStrings only to then turn around because you need to read them… it’s easier not to use them in the first place.

    For reference:

    $myTest=ConvertTo-SecureString -String 'Abcd' -AsPlainText -Force
    $nc = [System.Net.NetworkCredential]::new('dummy', $myTest)      
    $nc.Password
    

    (The ‘dummy’ is just a dummy, its value is not considered but is required.)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search