How to handle PowerShell Secure Strings - powershell

How do I properly enter and store a secure password? I am needing to Convert it from Secure in order to put in to JSON to get a REST token.
My example is:
PS C:\Temp> $secpass = Read-Host -assecurestring "Please enter password";
Please enter password: *****
PS C:\Temp> echo $secpass
System.Security.SecureString
PS C:\Temp> $pass =
ConvertFrom-SecureString $secpass
PS C:\Temp> echo $pass
01000000d08c9ddf0115d1118c7a00c04fc297eb010000004fe37b5a39a93542a74298c3740cae0b0000000002000000000003660000c00000001000000096aa9947681adf56ce6f9fd2d9ced2140000000004800000a0000000100000006bbff8b1e2115682e9be4c775d8372ee10000000b80a4a99147901275a9080c257712b1914000000010eabc8c134837751dbd2d648dbbca1f7335e9f
PS C:\Temp>
I want to run the ConvertFrom-SecureString and get my simple plain text password back.
EDIT;
I have the following function that obtains a REST Token:
function Get-AuthToken {
Param(
[string]$server,
[string]$username,
[securestring]$password
)
$creds = #{
username = $username
password = $password
grant_type = "password"
};
Invoke-RestMethod -Method Post "$server/api/token" -Body $creds
}
To build $creds correctly the password needs to be in plain text.
Furthermore I also have the following to cover the case where password string is not given when the script is run:
If(!$Password) {
[ValidatePattern("\w+")]$password = Read-Host -assecurestring "Please enter password";
}
As per first answer given here Convert a secure string to plain text I have tried to add the following before calling the Get-AuthToken function:
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
$unsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
$response = Get-AuthToken -username $User -password $unsecurePassword -server $server
If I do a Write-Host $unsecurePassword I can see the correct string however the Get-AuthToken fails authentication.
EDIT 2:
If I change the function to :
function Get-AuthToken {
Param(
[string]$server,
[string]$username,
[string]$password
)
$creds = #{
username = $username
password = $password
grant_type = "password"
};
Invoke-RestMethod -Method Post "$server/api/token" -Body $creds
}
Which is making the $password parameter a string rather than a secure string then it works however don't believe this is best practice since Visual Studio Code is complaining.

It's not recommended for production systems but try this:
$secpass = Read-Host -assecurestring "Please enter password"
$credentials = New-Object System.Net.NetworkCredential("UserTest", $secpass, "Domain")
$credentials.Password
You cannot do that with ConvertFrom-SecureString

Related

Using encrypted password to send mail is failing

I'm trying to use a stored encrypted password in a script that sends an email but I keed getting the error:
send-mailmessage : The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.57 SMTP; Client was not authenticated to send anonymous mail during MAIL FROM
[DM6PR66666019.namprd456.prod.outlook.com]
I used the following code to create the text file:
$passwordtostore = 'NotTheRealPassword$9gv8z6VHnPfDd8zc'
$secureStringPWD = $passwordtostore | ConvertTo-SecureString -AsPlainText -Force
$secureStringText = $secureStringPWD | ConvertFrom-SecureString
Set-Content "c:\temp\scriptsencrypted_password1.txt" $secureStringText
I use the following to import the password:
$passwordFile = "c:\temp\scriptsencrypted_password1.txt"
$password = Get-Content $passwordFile | ConvertTo-SecureString
Here's the sendmail function I am using:
function SendMail($ToEmails,$FromEmail,$Subj,$Body,$UserName,$Password){
$cred = New-Object System.Management.Automation.PSCredential $UserName,$Password
$MailParams=#{"from"=$FromEmail; "to"=$ToEmails;"body"=$Body;"subject"=$Subj;"smtpserver"="smtp.office365.com"}
send-mailmessage #MailParams -Credential $cred -UseSsl $true -port 587
}
Here's the code which calls the function:
$alertEmail = "me.stillme#mydomain.com"
$username="psemail#mydomain.com"
$passwordFile = "c:\temp\scriptsencrypted_password1.txt"
$password = Get-Content $passwordFile | ConvertTo-SecureString
$credential = New-Object System.Management.Automation.PsCredential($username, $password)
Import-Module -Name "..\SendMail.psm1"
... Doing some stuff
SendMail $alertEmail $username "This is the subject" "this is the body" $credential.UserName $credential.Password
Personally, I fail to see why you would make a function in a module you need to import for the Send-MailMessage cmdlet..
This makes things a lot harder to use.
Also, it kind of looks like you are switching the emailaddresses To and From inside the function.
Anyway, things go wrong when you are creating the credentials, split it into username and (secure) password to send as parameters to the function and recombine them into a credentials object in there.
Why not skip that module function and simply do:
$password = Get-Content 'c:\temp\scriptsencrypted_password1.txt' -Raw | ConvertTo-SecureString -AsPlainText -Force
$credential = New-Object System.Management.Automation.PsCredential('YourLoginName', $password)
$MailParams=#{
From = 'me.stillme#mydomain.com'
To = 'psemail#mydomain.com'
Body = "this is the body"
Subject = "This is the subject"
SmtpServer = 'smtp.office365.com'
Port = 587
UseSsl = $true
Credential = $credential
}
Send-MailMessage #MailParams
This will make your script far more readable/maintainable
I found two issues with my code above:
An unescaped $ in the password.
Once I added " -NoNewline" to the set-content, it began to work.
So, to create the encrypted file:
$passwordtostore = "7K9CBgvc4rttvfctrsef6PVHqnP6fDdwhatevervtfdscttzSc"
$secureStringPWD = $passwordtostore | ConvertTo-SecureString -AsPlainText -Force
$secureStringText = $secureStringPWD | ConvertFrom-SecureString
Set-Content "D:\Powershell Scripts\encrypted.hash" $secureStringText -NoNewline
Then to retrieve the password and use it in a credential:
$password = Get-Content $passwordFile -Raw | ConvertTo-SecureString
$credential = New-Object System.Management.Automation.PsCredential($username, $password)
It wasn't the source of the issue, but I did implement #Theo's suggestion re: using send-mailmessage.

How can I verify PowerShell credentials are domain credentials?

The solution posted here is what I am trying below: Validating PowerShell PSCredentials
My script requires domain credentials to be passed as arguments. Here is how I'm trying to validate the creds:
if ($username -and $pass) {
$Password = ConvertTo-SecureString $pass -AsPlainText -Force
$Credentials = New-Object -Typename System.Management.Automation.PSCredential -ArgumentList $username, $Password
$TestUsername = $Credentials.username
$TestPassword = $Credentials.GetNetworkCredential().password
# Get current domain using logged-on user's credentials
$CurrentDomain = "LDAP://" + ([ADSI]"").distinguishedName
$domain = New-Object System.DirectoryServices.DirectoryEntry($CurrentDomain,$TestUsername,$TestPassword)
if ($domain.name -eq $null) {
write-host "Authentication failed - please verify your username and password."
exit #terminate the script.
} else {
write-host "Successfully authenticated with domain $domain.name"
}
}
But for some reason, this always leads me to "Authentication failed - please verify your username and password". What is the problem, and would your solution also work from a runas command where creds are not passed in as arguments?

Invoke-RestMethod special characters in credentials

I'm trying to make an API call using a password that contains an "#" character and I'm getting invalid credentials.
$Password = ConvertTo-SecureString -String $Password -AsPlainText -Force
$Creds = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList $Username, $Password
Invoke-RestMethod -Uri ("http://contoso") -Credential $Creds
You have to escape the special chars or put the password in single quotes.
But as #Lieven Keersmaekers said - the # is no special char.
So you have to look if you have an other problem :)
Examples:
$Password = '$up#r' // -- This works (single quotes wont interpret the "special chars")
$Password = "`$up#r" // -- This works because you escaped the characters
$Password = "$up#r" // -- This wont work
More Examples:
PS > $Password = "H#ppy"
$Password
H#ppy
PS > $Password = '$uper H#ppy'
$Password
$uper H#ppy
PS > $Password = "`$uper H#ppy"
$Password
$uper H#ppy
hava a look at this Site
Greetz Eldo.Ob
it was not the # causing the problem it was in-fact a $ in the password causing the problem.
I added single quotes to my password and it works.
Thanks for the suggestions.

Invoke SQL Command with Secure Creds

A little stuck on how I use a secure string within a Powershell command to run a remote SQL Query.
The following command run's fine in a powershell, as this is running under my own account - it also returns results when providing the values for username and password.
"SELECT COUNT(E.intEmployeeID) AS Count FROM Employees E WITH(NOLOCK)" - ServerInstance "SERVERA\INSTANCEA" -Database "DATABASEA" -u USER1 -p SomePassword
I want to automate/schedule this script and as I don't want the password in clear txt in my script, I was looking at ways of making this a secure/encrypted string. So I have created an encrypted password using the below. The problem is I'm not sure how to pass this password back into my Command..
This creates the encrypted string and stores in a file. This will be a file secured somewhere remotely.
$File = "C:\password.txt"
[Byte[]] $Key = (1..16)
$Password = "SomePassword" | ConvertTo-SecureString -AsPlainText -Force
$Password | ConvertFrom-SecureString -key $Key | Out-File $File
This then will read the encrypted file and store in secure string... But how do I get my Invoke SQL command to use this password.
$File = "C:\Cred.txt"
[Byte[]] $Key = (1..16)
$Password = Get-Content $File | ConvertTo-SecureString -Key $Key
The value for $Password is System.Security.SecureString, if I use this variable in the original command, the command fails with 'Login Failed for User'
The account being used to perform the SQL query is a SQL Authenticated account, not a Domain account..
Any advice would be Welcome
Thanks.
Create a Credential object:
$cred = new-object -typeName System.Management.Automation.PSCredential -ArgumentList $user, $pass
Then, convert password to plain text:
[string]$pass = $cred.GetNetworkCredential().Password
invoke-sqlcmd -UserName $user -Password $pass -Query 'select ##servername'
Ivoke-SqlCmd can only use plain text passwords.
It is possible to use a secure string without storing the plain text in a variable. Here is an example.
$Server = Read-Host "Server"
$Database = Read-Host "Database"
$Username = Read-Host "User"
$Password = Read-Host "password for user $Username on $Server" -AsSecureString
Invoke-Sqlcmd -Database $Database -ServerInstance $Server -Verbose -Username $Username -Password (New-Object PSCredential "userDummy", $Password).GetNetworkCredential().Password -Query "SELECT table_catalog [database], table_schema [schema], table_name name, table_type type FROM INFORMATION_SCHEMA.TABLES GO"

Processing a PowerShell SecureString as a parameter or console entry

I'm having a lot of difficulty with a PowerShell script that I'm trying to call a DirectoryServices query from. Currently, if I do a
$password = read-host "Password" -asSecureString
and subsequently
$credential = New-Object System.Management.Automation.PSCredential $username,$password
everything works fine. However if I try to pass the string parameter with a param($password) and then convert it to a secure string with this code:
$password = ConvertTo-SecureString -AsPlainText -Force $password
After extensive debugging I can see this is working fine in terms of converting the string to a securestring, but I get a bad user/password from DirectoryServices when I use the parameter. Everything works fine when read from the console. Any ideas on what I can do to accept a parameter OR take console input in the absence of a parameter?
This is what I was hoping would work, but doesn't:
if($password -eq $null) {
$password = read-host "Password" -asSecureString
} else {
$password = ConvertTo-SecureString -AsPlainText -Force $password
}
$credential = New-Object System.Management.Automation.PSCredential $username,$password
I recently created a script and was running into the same issue. The work around I found in my case was the following:
#Prompts for the username/password, enter the username in the form of DomainName\UserName
$Credential = get-credential
#Converts the password to clear text to pass it through correctly as passing through a secure string does not work.
$Password = $credential.GetNetworkCredential().password
#Converts the $Credential to just the DomainName/UsernName.
$Account = $credential.UserName
Hopefully this will work in your situation