Decoding System.Security.SecureString - powershell

I want to decrypt a System.Security.SecureString to a readable password.
$mycrdentials = Get-Credential
$abc = $mycrdentials.Password
$Ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($abc)
$result = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($Ptr)
[System.Runtime.InteropServices.Marshal]::ZeroFreeCoTaskMemUnicode($Ptr)
$result
But when I print result all I am getting is a blank space. What am I doing wrong? How can I get a readable password?

The code you posted works for me. There is a simpler way, though:
PS C:\> $cred = Get-Credential # entered "somepassword" as the password here
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential
PS C:\> $cred.Password
System.Security.SecureString
PS C:\> $cred.GetNetworkCredential().Password
somepassword

Related

How to run Command as a different user with Powershell?

I'm trying to make a script that changes the HostnameAlias for a given dns record.
But only certain users have access to editing these records, for example ADMIN can edit it but CURRENTUSER cannot.
Currently I have this piece of code:
param(
[ValidateNotNull()]
[System.Management.Automation.PSCredential]
$Credential = $(Get-Credential)
)
$Command = "Set-DnsServerResourceRecord -NewInputObject $($NewObject) -OldInputObject $($OldObject) -ZoneName $($ZoneName)"
Start-Process -FilePath PowerShell -NoNewWindow -Credential $Credential -ArgumentList $Command
But i just keep getting Start-Process : This command cannot be run due to the error: The user name or password is incorrect even though I am absolutely sure they are indeed correct.
What am I doing wrong here.
Ps, I have looked at all the related questions, none seem to answer my question.
You can call System.Management.Automation.PSCredential object to specify any credentials you want and run with it in any process
$User = 'yourdomain\youruser'
$Password = 'yourpassword'
$Secure_Password = ConvertTo-SecureString $Password -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential($User, $Secure_Password)
$Command = "Set-DnsServerResourceRecord -NewInputObject $($NewObject) -OldInputObject $($OldObject) -ZoneName $($ZoneName)"
Start-Process -FilePath PowerShell -NoNewWindow -Credential $Credential -ArgumentList $Command
You can use this:
#Get User credential
$Credential = Get-Credential Domain\UserNameYouWant
#Use System.Diagnostics to start the process as User
$ProcessInfo = New-Object System.Diagnostics.ProcessStartInfo
#With FileName we're basically telling powershell to run another powershell process
$ProcessInfo.FileName = "powershell.exe"
#CreateNoWindow helps avoiding a second window to appear whilst the process runs
$ProcessInfo.CreateNoWindow = $true
#Note the line below contains the Working Directory where the script will start from
$ProcessInfo.WorkingDirectory = $env:windir
$ProcessInfo.RedirectStandardError = $true
$ProcessInfo.RedirectStandardOutput = $true
$ProcessInfo.UseShellExecute = $false
#The line below is basically the command you want to run and it's passed as text, as an argument
$ProcessInfo.Arguments = "The command you want"
#The next 3 lines are the credential for User as you can see, we can't just pass $Credential
$ProcessInfo.Username = $Credential.GetNetworkCredential().username
$ProcessInfo.Domain = $Credential.GetNetworkCredential().Domain
$ProcessInfo.Password = $Credential.Password
#Finally start the process and wait for it to finish
$Process = New-Object System.Diagnostics.Process
$Process.StartInfo = $ProcessInfo
$Process.Start() | Out-Null
$Process.WaitForExit()
#Grab the output
$GetProcessResult = $Process.StandardOutput.ReadToEnd()
# Print the Job results
$GetProcessResult
Just a mistake on my part, forgot to specify domain before username when entering credentials.
Can solve it like this Get-Credential Domain\

How to handle PowerShell Secure Strings

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

using secure password with multiple users without prompt

I am trying to have my password secured and stored in a file so that I don't need to enter each time when I run the script.
First step, I ran the following, entered the password which got stored into E:\cred.txt file. The txt file now contains an encrypted password.
(Get-Credential).Password | ConvertFrom-SecureString | Out-File "E:\cred.txt"
Secondly, I ran the below Script:
$File = "E:\cred.txt"
$User = "jason#domain.com"
#### I have two different user accounts, one for admin and other for operator,
#### however both user accounts use same password.
$adminuser = $User
$operator = $User -replace "#domain.com"
#### I would need to read $File to get only the password
$pass = New-Object -TypeName System.Management.Automation.PSCredential `
-ArgumentList (Get-Content $File | ConvertTo-SecureString)
$adminuser
$operator
$pass
Output:
jason#domain.com
jason
UserName Password
-------- --------
From the output, it seems New-Object refers to both UserName and Password. And when I try to connect to systems, it fails with Authentication error. Since I already have two different usernames hard coded within the script, how should I get only the password stored in $pass? or is it possible to include all usernames ($User, $adminuser, $operator) into the cred.txt file?
Try this:
#saving credentials
Get-Credential | Export-CliXml -Path c:\credential.xml
#importing credentials to a variable
$Credential = Import-CliXml -Path c:\credential.xml
Or this:
#you could then write it to a file or, i say its a better approach to a registry key
$SecurePassword = ConvertTo-SecureString -String 'P#ssw0rd' -AsPlainText -Force | ConvertFrom-SecureString
#now you are taking it back as a secure string
$RegistrySecureString = $SecurePassword | ConvertTo-SecureString
#you can aslo see the password
$UserName = "NULL"
$Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $UserName, $RegistrySecureString
$Password = $Credentials.GetNetworkCredential().Password
#P#ssw0rd

How to authenticate an user in ActiveDirectory with powershell

I would like to authenticate an user in my ActiveDirectory with the Username and the Password. Is there any chance to do that with powershell and the activeDirectory module.
Thank you
There are multiple ways of doing this. Here is a quick and simple function which authenticates a user to AD.
Function Test-ADAuthentication {
param($username,$password)
(new-object directoryservices.directoryentry "",$username,$password).psbase.name -ne $null
}
PS C:\> Test-ADAuthentication "dom\myusername" "mypassword"
True
PS C:\>
It might not be the best function for your needs but your question lacks details.
Requires .NET 3.5 and PowerShell V2
$UserName = 'user1'
$Password = 'P#ssw0rd'
$Domain = $env:USERDOMAIN
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
$pc = New-Object System.DirectoryServices.AccountManagement.PrincipalContext $ct,$Domain
$pc.ValidateCredentials($UserName,$Password)
here is my version of the script.
In this vesion the credentials are not stored in plain text,
when you run the function it will prompt you to enter the credentials and
Function Test-ADAuthentication {
$Cred = Get-Credential
(New-Object DirectoryServices.DirectoryEntry "",$($Cred.UserName),$($cred.GetNetworkCredential().password)).psbase.name -ne $null
}
If pass is wrong return false, if pass is right return true

Using Powershell -encodedcommand to pass parameters

I'm trying to find an elegant way of passing parameters to a powershell script where the string can contain any number of special characters that would need to be escaped. For example, a complex password with special characters.
I was looking at the -encodedcommand option but it seems like this is only intended to pass an encoded script block, not an encoded version of parameters.
For example, consider the following script:
param(
[Parameter()][Alias("un")][string]$Username,
[Parameter()][Alias("pw")][string]$Password
)
Write-Host "Username: $Username"
Write-Host "Password: $Password"
The string '-un testuser -pw testpw' is base64 encoded as the following:
LQB1AG4AIAB0AGUAcwB0AHUAcwBlAHIAIAAtAHAAdwAgAHQAZQBzAHQAcAB3AA==
I tried calling the script as a .ps1 file and passing -encodedcommand with the above string but got the error 'A parameter cannot be found that matches parameter name 'encodedcommand'
So, fine, this has to be a call to powershell.exe directly.
Also tried the following:
powershell.exe -encodedcommand LQB1AG4AIAB0AGUAcwB0AHUAcwBlAHIAIAAtAHAAdwAgAHQAZQBzAHQAcAB3AA== -file Base64ParamTest.ps1
This ran the script, but the parameters had no value.
This is behaving as I would expect, but not as I would hope. Is there a way to actually pass my parameters themselves as safely encoded strings?
You have to include the script invocation as part of the command e.g.:
PS> $command = "& '$pwd\login.ps1' -un testuser -pw testpw"
PS> $bytes = [Text.Encoding]::Unicode.GetBytes($command)
PS> $encodedCommand = [Convert]::ToBase64String($bytes)
PS> powershell.exe -noprofile -encodedCommand $encodedCommand
Username: testuser
Password: testpw
Here are some notes I've taken in the past on how to deal with passwords in scripts:
###########################################################
#
# Stashing passwords to avoid interactive password prompting
#
# NOT RECOMMENDED BUT IF PASSWORD IS DYNAMIC OR WIDELY KNOWN
$passwd = ConvertTo-SecureString "Not Very Secret Password" -AsPlainText -Force
# Need a way to prompt for password and use clear text password for use with net use
$cred = Get-Credential
$cred.GetNetworkCredential().UserName
$cred.GetNetworkCredential().Password
#
# SAFE BUT NOT NECESSARILY PORTABLE APPROACH
# Depends on how DPAPI works with roaming profiles
#
# Capture once and store to file
$passwd = Read-Host "Enter password" -AsSecureString
$encpwd = ConvertFrom-SecureString $passwd
$encpwd
$encpwd > $path\password.bin
# Later pull this in and restore to a secure string
$encpwd = Get-Content $path\password.bin
$passwd = ConvertTo-SecureString $encpwd
# Let's see if the rehydrate worked?
$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($passwd)
$str = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
$str
$cred = new-object System.Management.Automation.PSCredential 'john',$passwd
$cred
# NOTE: The "secret" required to rehyrdate correctly is stored in DPAPI - consequence:
# You can only rehydrate on the same machine that did the ConvertFrom-SecureString
#
# PORTABLE BUT NOT NECESSARILY SAFE APPROACH
#
# Let's do this so that it will work on multiple machines:
$key = 1..32 | ForEach-Object { Get-Random -Maximum 256 }
$passwd = Read-Host "Enter password" -AsSecureString
$encpwd = ConvertFrom-SecureString $passwd -Key $key
$encpwd
# Could easily modify this to store username also
$record = new-object psobject -Property #{Key = $key; EncryptedPassword = $encpwd}
$record
$record | Export-Clixml $path\portablePassword.bin
# Later pull this in and restore to a secure string
$record = Import-Clixml $path\portablePassword.bin
$passwd = ConvertTo-SecureString $record.EncryptedPassword -Key $record.Key
# Let's see if the rehydrate worked?
$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($passwd)
$str = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
$str
$cred = new-object System.Management.Automation.PSCredential 'john',$passwd
$cred
Start-Process powershell.exe -Credential $cred -NoNewWindow
# Portable is better BUT the secret (Key) is shared (stored with the password file)
# Can be reversed to original password - still much better than clear-text password
# stored in your script.