PowerShell Install .exe application with Credentials stored in Clixml - powershell

Trying to create a Powershell script that installs an application (.exe) with stored credentials (Clixml).
Everything works fine when using:
Start-Process -FilePath "C:\Users\$($env:USERNAME)\Downloads\Software\Software.exe" -ArgumentList '/s' -Credential $credentials
But I would like a more elegant solution:
$startprocessParams = #{
FilePath = "C:\Users\$($env:USERNAME)\Downloads\Software\Software.exe"
ArgumentList = '/s'
Credential = $credentials
Verb = 'RunAs'
PassThru = $true
Wait = $true
}
$proc = Start-Process #startprocessParams
if ($proc.ExitCode -eq 0) {
'Software installed!'
}
else {
"Fail! Exit code: $($Proc.ExitCode)"
}
This works perfectly without the Credential parameter, you then get the "enter credentials/UAC" popup that I would like to avoid. With the Credential parameter I get this error:
Start-Process : Parameter set cannot be resolved using the specified name parameters.
What am I missing here? Appreciate any advice and/or guidance.
EDIT:
I use the following line to import the credentials:
$credentials = Import-Clixml "C:\Users\$Env:USERNAME\AppData\Local\Apps\SOFTWARE\cred.xml"
The credentials is created with a standard:
Get-Credential | Export-Clixml "C:\Users\$Env:USERNAME\AppData\Local\Apps\SOFTWARE\cred.xml"
This works as it should.

you need to set the credentials as PSCredential.
have a look at this solution:
$username = "username"
$password = "password"
$credentials = New-Object System.Management.Automation.PSCredential -ArgumentList #($username,(ConvertTo-SecureString -String $password -AsPlainText -Force))
Start-Process dnscrypt-proxy.exe -WorkingDirectory path_here -Credential ($credentials)
is it stored in PSCredential in the first place?

Start-Process : Parameter set cannot be resolved using the specified name parameters.
The error tells us the set of parameters used is incorrect. Checking the MSDN doc or Get-Help for Start-Process will show that -Credential can not be used with -Verb.

Related

Powershell Start-Process the filename or extension is too long

I've a error message while using credentials in start-process with a encrypted password file. In my oppinion the start-process argument credentials cannot handle the length of the encrypted password file. I tested the code with a convertion of the plain password into a secure string and use the secure string in start-process this will work. But when I using the encrypting pw file following error message appear.
start-process: this command cannot be run due to the error ; the filename or extension is too long
Invoke-Command use the encrypted pw file without problems. I Think the lenght of the variable is to long for the argument deklaration of start-process. The lenght of the content is 324 character.
Have anybody an idear?
$hostname = $env:computername
$pw_file_individual = 'c:\Scripts\secure_password_' + $hostname + '.txt'
$PW_File = Get-Content $pw_file_individual
$password = ConvertTo-SecureString $PW_File -AsPlainText -Force
$username = "contoso\account"
$creds = New-Object System.Management.Automation.PSCredential -ArgumentList ($username, $password)
$scriptfile = "C:\Skripte\test.ps1"
Start-process powershell.exe -credential $creds -NoNewWindow -ArgumentList '-executionpolicy bypass', '-file', $scriptfile -WorkingDirectory c:\windows\system32

New-PSDrive's "-Persist" flag not working: drives removed on reboot

The script mounts the drive correctly, but the drive is not persisted after rebooting the machine:
function RemapDrive {
param(
$DriveLetter,
$FullPath,
$Credential
)
Write-Host "Trying to remove $DriveLetter in case it already exists ..."
# $DriveLetter must be concatenated with ":" for the command to work
net use "${DriveLetter}:" /del
## $DriveLetter cannot contain ":"
$psDrive = New-PSDrive -Name "$DriveLetter" -PSProvider "FileSystem" -Root "$FullPath" -Credential $Credential -Scope "Global" -Persist
Write-Host "$DriveLetter was successfully added !"
}
function BuildCredential {
param (
$Username,
$Password
)
$pass = ConvertTo-SecureString $Password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ($Username, $pass)
return $credential
}
$credential = (BuildCredential -Username "xxxxxx" -Password "yyyyyy")[-1]
RemapDrive -DriveLetter "X" -FullPath "\\my-server\x" -Credential $credential
What I have found:
“When you scope the command locally, that is, without dot-sourcing, the Persist parameter does not persist the creation of a PSDrive beyond the scope in which you run the command. If you run New-PSDrive inside a script, and you want the new drive to persist indefinitely, you must dot-source the script. For best results, to force a new drive to persist, specify Global as the value of the Scope parameter in addition to adding Persist to your command.”
I have tried executing the script with ". .\my-script.ps1" (to dot-source the script?), but the result is the same.
Playing around with "net use" and the registry to try to add the network drive has lead me to a cul-de-sac as well.
Specs:
Windows 10 Home
Powershell version:
Major Minor Build Revision
----- ----- ----- --------
5 1 18362 1171
Basically, New-PSDrive doesn't have the /SAVECRED parameter from net use, and will not persistently map drives as a user other than the one running the script.
There are three ways to handle this:
[Recommended] Fix the file share permissions instead of using a separate username/password, then use New-PSDrive -Name "$DriveLetter" -PSProvider "FileSystem" -Root "$FullPath" -Scope 'Global' -Persist with no credential flag. This assumes your file share allows kerberos logins, so may not work in some edge cases.
Use net use, and include the username, password, /persistent:yes and /savecred. This can be done in powershell without any issues.
Set the powershell script you already have to run at startup.
Set up your script to use the credential manager - see the answer here
Install the CredentialManager powershell module
set HKCU\Network\[drive letter]\ConnectionType = 1
set HKCU\Network\[drive letter]\DeferFlags= 4
What finally work was user19702's option #2, with a bit of extra work regarding the registration of the username and the password.
WARNING: as he mentioned, the best option (option #1) would have been "fixing the file share permissions instead of using a separate username/password". This was not possible in my case, and this is why I had to go with option #2.
This is the script:
# ---
# Helper functions:
function RemapDrive {
param(
$DriveLetter,
$Server,
$FullPath,
$Credential
)
# For net.exe to work, DriveLetter must end with with ":"
Write-Host "Trying to remove $DriveLetter in case it already exists ..."
net use "$DriveLetter" /del
# "net use" requires username and password as plain text
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($credential.Password)
$Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
$Username=$Credential.Username
Write-Host "Registring credentials for server '$Server' ..."
cmdkey /add:$Server /user:$Username /pass:$Password
Write-Host "Mapping the drive ..."
net use $DriveLetter $FullPath /persistent:yes i
Write-Host "$DriveLetter was successfully added !"
}
function BuildCredential {
param (
$Username,
$Password
)
$pass = ConvertTo-SecureString $Password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ($Username, $pass)
return $credential
}
# ---
# Process to execute:
$credential = (BuildCredential -Username "xxxxxx" -Password "yyyyyy")[-1]
RemapDrive -DriveLetter "X:" -Server "my-server" -FullPath "\\my-server\x" -Credential $credential
If you do not want to use a hardcoded password in BuildCredential, but you want to prompt the user instead:
function GetCredential {
param(
$Label
)
$credential = Get-Credential -Message "Write your credentials for '$Label':"
if(!$credential) {
throw "A credential was needed to continue. Process aborted."
}
return $credential
}
Also, if instead of using $Server as a param, you want to extract it from $FullPath using regex, you can do that.
It presumes the $FullPath has the following format: \\server-name\dir1\dir2\etc
# Get server name using regex:
$FullPath -match '\\\\(.*?)\\.*?'
$Server = $Matches[1]

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\

Run code as different user to have elevated privileges

I'm deploying a monitoring system, and even though it has a large number of plugins, some need to run as a different user to run right.
So I switched to powershell, but the problem is the same, I have some code that give me access denied, because the user has no elevated privileges.
My question how can I run this code as different user, I tried this
$usuario = "myuser#mydomain"
$pass = get-content C:\credential.txt`
$spass = $pass | Convertto-SecureString`
pass = "securepass"`
spass = $pass | ConvertTo-SecureString -AsPlainText -Force`
write-host $pass
$cred = new-object System.Management.Automation.PSCredential -argumentlist $usuario, $spass
$UpdateSession = New-Object -ComObject Microsoft.Update.Session
$UpdateSearcher = ($UpdateSession.CreateupdateSearcher())
$Updates = $UpdateSearcher.Search("IsAssigned=1 and IsHidden=0 and IsInstalled=0").updates
$total = $Updates | measure
$total.count
Then how can I pass the credentials to the variables. The problem access denied come from this line
$Updates = $UpdateSearcher.Search("IsAssigned=1 and IsHidden=0").updates
$args = ' -file path-to-script.ps1'
Start-Process -FilePath powershell.exe -Credential $creds -ArgumentList $args -Verb RunAs
Powershell also has -Command which you can use to call a function or cmdlet instead of another script.

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