2

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.

Community
  • 1
  • 1
Richard Schaefer
  • 525
  • 3
  • 13
  • 45

3 Answers3

2

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
Frode F.
  • 52,376
  • 9
  • 98
  • 114
  • The script already lives on the remote server. I'm referencing it via a UNC path. My workaround has been since I know the UNC path I can calculate the file system path and pass that as a parameter, but I was hoping there would be a way to compute it from the running context on the remote server rather than passing it in... – Richard Schaefer Feb 15 '16 at 19:41
  • `$psscriptroot` didn't work (ps3.0 or newer)? You need to provide a sample of how you use `invoke-command` as this was unclear. – Frode F. Feb 15 '16 at 19:44
  • Updated the original post with the script running the Invoke-Command. – Richard Schaefer Feb 15 '16 at 19:51
  • Also, PowerShell V4 and I verified that $PSScriptRoot is empty when examined in the remote script – Richard Schaefer Feb 15 '16 at 19:59
  • ++; it sounds like using the target _server-local path_ inside the script block is the simplest option (`D:\AHP\pi_exceed_presentation\pi_exceed_presentation_deploy.ps1`, using the OP's example), which bypasses the need to access network resources. – mklement0 Feb 16 '16 at 03:27
  • I have to talk to the server owner if I'm going to use CredSSP. We haven't approved using CredSSP in our environment yet since storing passwords securely for it gets clunky and most of our PowerShell scripting is for hands-off automation so we can't have scripts prompting for passwords. – Richard Schaefer Feb 16 '16 at 11:21
  • @RichardSchaefer You could use psexec to trigger the script which should not require CredSSP if I remember correctly. @mklement0 The fact that `$server` is the same as the server in the scriptpath is probably just because he's testing this. If he was going to copy the script locally, he could simply hardcode the path in the first place. :-) – Frode F. Feb 16 '16 at 20:11
  • @FrodeF I'm unable to find PSExec on my local machine or the remote server. I need to make sure the authentication context of the script running on the remote server is correct since it involves file system access on that server and on servers remote to the remote server (hence CredSSP to cover the hop). Frankly I'm running out of time to tweak this. I have to deliver something (I hate being driven by a deadline, but there it is) so I think I'm going to stick with what I have and just add CredSSP to it to cover the hop. – Richard Schaefer Feb 17 '16 at 11:10
  • psxec is a Sysinternals Suite-tool that you can download for free from Microsoft. – Frode F. Feb 17 '16 at 11:24
1

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.

Richard Schaefer
  • 525
  • 3
  • 13
  • 45
0

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]}
pvoosten
  • 3,247
  • 27
  • 43