I have a powershell script where I can add an VPN to the local computer. It prompts for the users credentials and after that it creates the VPN connection and adds the credentials. When I try this on my own computer it works perfectly fine but when I try this on another computer it gives an error saying Set-VpnConnectionUsernamePassword isn't a command.
Does anyone know what causes this or how to fix this.
$creds = $host.ui.PromptForCredential("Need credentials", "Voer de inloggegevens in van de VPN gebruiker", "", "")
$name = "name of vpn"
$username = $creds.username
$plainpassword = $creds.password
Add-VpnConnection -Name $name -ServerAddress $name -RememberCredential -TunnelType Pptp
Set-VpnConnectionUsernamePassword -connectionname $name -username $username -password $plainpassword
The error message indicates that on the other computer, the module VPNCredentialsHelper is not installed.
Beside that, with your code
$plainpassword = $creds.password
the variable $plainpassword will receive the password as System.Security.SecureString, but the code wants a plain-text string (hence the variable name).
You should change that to
$plainpassword = $creds.GetNetworkCredential().Password
Related
I'm looking to create a simple powershell script that will import the user's first name from file, prompt to create a new password and loop on error when the password doesn't meet the password requirement based on the "ErrorVariable" if possible. If not, please advise.
# import user firstname from file
$firstname = $(Get-Content "C:\tmp\local\firstname.txt")
# prompt user for new password
$password = Read-Host "Hello, $firstname!! Please change your local admin account password. (Requirements: At least 8-characters, 1-Cap Letter, 1-Number) " -AsSecureString -Erroraction silentlycontinue -ErrorVariable PasswordError
# create new password
$password = $password
Get-LocalUser -Name "$firstname" | Set-LocalUser -Password $password -Erroraction silentlycontinue -ErrorVariable PasswordError
If ($PasswordError)
{
"Unable to update the password. The new password does not meet the length or complexity."
}
If (-Not $PasswordError)
{
"Password updated successfully!!"
See script above.........
Think you could simply use try/catch - e.g.:
try {
Set-LocalUser -Name $firstname -Password $password -Erroraction:stop
write-host "Password updated successfully!!"
}
Catch {
write-error $_
}
If the operation succeeded you will get "Password updated successfully!!", otherwise it returns the error.
I would like to change the language in this script to Norwegian and believe I have done it successfully, however, this change has suppressed error messages that are output. The same issue is present with Using-Culture en-us.
Any ideas on why this happens and how to fix it if possible?
My method of testing what the output error is is by creating a new VPN connection with the same name as an existing one.
Without the Using-Culture function, errors are shown. With it, the errors are suppressed and the script only shows the custom message (Which is shown when an error is present regardless).
Example below shows errors as intended, but does not change the language to Norwegian:
try
{
$Name = Read-Host -Prompt 'Enter the profile name for this VPN connection'
$password = Read-Host -assecurestring "Please enter your Pre-shared Key"
#Default Cisco Meraki parameters
$password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))
Add-VpnConnection -Name "$Name" -ServerAddress 193.214.153.2 -AuthenticationMethod MSChapv2 -L2tpPsk "$password" -TunnelType L2tp -RememberCredential -Force
$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup("VPN-profile for $Name has been created.
You may now use this connection.
Username and password are required on the first-time sign on.
Support: contact | company",0,"Completed") | Out-Null
}
catch
{
Write-Error $_.Exception.ToString()
Read-Host -Prompt "The above error occurred, please try again. If the issue persists, please contact support.
Support: contact | company
Please press Enter to exit"
}
See full script below. This does not show errors, and I can not confirm if the language is Norwegian in the errors.
Function Using-Culture([Globalization.CultureInfo]$culture, [ScriptBlock]$script) {
$OldCulture = [System.Threading.Thread]::CurrentThread.CurrentCulture
trap {
[System.Threading.Thread]::CurrentThread.CurrentCulture = $OldCulture
}
[System.Threading.Thread]::CurrentThread.CurrentCulture = $culture
$ExecutionContext.InvokeCommand.InvokeScript($script)
[System.Threading.Thread]::CurrentThread.CurrentCulture = $OldCulture
}
Using-Culture nb-NO {
try {
$Name = Read-Host -Prompt 'Enter the profile name for this VPN connection'
$password = Read-Host -AsSecureString "Please enter your Pre-shared Key"
# Default Cisco Meraki parameters
$password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))
Add-VpnConnection -Name "$Name" -ServerAddress 193.214.153.2 -AuthenticationMethod MSChapv2 -L2tpPsk "$password" -TunnelType L2tp -RememberCredential -Force
# Gives popup with information on next steps
$wshell = New-Object -ComObject WScript.Shell
$wshell.Popup("VPN-profile for $Name has been created.`nYou may now use this connection.`nUsername and password is required on first time sign on.`nSupport: contact | company", 0, "Completed") | Out-Null
} catch {
# Reports error and suppresses "Completed"
Write-Error $_.Exception.ToString()
Read-Host -Prompt "The above error occurred, please try again. If the issue persists, please contact support.`support: contact | company`nPlease press Enter to exit"
}
}
I apologize for grammatical errors as English is not my first language.
The top example-script is not optimized, as it is a testing script.
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?
I currently have a VBScript that reads a list of servers, and attempts to verify the password of a specific userid. The userid is locally on that server. I am checking to see that the password is not set to the default (I want to make sure it was changed to something else).
The "list of servers" can be a mix of IP addresses, hostnames (like Rocky), or fully qualified DNS names (like rocky.bigcompany.com). The servers are a mixture of physical and virtual devices, and may or may not be on a domain.
The existing VBScript I wrote handles all this, and works fine. I'm trying to re-write this same program in Powershell, and It's not working.
Here's the function I have in VBScript that does what I want:
Function LoginToServer(Computer, username, password)
'this function will log into a server
On Error Resume next
Set locator = CreateObject("WbemScripting.SWbemLocator")
Set wmi = locator.ConnectServer(computer, "root\cimv2", username, password)
'check the error code and see if we logged in successfully
LoginRC = Err.Number
If LoginRC <> 0 Then
msg = "Could not log into server: " & CStr(computer) & " With ID: " & CStr(username)
lfo.lmsg "B", "WARN", msg
Else
msg = "Server: " & CStr(computer) & " Logged in successfully as: " & CStr(username)
lfo.lmsg "B", "INFO", msg
End If
wmi.Security_.ImpersonationLevel = 3
'return the code back to calleer
LoginToServer = LoginRC
End Function
… and here's what I've tried to do in PowerShell:
Param($ComputerName = "LocalHost")
$ErrorActionPreference = "Stop"
# Actual Code starts here
Write-Host "Attempting to ping server: $ComputerName"
$IPResult = Test-Connection -ComputerName $ComputerName -Quiet
if ($IPResult -eq "TRUE") {
Write-Host "Ping OK - now attempting to log in"
try {
$ID = "userid"
$PSW = "password"
$password = ConvertTo-SecureString $PSW -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ($ID, $password)
$sesh = New-PSSession -ComputerName $ComputerName -Credential $cred
} catch {
Write-Host "Error caught"
$ErrorMessage = $_.Exception.Message
$FailedItem = $_.Exception.ItemName
} finally {
$Time = Get-Date
"$Time Computer: $ComputerName ERROR: $ErrorMessage ITEM: $FailedItem" |
Out-File c:\temp\TestCredScript.log -Append
}
} else {
Write-Host "Could not ping server"
}
How do I log into these remote computers with an ID and Password using PowerShell?
Your two code samples do different things. The VBScript code connects via WMI whereas the PowerShell code tries to establish a PowerShell session. For the latter you need PowerShell Remoting enabled, which you probably don't have.
While you probably may want to enable PSRemoting anyway, you can also use WMI from PowerShell. The Get-WmiObject cmdlet allows you to provide credentials and impersonation level, so you don't need to establish a connection first like you need to do with VBScript (if you want to use explicit credentials).
Example querying the Win32_Process class on a remote computer:
$computer = '...'
$username = 'userid'
$password = 'password'
$pw = ConvertTo-SecureString $password -AsPlainText -Force
$cred = New-Object Management.Automation.PSCredential ($username, $pw)
Get-WmiObject -Computer $computer -Namespace 'root\cimv2' -Class Win32_Process -Impersonation 3 -Credential $cred
See here for further information.
So in my script I want to not only have the user enter and store credentials in a variable but be able to verify that the password matches the admin password on the target system. So far the only way I have found to do this is by putting the actual password unecrypted in the script and comparing it to the one the user enters. That is a huge security flaw and to remedy it I was wondering if I could get the admin password using a gwmi query (SID?) as an object and compare that to the secure string the user enters.
Here is my flawed code I am using right now.
Do
{
$password = $null
$password = read-host "Enter the Administrator Password" -assecurestring
$AdminPass = ConvertTo-SecureString "adminpassword" -AsPlainText -Force
$pwd1_text = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))
$pwd2_text = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($AdminPass))
if ($pwd1_text -cne $pwd2_text) {Write-Host -ForegroundColor Red "Incorrect Password"; $password = $null}
$count ++
$tries = 3 - $count
if ($password -eq $null) {Write-Host -ForegroundColor Yellow "$tries Attempts Remaining"}
if ($count -eq 3) {Write-Host -ForegroundColor Red "$count Unsuccessful Password Attempts. Exiting..."; exit}
}While ($password -eq $null)
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist "$ComputerName\Administrator",$password
Here's a function I wrote that tests a PSCredential object, against a Domain or a local Machine:
function Test-Credential {
<#
.SYNOPSIS
Takes a PSCredential object and validates it against the domain (or local machine, or ADAM instance).
.PARAMETER cred
A PScredential object with the username/password you wish to test. Typically this is generated using the Get-Credential cmdlet. Accepts pipeline input.
.PARAMETER context
An optional parameter specifying what type of credential this is. Possible values are 'Domain' for Active Directory accounts, and 'Machine' for local machine accounts. The default is 'Domain.'
.OUTPUTS
A boolean, indicating whether the credentials were successfully validated.
.NOTES
Created by Jeffrey B Smith, 6/30/2010
#>
param(
[parameter(Mandatory=$true,ValueFromPipeline=$true)]
[System.Management.Automation.PSCredential]$credential,
[parameter()][validateset('Domain','Machine')]
[string]$context = 'Domain'
)
begin {
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::$context)
}
process {
$DS.ValidateCredentials($credential.GetNetworkCredential().UserName, $credential.GetNetworkCredential().password)
}
}
If you want to test against local accounts on a remote machine, you'll need to load this function on the remote machine and test the credential against the 'local' machine via remoting (Invoke-Command), but it should be possible.