Invoke-Item executes file locally - powershell

I have a command
Invoke-Item \\remote_IP\share\setup.exe
That executes setup.exe on my local computer even though I specified "remote_IP" in the UNC path.
What is missing?

Your question isn't clear, but it looks like you are trying to remotely execute an application. You don't want Invoke-Item for that, you want Invoke-Command which has the -ComputerName switch (along with other things to facilitate remote execution like accepting credentials).
Invoke-Command -ComputerName RemoteIP -ScriptBlock {& 'C:\Path\To\Setup.exe'}
Or however you want to execute the file.

UNC paths have the following form \\remote_name\share_name\path. In your case the share_name is missing.
See https://en.wikipedia.org/wiki/Path_%28computing%29#Uniform_Naming_Convention
Also UNC paths only allow you to access file remotely, not execute them on the remote computer. For excecuting a program remotely you need a special service or tool support: https://serverfault.com/questions/221064/running-remotely-an-app-from-a-shared-folder-with-psexec
From PowerScript, however, you could also use the invoke-command command (see http://technet.microsoft.com/en-us/library/hh849719.aspx)

Related

How do I run a powershell script from another script passing credentials?

I am currently running a powershell script that displays a message asking which script do you want to run. 1-5?
Once the user selects this it imports credentials using Import-Credential on a clixml file and runs something like:
Invoke-Command -ComputerName $Server -Credential $Cred -ScriptBlock {& C:\Temp\script.ps1}
The script then launches on the server but has no permission to read / copy / move files. I assumed because I ran with the credentials specified it would be able to perform the actions needed.
Troubleshooting
If the credentials specified were wrong then it wouldn't launch the script on the server at all.
I've tried running the script on the server and it works perfectly.
I can't see a way to pass credentials on the
{& C:\Temp\script.ps1} or I would create another set of credentials on the server and use that.
Any help would be appreciated.

Run script from Host onto PsSession Computer

I am trying to run the following code to run a script from my host computer onto a Vm that I have PSRemoted into (I am successfully remoted into the PSSession). Where am I going wrong?
Invoke-Command -FilePath C:\Script.ps1 -ComputerName PSRemoteComputer
You do not need to use both a PSSession and the Invoke-Command -ComputerName command as you have above. At that point, you'd be invoking C:\Script.ps1 on your VM and from your VM (which I assume doesn't exist, since C:\Script.ps1 exists on your machine).
If you exit your PSSession and run the command as you have typed it above, it should run correctly assuming PSRemoting is correctly enabled, and permissions for the script to run are set.
Keep in mind, objects are handled differently through PSRemoting, so if you are expecting a certain output you may be getting the deserialized version.

Script location of a remotely executed script?

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]}

Execute remote quiet MSI installs from Powershell

I am trying to use the Invoke-Command powershell cmdlet to install a MSI installer. From within powershell on the local machine and from the proper directory, the following works:
./setup /quiet
The following does not seem to work:
$script =
{
param($path)
cd "$path"
& ./setup /quiet
return pwd
}
return Invoke-Command -ComputerName $product.IPs -ScriptBlock $script -Args $sourcePath
For test purposes I am working on the local machine passing in "." for the -ComputerName argument. The paths have been verified correct before passing in to Invoke-Command, and errors generated on different versions of this code indicate the paths are correct. I have also tried with and without the "& " on the remote call to setup. Other Invoke-Command calls are working, so I doubt it is a permissions issue. I have verified that the return from the pwd call is the expected directory.
How do I get the install to work?
What error (if any) are you receiving? Unfortunately, you must run the shell as admin on your local machine to be able to connect to your local machine with invoke-command or any WINRM based command that requires administrative privilege (this is not a requirement when connecting remotely).
When connecting to loopback, I believe it is unable (for some security reason) to enumerate groups and determine if you are in an admin enabled AD or local group, which is how it auto elevates when invoking on a remote machine. The only solution may be to have a conditional which checks for localhost and if so, don't use the -ComputerName parameter.
This GitHub Issue covers it
You might try using Start-Process in your script block:
cd $path
start-process setup.exe -arg "/quiet"
Not sure if you will want or need to wait. Look at help for Start-Process.
I have had weird issues when trying to remotely execute a script on a local machine. In other words, remote powershell to the local machine. It comes back with an error that seems to say that PowerShell remoting is not enabled on the machine, but it was. I can run the script remotely from another machine to the target, but when using remoting to the same box, the issue crops up.
Verify that the WinRM service is running.
Verify powershell remoting has been enabled as in Enable-PSRemoting -force.
Verify your powershell execution policy is loose enough as in Set-ExecutionPolicy Unrestricted, for example. If the policy was set to RemoteSigned, this might be the problem.
You might also want to verify the user you are running the script as (locally, but using remoting) has privileges to "log on as a service" or as a batch job. Just guessing there, if the above list doesn't solve anything.

Get script directory in PowerShell when script is invoked with Invoke-Command

I have a set of PowerShell scripts that include a "common" script, located in the same folder, like this:
# some-script.ps1
$scriptDir = Split-Path -Parent $myinvocation.mycommand.path
. "$scriptDir\script-utils.ps1"
This is fine if the script is called directly, e.g.
.\some-script.ps1
However, if the script is called with Invoke-Command, this does not work:
Invoke-Command -ComputerName server01 -FilePath "X:\some-script.ps1"
In this case, infact, $myinvocation.mycommand contains the contents of the script, and $myinvocation.mycommand.path is null.
How can I determine the script's directory in a way that works also when the script is invoked with Invoke-Command?
NOTE
In the end, this is the solution I actually used:
Invoke-Command -ComputerName server01 `
{param($scriptArg); & X:\some-script.ps1 $scriptArg } `
-ArgumentList $something
This also allows passing parameters to the script.
I don't believe you can, from within the invoked script. From get-help invoke-command:
-FilePath
Runs the specified local script on one or more remote computers. Enter the path and file name of the script, or
pipe a script path to Invoke-Command. The script must reside on the local computer or in a directory that the
local computer can access. Use the ArgumentList parameter to specify the values of parameters in the script.
**When you use this parameter, Windows PowerShell converts the contents of the specified script file to a script
block, transmits the script block to the remote computer, and runs it on the remote computer.**
When you use invoke-command using the -filepath parameter, the script is read from the file on the local computer, converted to a script block, and that's what gets passed to the remote computer. The remote computer doesn't have any way of knowing if that script block was read from a file.
For the remote computer to know what that original file path was, you'll have to tell it. I think the easiest way to do that would be to write a function to do the invocation, and have it pass the filename to the invoked script as a parameter.
alternatively rather than using filepath.. you could pass in a scriptblock, that dotsources the script from a UNC path that all machines have access to. However each machine will need to have the appropriate executionpolicy set so that they can run that script from the UNC path
let me be clear though, that i'm not saying to run the script from the UNC path as if that does the remoting, but still using invoke-command or start-job to run a scriptblock on a remote computer. It just happens that that scriptblock will run the script from a UNC path for convenience.