I am trying to execute powershell script remotely using invoke-command. The script relies on a configuration file which is available over the local network. The script is called in a following way:
Invoke-Command -ComputerName 192.168.137.181 -FilePath c:\scripts\script.ps1 -ArgumentList \\192.168.137.1\share\config.xml
The configuration as you can see is an xml file and it's loaded using:
$xml = New-Object XML
$xml.Load(args[0])
When the script is called locally on the machine then it runs witout any problems and reads the configuration file. However when I run it from different machine using invoke command I get
"Access to the path '\\192.168.137.1\share\config.xml' is denied"
exception, which is thrown when executing Load method.
The file is accessible to everyone with read and write permissions.
Both, machine on which the scrip should be run (.181) and the machine on which it is run physically have the same credentials, thus I do not pass them in invoke-command cmdlet.
The share machine (.1) has different credential, but this was never an issue when calling the script locally from .181.
Can you please point me in the right direction? I stuck on this step and can't find solution by myself. I tried downloading the xml string using WebClient#DownloadString method and passing credentials for the share machine but it did not help.
Thanks in advance
It is probably a double hop issue. You have to use CredSSP to delegate your credentials to the remote computer.
Try the solution mentioned here: http://blogs.msdn.com/b/clustering/archive/2009/06/25/9803001.aspx
Related
I am unable to access the UNC paths on my servers in a Powershell remote session from my local machine. I am able to use them from Servers Cmd prompt directly.
Actually, I have logged into the server and mapped a UNC path as local drive (say X:). Used Reconnect on Login option.
I have a batch file which resides in this X: drive, I want to run it remotely using invoke command from my local script. But, it fails.
It says "Cannot find drive. A drive with name X doesn't exist".
Also, when I try to map drive using net use command in the scriptblock then also it throws an error - System error 1223 - Native Command Error.
I use administrator credentials to log into this server.
Can anyone please help me on this, all i want to do is to run the script remotely which resides on this UNC path ?
Also, when I map a UNC Path in the server as a local drive, why am I unable to use it in a PS remote session ?
Thanks in Advance.
TS
You've really got 3 different things going on here.
1 & 3. Drives are only mapped when you log on interactively. So when you remoted into the other computer, mapped a drive, and then logged off/disconnected, that mapped drive was disconnected. Except in interactive GUI user sessions, you cannot depend upon a mapped drive letter that you don't create yourself. Within scripts or any remote session, just use UNC paths for everything - it's more reliable.
2 . When you attempt to map the drive in the remote PS session, you're encountering what's known as the "double hop" problem. There is a solution to this, but there's extra setup you have to do. See Double hop access to copy files without CredSSP
alroc's helpful answer explains the problem well and points to resources for solving it through prior configuration.
An explanation of the underlying problem, the infamous Kerberos double-hop problem, as well as an overview of available solutions can be found in this blog post.
As for an ad hoc solution for accessing a network share in a remote session (PSv3+):
Pass the credentials for the session via a variable; e.g., -Credential $cred
Then use these credentials inside the session too - e.g., as $using:cred - to establish a session-scoped auxiliary drive that maps the network location, using New-PSDrive.
Once the drive has been mapped, the target location is accessible - whether via the drive name, or directly by UNC path.
Note: This is a variation of the approach discovered by the OP him/herself and discussed briefly in a comment on alroc's answer, except that New-PSDrive is used rather than net use, which obviates the need for retrieving the password as plain text.
The following sample code demonstrates running a script from a network share from inside a remote session:
# A sample script to run from a network share on a remote computer.
$script = '\\server-001\install\Install-Agent.ps1'
# A sample target computer.
$computer = 'ws-002'
# Obtain the credentials for the remote session and store them in a variable.
$cred = Get-Credential $env:USERNAME
Invoke-Command -ComputerName $computer -Credential $cred {
# Map the target network share as a dummy PS drive using the passed-through
# credentials.
# You may - but needn't - use this drive; the mere fact of having established
# a drive with valid credentials makes the network location accessible in the
# session, even with direct use of UNC paths.
$null = New-PSDrive -Credential $using:cred -Name dummy -Root (Split-Path -Parent $using:script) -PSProvider FileSystem
# Invoke the script via its UNC path.
& $using:script
}
Note:
$null = ... suppresses New-PSDrive's output (it outputs an object describing the newly created drive).
Since the drives created by New-PSDrive are not persistent (except if you pass -Persist), there's no need to explicitly remove the dummy drive again, but you can do so with Remove-PSDrive.
Also note that PS drive definitions are scoped so that only the calling scope and its descendants see the drive; this enables wrapping statements in & { ... } to call them in a child scope, which means the a PS drive created inside that block will automatically go out of scope when the block is exited.
You can try to open the script by calling a WmiMethod :
$cmd = "CMD.EXE /c *\\\servername\somefolder\yourscript*.cmd"
Invoke-WmiMethod -class Win32_process -name Create -ArgumentList $cmd -ComputerName *servername*
Note that this will run the script on the server. You can do much more with that, like installing a package remotely (after copying the package locally on the remote machine).
Hope this help!
I am trying to unzip a file remotely. The file-share the ZIP is on uses a different credential
This is the command I ran.
Invoke-Command -Computername $compname -ScriptBlock
{
Expand-Archive -Path "\\share\somefolder\myfile.zip" -DestinationPath "\\share\somefolder"
}
I get an error stating username/password incorrect for accessing the share.
The problem is, the account I use to access $compname is not the same account I use to access the share the zip is on. I don't have a common account that can access both.
Incidentally, running the expand-archive by taking RDP to $compname works because it uses the saved credentials from the credential manager. Invoke-command on the other hand seems to be trying to access the share with the credentials used to connect to the remote computer.
Things I have tried
Mapping a network drive beforehand, but that doesn't get
recognised as a valid path when accessed via invoke-command.
Mapping a network drive on the fly inside the invoke-command
option, and then using that mapped drive with expand-archive. This
showed the most promise as I could get it working via
enter-pssession, but of course this won't work in a script am trying to automate and when
I created a new session via new-pssession and passing that to
invoke-command, it again failed to work.
Does anyone have suggestions on a possible approach? I might revisit option #2 to see if I have made a mistake somewhere.
So I have a script sitting on a server that I can remote into using Enter-PSSession and run the script from my local environment just fine. What I do is...
Enter-PSSession hostname
cd c:\temp\myscript.ps1
or
$s = New-PSSession -ComputerName hostname
Invoke-Command -Session $s -ScriptBlock {C:\temp\myscript.ps1}
these run the script just fine. The problem I am having is the data is supposed to get sent to a database. If I run the .ps1 on the hostname by RDPing directly into it, it works. If I RDP into the server and go back to my local environment where I Enter-PSSession using the code above, it submits to the database just fine. But when I close out of the RDP session and just try running the script again locally, it doesn't go to the database.
Maybe it is something stupid I am missing but any help would be greatly appreciated.
The important bits are in the myscripts.ps1, so it's impossible to say from what you have provided.
I suggest you check that script file for where the credentials are stored. When you run it locally, I assume you run it from that working directory.
Try using $psexecscript as the root of the config file's path. That's whatever path the script is in, assuming the credentials are in the same or sub- directory.
Is it possible that the user lacks permission to write in your DB or the credentials to write in that DB are not provided in the script?
If after verifying the credential issue, it still doesn't work, you might want to register your script as a task. You can set it as a manual task. Then, whenever you need it, you (remotely) run that task. In that way your credentials are stored as well and you can safely use the 'run as' feature.
I have a Powershell script that I need to execute a script file (no functions) on another server. I am using invoke-command for this but I cannot seem to get this to work correctly and execute the script on the remote server.
I don't have any code examples with me but what's the way to do this?
Thanks
How can I get a remotely executed script to know it's own location? I'm using Invoke-Command to run a script on a remote server. The script needs to create files in the directory in which it lives. Running with relative addressing doesn't work (i.e. .\output.log), the scripts generally end up in my user profile on the remote server. I tried all the methods outlined in this question but none of them seem to work when the script is remote.
Update: Provided script invocation code per request
$server='ad1hfdahp802'
$remotepath='\\ad1hfdahp802\d$\AHP\pi_exceed_presentation\pi_exceed_presentation_deploy.ps1'
$SDFEnvironment='INT'
Invoke-Command -ComputerName $server -FilePath $remotepath -ArgumentList($SDFEnvironment,$remotepath)
The remote script takes the $remotepath and turns it into a file system path.
Using -FilePath with Invoke-Command means that you read the script locally and send the content as the scriptblock to the remote computer. $PSScriptRoot only works when the script is executed directly on the target. You could try using:
Invoke-Command - ComputerName "computer1" -Scriptblock { & '\\server\path\to\script.ps1' } -Authentication Credssp
Be aware that you need CredSSP to make this work since the remote computer can't use your credentials to access network-resources without it. As an alternative, you could use psexec (or start a process remotely). Ex.
psexec \\computer1 powershell -noprofile -file \\server\path\to\script.ps1
After trying some of the changes proposed I've come to understand that the Invoke-Command isn't actually running the remote script at its original location, but rather loading it from the original location and then running it under the context of PowerShell as the user running the local script. The "script directory" is actually a directory in the user's workspace regardless of where the script originally lived.
This clarifies things for me somewhat. While there may be ways to divine where the script originally came from or to actually start a session on the remote server then run the script as a "local" script there, the need for the remote script to further access other servers, creating multiple hops in authentication, means I have to add CredSSP to the mix.
It seems my original plan, to pass the path I'm using to locate the script to the script so it can place output files in the original directory, is probably the best approach given that I also have to add CredSSP to the mix.
I'm open to refutation, but I don't think any of the proposed solutions actually improve the functionality of the remote script so I'm going to stick with what I started with for now. Thanks to everyone for their contributions.
Enter a session on the remote server, and call the script from there.
local PS> Enter-PSSession -ComputerName $server ...
remote PS> powershell d:\AHP\...\script.ps1
remote PS> exit
local PS>
Then you can use $PSScriptRoot in the script in the remote server to get the local path of the directory of the script on the remote server.
EDIT:
To locate the script on the remote server, you can use your knowledge of the network path of the script file, and parse the output of net share to map network path to local path on the remote server.
remote PS> net share | where { $_.StartsWith('D$ ') } | foreach { [regex]::Split($_, " +")[1]}