- Reading Azure VM name, IP address, and hostname with PowerShell - Fri, Jul 28 2017
- Automating WSUS with PowerShell - Thu, Jul 13 2017
- Disable SSL and TLS 1.0/1.1 on IIS with PowerShell - Tue, Jun 27 2017
PsExec
PsExec is a well-known tool that has been around for more than ten years. It is still very useful when it comes to executing commands and applications on remote machines. Have a look at the example below. To open a remote command shell, I can just run the following command:
psexec \\ms2 cmd
The remote machine name here is ms2. After this command executes successfully, I can run the console commands locally and they will execute on the ms2 machine, but PsExec will redirect the output to my local console. This is how it looks when I run ipconfig on the remote machine:
By default, the PsExec command runs under the local account where you execute it. If you want to use another account, you can use a combination of the -u and -p switches. For example:
psexec \\ms2 –u mytest\admin –p password cmd
If you have an application not present on the remote machine, you need to combine the -c switch with the path to the application on the local file system. This will copy the application file to the remote system, execute the application, and then remove the file.
When it comes to copying files to the remote machine, PsExec's -v switch can be quite useful. The parameter ensures that PsExec only copies the specified file if its version is higher than the one already present on the remote machine.
There is one more very interesting—and I have to say even dangerous—option you can exploit with PsExec: the ability to use the system account to execute a remote process. I called it dangerous for a reason: there are some Windows components that only the system account can access and modify because their integrity is crucial for the operating system.
Such examples include the HKEY_LOCAL_MACHINE\SAM registry subkey and the \System Volume Information directory. The system account also has access to the Winlogon process data and Local Security Authority Subsystem Service (LSASS). Even local administrators are unable to access these processes.
However, in one of those rare cases where you need information from these processes, PsExec's -s switch allows you to access a remote or local machine using the system account. As you can see in the screenshot below, I connected to the remote machine under the system account and accessed the System Volume Information folder.
To be able to do all these useful things, PsExec essentially creates a new service on the remote machine and then uses the Service Control Manager API to start the program. After that, its client interacts with this service to execute the command remotely.
PowerShell remoting
Now I'd like to take a look at the PowerShell counterpart of PsExec: PowerShell remoting.
My first example gives you the ability to run PowerShell commands in a remote PowerShell session (PSSession) using the Enter-PSSession cmdlet. To create a new PSSession, you just have to enter the following command in a PowerShell console:
Enter-PSSession -ComputerName
This feature will send the commands you enter at the new prompt to the remote machine for execution. This is very similar to the PsExec remote console session. And as with PsExec, an option exists to run the command using the credentials of another user account. For this, you have to use the -Credential parameter:
Enter-PSSession -ComputerName ms2 -Credential mydomain\admin
This method is good for executing commands on one remote machine. But what if I need to run commands on multiple machines? And what if I'd like to execute not just one command but a complete PowerShell script remotely? In this case Invoke-Command is my best friend.
This cmdlet has the same -ComputerName switch as Enter-PSSession, but it also offers the ‑ScriptBlock parameter, which allows us to put virtually any PowerShell script inside it.
For instance, if I'd like to install software on multiple remote machines, I could use this little script:
Import-Csv -Path "C:\temp\New_relicInst.csv" | % { $vmhost = $_.Name $dest = "\\"+$vmhost+"\C$\Windows\temp" copy-item " WindowsAzureVmAgent.2.7.1198.778.rd_art_stable.160617-1120.fre.msi" -Destination $dest -Force Invoke-Command -ComputerName $vmhost -ScriptBlock{ $Exp = "cmd.exe /c C:\windows\temp\WindowsAzureVmAgent.2.7.1198.778.rd_art_stable.160617-1120.fre.msi /q /l* C:\windows\temp\azureagentinst.log" Invoke-Expression $Exp } }
I'm getting the machine names from a CSV file and then using Invoke-Command against every one of them to install Azure VM Agent.
One of the features I like about Invoke-Command is the ability to work with variables defined on the local machine within the remote session. The $using: keyword provides this ability:
LocalVar = "test"Invoke-Command -ComputerName ms2 -ScriptBlock{Write-host "The localvar value $using:LocalVar"}
Just be aware that the $using: option first appeared in PowerShell 3.0. Hence, machines that only have PowerShell 2.0 installed don't support this feature.
Note that to be able to work with PowerShell remoting, the WinRm service has to be running and configured on the remote machines. To learn more about enabling PowerShell remoting and working with Invoke-Command and Enter-PSSession in different usage scenarios, please read our series about PowerShell remoting.
Psexec vs. PowerShell remoting
This is in fact the main difference between PowerShell remoting and PsExec. PowerShell, as powerful as it is, only works if the remote machine already has PowerShell installed and if PowerShell remoting is configured to allow remote access. But in exchange it gives you the whole power of PowerShell and the ability to execute comprehensive scripts remotely.
On the other hand, PsExec only requires network access to the machine and administrator privileges. No agents or preinstalled server applications are required. This is especially useful when dealing with older systems such as Windows Server 2003 and Windows Vista, which don't have PowerShell installed by default.
As I mentioned before, if you need to access the operating system under the system account, PsExec is the simplest solution. A PowerShell session cannot run under a system account, unless I use PsExec for this purpose.
Subscribe to 4sysops newsletter!
Also read: Use PsExec and PowerShell together
There are a couple of other key differences for psexec..
You lose access to the ability to do tab completion, it also requires the Admin must be enabled on the operating system..
Also, you can’t get a lot of process ownership information from other tools, like the query tools..
David F.
Losing access to tab completion when I use psexec drives me insane!!
Scott
>> it also requires the Admin must be enabled on the operating system..
What do you mean with the admin must be enabled?
FYI, Administrative shares must be available on the remote computer in order to use psexec, i.e. admin$ so if your organization turns those off via a GPO for example then you will have a trickier time using psexec.
Bruce got it exactly.. I thought I had typed out Admin shares 🙂
David F.
Yeah, Admin shares. But by default they are enabled. What I really like about psexec is that it works right out of the box whereas you always have to jump through a few hoops before you can work with PowerShell remoting
I’ve used psexec for many years.. a couple of times I have run into some customers that had them disabled, and I had to work around it :-\
I have used psexec to remotely enable powershell remoting a few times.. 🙂
David F.
Hello,
I am certainly not a security expert, so correct me if I am wrong.
It has been a while since I researched it, but as far as I know when you supply a username and password with PsExec the credentials are passed in cleartext. I am not sure how PowerShell handles credentials when provided for a PSSession, but I would hope it is more secure. I think any PowerShell cmdlets that use CredSSP might pass cleartext as well.
To try to mitigate the danger I tend to run either CMD or PowerShell as the account I want to use on the remote system. At least then theoretically it is doing a network logon and probably using Kerberos (at least in a Windows domain) for authentication so it won’t require explicit credentials.
Arioth, I think old versions of PsExec transmitted the password in clear text. However, now the PsExec website states:
PowerShell remoting also encrypts, no matter if you use HTTP or HTTPS. However, I believe using HTTPS is more secure.
Made a function to Invoke-Command against local/remote computer using SYSTEM or provided credentials. Returns PSObjects, handles network interuptions due to PSSessions, and resolve any Double-Hop issues.
https://github.com/mkellerman/Invoke-CommandAs
Totally late to the conversation but if I’m finding this conversation, so are others… with that said… that’s right, in PSRemoting, both are encrypted. Using 5986 (HTTPS) will apply SSL on top of it.