Using a shared file variable in powershell - powershell

I am trying to execute a remote command to perform netsh command. The command will do a export of the nps configuration file and output it to a shared path. But, the command always give me an error "Access is denied". I realised the problem lies in the shared path value (\\shared-pc\temp). Without it, I am able to execute it successfully eg (C:\Users\User1\Desktop). I am able to browse to the shared location from the local and remote PC. Any advice is greatly appreciated. Below is the command. Thanks.
invoke-command -computername nap1 -scriptblock {netsh nps export filename = "\\shared-pc\temp\config.xml" exportPSK = yes}

This is the double-hop / second-hop authentication problem. You're credentials is passed to the nap1-server, but nap1 doesn't have the permission to pass on the same credentials(yours) to the fileserver to get access.
The solution to is to use CredSSP
There are some mixed feelings about how smart it is to use in a production enviroment, but that's up to your company to decide.

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 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.

Powershell 3.0: Using my local profile and modules in remote PSSessions

I need my local $profile located on my local PC to be loaded automatically when I PSRemote into other computers. My $profile also imports a few local modules (available only on my local PC). So, I need my $profile to be enhanced so that my modules can be still be imported (regardless where my $profile is loaded).
I spent a lot of time trying to get this to work; but see a lot of inconsistent information posted (probably because the differences between PS2 and PS3). Everything I tried, resulted in some kind of error.
I was hoping someone would help me with a dummy-proof working example of how to do this. The only thing that actually works is a basic: enter-pssession -ComputerName RemoteServerName. I did try to at least get my local profile to load in a remote session (see below), but that didn't work either; let alone loading the modules imported in the profile file.
Register-PSSessionConfiguration -Name MyLocalProfile -StartupScript $Profile
Enter-PSSession -ComputerName REMOTESERVERNAME -ConfigurationName 'MyLocalProfile'
Gives error:
Enter-PSSession : Connecting to remote server REMOTESERVERNAME failed with the following error message : The WS-Management service cannot process the request. Cannot find the MyLocalProfile session configuration in the WSMan: drive on the REMOTESERVERNAME computer.
I even tried:
Register-PSSessionConfiguration -Name MyLocalProfile `
-StartupScript \\MYLocalPC\profile$\Microsoft.PowerShell_profile.ps1
But, but it still produced the same error. Not sure why it should be this hard to do something that most people would most likely want to happen by default.
Short answer: You're doing it incorrectly, and it's impossible to do it that way.
Long Answer:
From the Enter-PSSession page on MSDN, a line stands out:
The session configuration for a session is located on the remote computer. If the specified session configuration does not exist on the remote computer, the command fails.
Therefor you will have to Invoke-Command the Register-PSSessionConfiguration before creating the new session.

PowerShell 2.0: Accessing Windows Shares during a Remote Session

I am having trouble accessing a shared network location while within a PowerShell remote session.
From the PowerShell prompt, I enter a new session:
Enter-PSSession server1
The session is properly created and entered. I then attempt to list the contents of the share:
dir \\server2\share1
The response is this error:
Get-ChildItem : Cannot find path '\\server2\share1' because it does not exist.
However, if I remote desktop into server1, bring up PowerShell, and execute the very same dir command, the contents are correctly listed.
I've tried various things using credentials, but that doesn't seem to fix it. I've also confirmed via the "whoami" command that I have the same identity in both examples.
What would cause this?
If you can't use credential delegation as mentioned above, you can mount (or just authenticate as below) the remote share in the remote session using explicit credentials, e.g.
[server1] ps> net use \\server2\share * /user:username
(prompts for password)
[server1] ps> dir \\server2\share
(listing)
This problem has nothing to do with powershell per-se; you are trying to replay your local credentials in a remote session to a third location and falling foul of the NTLM "double hop" limitation.
Read the section "Credential Delegation"
Here - Credit to Keith Hill
and perform the steps if you have not already done so.
Another option is kerberos resource delegation
eg:
$server_name = "my-server" $servers = #(get-adcomputer -identity $server_name)
$target = "target-server" $tgt_srv = get-adcomputer -identity $target
Set-ADComputer -Identity $to_delegate -PrincipalsAllowedToDelegateToAccount $servers

Run Command as administrator in PowerShell script. UAC

OK here is my issue:
I am trying to run a script remotely on a server.
I am an administrator on both boxes, firewall exceptions are in place, remote admin is enabled, and everything else looks good that i can see.
invoke-command -ComputerName $ComputerName -ScriptBlock `
{
cd C:\Windows\System32\inetsrv\;
./appcmd.exe ADD vdir /app.name:<SiteName>/ /path:/<VDir Name> /physicalPath:<Path to files>
}
I keep getting the following error in return
ERROR ( hresult:80070005, message:Failed to commit configuration changes. Access is denied.
The server it is trying to run on is a server 2k8 R2 box and I am thinking the issue is a UAC problem. Is there anyway to get this to run as administrator without having to click yes on a UAC box?
This piece of code will eventually become a script that will have to be completely automated.
Any help would be greatly appreciated.
OK. After some research and testing I figured out the issue. After disabling UAC and the firewall and the script still not working I dug a little deeper and discovered that the main issue was the way invoke-command runs the commands. it uses the credentials of the person running the script to authenticate to the server then tries to use another account to run the permissions or lowers the privileges of the user so that certain commands cannot be run.
I added the -Credentials switch to the invoke command and everything is working great now. Corrected code sample below:
$user = New-Object Management.Automation.PSCredential("$UserName", $securePassword)
invoke-command -ComputerName $ComputerName -Credential $user -ScriptBlock `
{
cd C:\Windows\System32\inetsrv\;
./appcmd.exe ADD vdir /app.name:<SiteName>/ /path:/<VDir Name> /physicalPath:<Path to files>
}
This seems to indicate that you need to ensure you are a local admin on the remote machine (although admittedly this is for WMI specifically). According to this you can change a registry key to stop UAC applying to remote logons for administrators (search for LocalAccountTokenFilterPolicy). That shouldn't disable UAC just not filter the token if you use powershell/WMI remotely with an administrator account.
Set the option "EnableLUA" (DWORD value) found in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System to 0 and reboot.
This will disable UAC without a problem, I would do it for all your users, whether with or without permission is up to you.
This trick works in Windows Vista and Windows 7 too.
Is there anyway to get this to run as administrator without having to click yes on a UAC box?
If this were possible it would entirely defeat the point of UAC.
Thus, it would appear your only real solution is to disable UAC on the box.