How to rejoin domain when trust relationship is lost - powershell

I have a number of virtual machines which have snapshots applied by using a PowerShell script. Occasionally, the virtual machines lose their "trust relationship" with the domain. This breaks the script as I can no longer use PowerShell remoting to get into the machines and configure them.
How can I remotely reset the trust relationship of these virtual machines? Perhaps there are possibilities for rejoining the domain that don't involve remoting?
Any alternate solutions to manually rejoining the domain require logging in to the computer and doing this locally. I haven't found anything that can do this otherwise.
So far, I've attempted to put together a script that simply remotes into the box as the local administrator:
$password = ConvertTo-SecureString "password" -AsPlainText -Force
$cred= New-Object System.Management.Automation.PSCredential ("Administrator", $password)
$sesh = new-pssession -computername "theMachine" -credential $cred
At this point, I was hoping to use PowerShell to reset the password or something like that to reset the domain trust relationship. However, this results in an error on the last line: Access is Denied.
I don't think you can use the local administrator account with PowerShell remoting. Is there any other way I can remotely get a virtual machine that has lost its domain trust relationship to rejoin the domain?

Interesting a problem. Would a combination of PSExec and netdom work? I don't have a VM with broken trust relationship, so I can't test the idea.
Anyway, PSExec has parameters -u and -p for username and password. Make sure you know a local administrator account. Passing its credentials to PSExec should provide a remote shell even with broken trust relationship. Netdom.exe or a Powershell script can be used to re-join the computer to the domain.
Another an option would be changing the policy for computer accounts. A GPO that sets "Computer Configuration\Windows Settings\Security Settings\Local Policies\Security Options\Domain member: Maximum machine account password age" to 0 would set the computer account password never to expire. This might rise some security issues, though.
Edit
Use psexec to open a shell session. Like so,
psexec -u computer\administrator -p password \\computer cmd
After you got the shell, try and experiment with netdom commands. Remove the computer from the domain and add it to the domain. Netdom join and netdom remove support credential passing, so supply valid domain account credentials. After you know the exact command syntax, save the values to a script file and launch it with psexec like so,
psexec -u computer\administrator -p password \\computer c:\myScript.cmd

Related

Double-Hop Errors when running Skype for Business Cmdlets

I am attempting to automate the Skype for Business Server installation process in Powershell, I have a script that remotes into specified machines and begins preparing them as Front-End servers. The problem lies when certain SfB cmdlets (SfB commands are all of the form "verb-Cs...", ex. Get-CsUser or Get-CsPool) are run in remote sessions, they throw the double-hop error:
Exception: Active Directory error "-2147016672" occurred while searching for domain controllers in domain...
This is after running Enable-CsComputer, which enables the computer's role-based off its definition in the topology (topology was published successfully). The user object is in all required groups (RTCUniversalServerAdmins, Schema Admins, CsAdministrators & Local Admin rights on all SfB Servers). Oddly enough, the command 'Import-CsConfiguration -localstore" does not throw errors, and it's in the same remote session. There may be other local or domain groups that I need to be in, but I cannot pinpoint exactly which and have not seen them documented in the Skype build guides. Skype commands that have parameters to specify targets or just pull data, such as Get-CsPool or Get-CsAdForest, do not have errors because they are run in the local scope. The Enable-CsComputer has no parameter for the computer name, it has to be executed from that machine itself.
Enabling CredSSP delegation on each server is not an option, and I'm not understanding why there is a "second hop" in this command! If the second hop was a resource on a file server or database, that would make sense, and be easy to solve, but in this case, I can't track it. Can anyone tell me what I may be missing?
Here's a code sample to try and illustrate. From the jumbox I get the pool data to create an array, and a session is opened to each machine:
$ServerArray =get-cspool -identity $poolName
$i=0
$SessionArray = #{}
foreach($server in $ServerArray.Computers){$SessionArray[$i] = new-PsSession -ComputerName $server}
foreach($session in $SessionArray.values){
invoke-Command -session $session -scriptBlock {
#remote commands:
import-csConfiguration -<config file path> -localstore; #no errors
enable-CsReplica; #no errors
enable-cscomputer; #double hop error here
}}
If I log into that machine and run the same command, it executes fine but the intention of the project is to automate it on an arbitrary number of machines.
It looks like it's just trying to authenticate to a domain controller, which is reasonable. You'll have to approach this like any other double-hop issue.
Microsoft has an article dedicated to the double hop issue, and has a few solutions other than CredSSP that you can look at: Making the second hop in PowerShell Remoting

Powershell remote access to nanoserver on docker

I have created a W10 VM (guest) running docker, pulled microsoft/nanoserver image and hosted a container of the image.
(tutorial here: https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/quick_start_windows_10)
Everything runs great, even host can ping the container running under guest W10. But what i cannot do, is to connect a remote powershell to container.
Enter-PSSession -ComputerName "<container ip>" -Credential ~\Administrator
This pops up a dialog asking for user and password. I cannot leave it blank or etc - the result is access denied. Any ideas how to connect or set a password for nanoserver container ?
I've been struggling with this for a few days now. However, think my problem is slightly different though, as I'm trying to do an Enter-PSSession to a windows docker container, but from another machine, not the container host.
In this tutorial (http://dinventive.com/blog/2016/01/30/windows-server-core-hello-container/), the guy makes a nested container PSSession inside a host PSSession.
He uses this command, which is only available in the latest versions of Powershell. (not in v3)
Enter-PSSession -ContainerId "<container ID>"
Get the ID by doing :
Get-Container | fl
You also have to check your Powershell version and make an upgrade if needed.
To check PS version :
$PSVersionTable
And to download Powershell latest version : https://www.microsoft.com/en-us/download/details.aspx?id=50395
When connecting to a PS-Session using a IP address it adds some requirements, You must either have the remote device configured to use ssl or have the IP address listed in your trusted hosts.
The solution is to either try use the host name for the device, I have had great success with this. Or play with the trusted hosts list. In my experience it works consistently if you add trusted list entries on your machine and the remote machine as well. You can also specify:
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*"
This will basically set all machines to be in the trusted hosts list, It has its cons like all machines being trusted but in certain restricted networks its acceptable. Doing this on the host and client machine seems to yield best results.
When specifying -Credentials it expects a credential object, You can craft one before the cmdlet to avoid entering it every time like so:
$secpass = convertto-securestring "Password Here" -asplaintext -force
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist "Username Here", $secpass
Enter-PSSession -ComputerName "<container ip>" -Credential $cred
Coding credentials like this in a script is bad practice, You should look in to storing credentials in scripts properly, there are plenty of good resources on it.

Powershell remoting - cannot execute an exe as another user

I've a commandline program (c#) that encrypts config files based on machine key.
A powershell script copies the build to a Target Server, modifies configs accordingly and installs windows services.
All the windows services run as local system account (standard user, non-admin) - let's call this account "locuser".
The Target Server is a Win 2012 R2 Server. All of the above is achieved by PS remoting from the Build Server to this Target server.
Now, I need to run the encrypt commandline program as "locuser", so that the program can use the account specific key to do the encryption.
I know that this can be easily achieved by calling Start-Process cmdlet with -Credentials parameter. Well, here's the catch, the above works fine, if I remote in (RDP) to the Target Server and then run the Start-Process .... -Credential $cred from a Powershell Console.
However, I need this to be working while I remote-in (using my scripts) to the TargetServer whilst deploying. When I remote-in to the TargetServer I use credentials that has Admin privileges.
I've tried the following
I've granted "locuser" both "Full Control" and "Invoke (Execute)" permissions by using the Set-PSSessionConfiguration -Name Microsoft.PowerShell -ShowSecurityDescriptorUI command. I've run this command for both Microsoft.Powershell and Microsoft.Powershell32 - Still get Access Denied
I've edited the "Local Security Policy"->"Local Policies"->"User Rights Assignment"->Impersonate a client after authentication - and added both the Admin account (that I login with) and the "locuser" account - Still get Access Denied
I've also granted locuser admin rights - Still get Access Denied
I'm pretty sure, there is some configuration on the PS Remoting Side of things that I'm missing out but can't figure out what - because all Powershell throws me is a Access Denied error (see screenshot) with little to no useful information to troubleshoot further.
Also, checked Event logs for any traces but to no avail.
You've fallen prey to the dreaded Double Hop. Basically you're authenticating from computer A to computer B, then trying to authenticate again from computer B to computer C (which also happens to be B in this case).
If at all possible, you would be better off ending the session and starting a new one with the locuser credentials, then just calling Start-Process. Another, more messy approach is to use schtasks.
I can tell you how to do it in the same session but it's a bit messy and very complicated, and should only be a last resort:
On the originating server (Build Server):
Run the command Enable-WSManCredSSP -Role Client -Delegate [name] where [name] is an IP or DNS address / range including any target servers (eg "192.168.1.*")
Open GPEdit.msc, navigate to Computer Configuration\Administrative Templates\System\Credentials Delegation and check that the rules Allow delegating fresh credentials and Allow delegating fresh credentials with NTLM... are enabled and include [name]
On the Target Server:
Run the command Enable-WSManCredSSP -Role Server
Running the command:
Invoke-Command [targetserver] [-Credential $cred] -Scriptblock {
## do stuff
Invoke-Command . -Credential $locusercred -Authentication Credssp -ScriptBlock {
Start-Process -FilePath $sc #etc
}
}
Some things to be aware of:
Firstly I used this setup to create a local session, then remote from there (so A-A-B instead of A-B-B) so the Group Policy stuff might be in the wrong place but pretty sure it's right.
Secondly I found that credentials are a pain to get working in sessions (in this case $locusercred). I did get it going natively but weirdly it suddenly couldn't decrypt the securestring. I ended up saving a securestring with a defined key to the registry so it can always be decrypted from any account, you may need to come up with your own solution there.
All this stuff is explained in the free eBook "The Secrets of PowerShell Remoting", if you go for the double-hop approach I recommend giving it a read.

Automate first time password reset using powershell

I am creating a VM on the fly with powershell (on ESX with Windows Server 2012 R2). I have most of the automation pieces in place, but when it comes to resetting the Administrator password the first time we login to the VM after provisioning (as a part of windows security policy), I am having a hard time.
I have tried stuff like the following (which didn't work):
[ADSI]$vmAccount="WinNT://$vmName/$vmUserName"
$vmAccount.ChangePassword($current, $new)
It fails by saying:
Exception calling "ChangePassword" with "2" argument(s):
"The specified network password is not correct.
Any help in pointing me in the right direction is much appreciated.
This has worked for me remotely which is something that you can try:
$comp = <computer>
$user = <Username here>
$pass = <New password here>
("WinNT://$comp/$user/").SetPassword($pass)
If that doesnt work you may want to check on the security policy and see if the password matches the security policy, powershell errors can sometimes be incredibly bland.

Powershell: Discover default network credentials when launched from runas /netonly

I am looking for a way to capture the network credentials of the current session into a variable that I can pass later...
The point is to execute commands on a foreign domain that I have account access/privileges to, but there is not a trust between the source and target domains.
First, we run inside a powershell that was spawned using the runas command (runas /netonly /user:domian\account powershell
From here I can do pretty much everything I want to except create an event in the task scheduler without hardcoding the username/password into the command line
invoke-command -computer $destination -scriptblock {schtasks -ru domain\account -rp password}
What I am looking to do is something like
$username = Get Current Session Network Username ($(whoami) brings up the actual local longon account,not the runas account that spawned the powershell window)
$password = Get the Password that was entered when the RunAs command was executed
Once a security token has been created from credentials entered and validated against active directory, the password is no longer kept around. It is not available for retrieval and reuse elsewhere. Only the token remains. This is by design.
UPDATE:
I dug a little further to bolster my case, and it's not quite as above but the end result is the same. The password used with runas.exe does not appear to be available. The network credentials are not validated against AD, which makes sense in retrospect since you often use /netonly for working with a remote, untrusted domain: By definition, you cannot validate the remote credentials from the local system. From MSDN:
Here's information for the flag LOGON_NETCREDENTIALS_ONLY, used with CreateProcessWithLogonW.
Log on, but use the specified credentials on the network only. The new
process uses the same token as the caller, but the system creates a
new logon session within LSA, and the process uses the specified
credentials as the default credentials.
This value can be used to create a process that uses a different set
of credentials locally than it does remotely. This is useful in
inter-domain scenarios where there is no trust relationship.
The system does not validate the specified credentials. Therefore, the
process can start, but it may not have access to network resources.
Ok, so since it can't validate the credentials and get a token, then it must store the password somewhere in memory since it must pass them over the wire later for SSPI etc. So, can we get at them from the process launched from runas.exe ? Let's see:
PS> runas /netonly /user:foo\bar powershell.exe
Enter the password for foo\bar: ******
I literally used foo\bar for domain and user above. It is not validated, as mentioned already. I entered 12345 for a password. The above line will launch a new instance of powershell. So, from that new instance, let's look at the default network credentials:
PS> [System.Net.CredentialCache]::DefaultNetworkCredentials
UserName Domain
-------- ------
Oh well, out of luck: Nothing there. My guess is the credentials are guarded in some encrypted part of memory in the kernel, probably the LSA (local security authority) out of reach from prying processes.