I try to run a script on a remote computer with PsExec.
C:\static\path\to\thePSTools\Folder\PsTools\PsExec.exe $IPAddress -i -s -u $Login -p $LoginPassword Powershell $PathToFile
But I just can run the the PsExec Command when writing like the code above, meaning, running PsExec from an absolute Path.
The thing is when my Program is installed on another machine, then I don't know the static path of my PsExec. So I need a relative Path. I tried a few things but none of it worked
Like this with Push-Location:
Push-Location $PSToolsPath PsExec.exe $IPAddress /accepteula $PathToFile
Or something like this:
$Path + PsExec.exe $IPAddress /accepteula $PathToFile
But I can't run it.
I know how to get the relative Path, but the question is, how to run, or is it even possible.
I am open for any edit on my question. Since its kind of complicated to explain.
Don't use PSExec
. While useful, PSExec
is a CLI program for running commands over WinRM
. PowerShell already has PSRemoting
built in (WinRM
is the backbone of PSRemoting
) and you can use New-PSSession
, Enter-PSSession
, Invoke-Command
, etc. in order to access remote machines you control access to:
Note: You must use a server name to connect to the server by default. If the server is not part of your domain or you want to use an IP, you must configure your local
WinRM
settings to trust that IP or server name. Alternatively, you can configureWinRM over SSL
to avoid having to trust servers by IP, but your client server will need to both trust the certificate presented byWinRM over SSL
, and the Subject or Subject-Alternative Name of the certificate must validate based on the name or IP you connect with.
WinRM
andPSRemoting
do not allow you to ignore SSL errors.
# Your remote machine credential
$cred = Get-Credential
# Run commands in a one off remote session
Invoke-Command -ComputerName $serverName -Credential $cred { "hello" }
# Create a PSSession so we can run commands over the same session at different times
$session = New-PSSession -ComputerName $serverName -Credential $cred
# Invoke-Command with an existing PSSession
Invoke-Command -ComputerName $serverName -Credential $cred -Session $session { "hello" }
# Enter-PSSession lets you open an interactive terminal within a remote PowerShell session
Enter-PSSession -ComputerName $serverName -Credential $cred -Session $session
# To leave a PSSession you've entered with Enter-PSSession
Exit-PSSession
exit
Note that exit
is not an alias of Exit-PSSession
, it just has the same effect when you exit the remote session as when you exit a local session.
If you must use PSExec
(for example, PSRemoting
doesn't let you run stuff as the SYSTEM
user directly, but PSExec
does), then one of two things must be true to execute psexec.exe
:
The following is not just true for
PSExec
, but for any program run on Windows, MacOS, or Windows due to their Unix roots or influences. Each one shares thePATH
concept, and without this, you must know where the program exists on disk or "you ain't runnin' it".
psexec.exe
must exist in one of the directories defined $env:PATH
psexec.exe
C:\path\to\psexec.exe
...\..\path\to\psexec.exe
.If you don't know where the program is installed and it's not on the PATH
, your only other option is to copy from media or download it where you know it will be stored on disk.
There is one way you can locate psexec.exe
(or another program) if you are certain it exists on the system. You can search the filesystem for it. The more files you have and the lower your IOPS are will extend the time it takes for the search to complete. If you find the executable, you can execute it with the call operator &
:
Warning: Be careful with this approach. If multiple executables exist which have the same name but are different versions or different programs entirely, you could accidentally end up executing the wrong version, wrong program altogether, or worst-case scenario, a malicious actor could place a modified or fake
psexec.exe
designed to steal your credentials or otherwise cause damage to your environment. You have been warned.If you go this route, check the known checksum of the program you search for. The below example does not include this but you can use
Get-FileHash
to obtain a foundpsexec.exe
's checksum, and compare it to the known correct checksum.
$foundPsExec = Get-ChildItem C:\ -Recurse -File -Include psexec.exe -EA Continue |
Select-Object -First 1
if( $foundPsExec ) {
& $foundPsExec.FullName
}
Allow me to explain a few things from the above example:
Get-ChildItem
will search the filesystem for files at the path you provide.
-Recurse
will allow Get-ChildItem
to traverse child directories while searching.
-File
only returns FileInfo
objects
-EA
is shorthand for -ErrorAction
. We want to ensure this behavior is set to continue on this operation because when searching the entire disk you are bound to hit some permissions errors.
You can hide them instead with -ErrorAction SilentlyContinue
or have PowerShell throw any errors away altogether with -ErrorAction Ignore
.
Select-Object
to only assign the first instance of PSExec
to the variable. You should implement some safer checks if you use this solution, I have only provided this as an example of making sure you only use one path when executing with &
.$foundPsExec
has a value, run it with the absolute path (this is referenced with FileInfo.FullName
, hence the FullName
property reference.