> For the complete documentation index, see [llms.txt](https://cajac.gitbook.io/ctf-notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cajac.gitbook.io/ctf-notes/connect-to-machines/remoting-with-powershell.md).

# Remoting with PowerShell

## Administrator access required

In order to access the remote PowerShell session, you must have Administrator access to the remote system. This could be that your logged in user has Administrator access on the remote system, or that, when the system is part of a domain, you have Domain Admin access. From the Microsoft documentation:

> To create remote sessions and run remote commands, by default, the current user must be a member of the **Administrators** group on the remote computer or provide the credentials of an administrator. [about\_Remote\_Requirements](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_remote_requirements?view=powershell-7.2#user-permissions)

The user might also need to be a member of the [Remote Management Users](https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/understand-security-groups#remote-management-users) group.

## Enable PowerShell remoting

By default, Windows Server 2012R2 and later have PowerShell remote access turned on by default. Windows 10 and Windows 11 systems have this feature turned off by default. To turn on PowerShell remote access, an administrator can run the `Enable-PSRemoting` command:

Run from an elevated PowerShell session

```powershell
PS C:\WINDOWS\system32> Enable-PSRemoting
WinRM has been updated to receive requests.
WinRM service type changed successfully.
WinRM service started.

WinRM has been updated for remote management.
WinRM firewall exception enabled.
```

When you run `Enable-PSRemoting`, Windows makes several changes to the local Windows configuration:

1. Starts the WinRM service, listening on TCP port 5985
2. Changes WinRM to start automatically
3. Makes Windows firewall changes to permit access to TCP port 5985
4. Configures the WS-Management remote access feature for PowerShell use

> Note: PowerShell remoting is accessible only when the Windows Firewall is set to Domain or Private. WinRM is not available for Public network access.

## TrustedHosts

### Check TrustedHosts

To check winrm configuration including TrustedHosts, run the following from an elevated shell

```batch
winrm get winrm/config
```

Or for the client configuration only

```batch
winrm get winrm/config/client
```

### Set Trusted Hosts

You might also need to add the remote machine to the list of trusted hosts on your local machine. *This shouldn't be needed if both the source and destination machine are in the same domain*.

The **TrustedHosts** item can contain a comma-separated list of computer names, IP addresses, and fully-qualified domain names. Wildcards are permitted.

```powershell
PS C:\WINDOWS\system32> Set-Item wsman:\localhost\client\trustedhosts 192.168.50.80

WinRM Security Configuration.
This command modifies the TrustedHosts list for the WinRM client. The computers in the TrustedHosts list might not be authenticated. 
The client might send credential information to these computers. Are you sure that you want to modify this list?
[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"): Y

```

Or with the `winrm` command from an elevated PowerShell window

```powershell
winrm set winrm/config/client '@{TrustedHosts="192.168.140.130"}'
```

{% hint style="info" %}
Note that the TrustedHosts configuration must be done on **both the source and destination machines**!
{% endhint %}

## Run commands with Invoke-Command

You can run commands specified in a script block with `Invoke-Command`

```powershell
PS C:\Users\Sec504> Invoke-Command -ScriptBlock { Get-Process } -ComputerName FM-CEO
Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName      PSComputerName
-------  ------    -----      -----     ------     --  -- -----------      --------------
    102       7     6220      10788       0.00   4952   0 conhost          FM-CEO
    236      13     3856      24652       0.23   5880   1 conhost          FM-CEO
...
```

You can also specify a comma-separated list of multiple systems to run the script block

```powershell
PS C:\Users\Sec504> Invoke-Command -ScriptBlock { Get-Process | Where-Object -Property Name -EQ 'lsass' | Select-Object -Property Name, ID } -ComputerName FM-CEO, FM-WEBDEV, FM-GOLF, FM-ALGORITHM


Name           : lsass
Id             : 704
PSComputerName : FM-CEO
RunspaceId     : 199cb838-d1c5-43b1-a155-cd1b78025e7f

Name           : lsass
Id             : 680
PSComputerName : FM-WEBDEV
RunspaceId     : 2d1e05ba-4fdc-4010-9c49-e5e5eeb5b5a8

Name           : lsass
Id             : 680
PSComputerName : FM-GOLF
RunspaceId     : 146813ae-5059-4b89-9331-317a45c045b1

Name           : lsass
Id             : 684
PSComputerName : FM-ALGORITHM
RunspaceId     : 6ca5d060-bddf-4dd2-abbc-23bdd03a6efb

```

## Connect with Enter-PSSession

### With standard credentials

You can get a remote session with `Enter-PSSession`

```powershell
PS C:\WINDOWS\system32> Enter-PSSession -ComputerName SEC504STUDENT
[SEC504STUDENT]: PS C:\Users\Sec504\Documents> Get-Service | Where-Object -Property Status -EQ Running

Status   Name               DisplayName
------   ----               -----------
Running  AarSvc_75beb       Agent Activation Runtime_75beb
Running  Appinfo            Application Information
Running  AppXSvc            AppX Deployment Service (AppXSVC)
Running  AudioEndpointBu... Windows Audio Endpoint Builder
Running  Audiosrv           Windows Audio
Running  BFE                Base Filtering Engine
...
```

Exit the session with `Exit-PSSession`.

### With alternate credentials

If your logged-in user does not have the remote access privileges and you want to use alternate credentials, save the credentials to a variable with `Get-Credential`. You will be prompted to enter authentication credentials:

```powershell
PS C:\WINDOWS\system32> $cred = Get-Credential

cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential
PS C:\WINDOWS\system32> $cred

UserName                     Password
--------                     --------
sec504   System.Security.SecureString
```

Supply the variable `$cred` as an argument to `Enter-PSSession` using the `-Credential` option:

```powershell
PS C:\WINDOWS\system32> Enter-PSSession -ComputerName SEC504STUDENT -Credential $cred
[SEC504STUDENT]: PS C:\Users\Sec504\Documents> $env:USERNAME
Sec504
[SEC504STUDENT]: PS C:\Users\Sec504\Documents> Exit-PSSession
PS C:\WINDOWS\system32>
```

## Use cmdlets that support the -ComputerName parameter

Since the early versions of PowerShell, Microsoft has added support for [cmdlets](https://learn.microsoft.com/en-us/powershell/scripting/security/remoting/running-remote-commands?view=powershell-5.1#windows-powershell-remoting-without-configuration) to run on remote systems with the `-ComputerName` parameter:

```powershell
PS C:\Users\Sec504> Get-Command -ParameterName ComputerName | Where-Object -Property CommandType -Eq Cmdlet | Select-Object -Property Name

Name
----
Add-Computer
Clear-EventLog
Connect-PSSession
Connect-WSMan
Disconnect-WSMan
Enter-PSSession
Get-EventLog
Get-HotFix
Get-Process
...
```

The `-ComputerName` parameter is a .NET capability exposed in PowerShell for easy access:

```powershell
PS C:\Users\Sec504> Get-Process -ComputerName SEC504STUDENT

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    260      16     4780       2780       0.48    564   1 ApplicationFrameHost
    241      14     5544      28412      13.77   1468   1 conhost
    227      14     5604      24672       4.36   4324   1 conhost
    102       7     6232       1248              4896   0 conhost
    641      48    25316        924       0.67   7056   1 Cortana
    609      22     1864       2024               416   0 csrss
...
```

These types of connections don't use PowerShell remoting and require the `Remote Registry` service  instead. You also need to have TrustedHosts configured.

## Resources

**about\_Remote\_Troubleshooting** - Microsoft Learn: <https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_remote_troubleshooting?view=powershell-5.1>

**Enter-PSSession** - Microsoft Learn: <https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/enter-pssession?view=powershell-5.1>

**Invoke-Command** - Microsoft Learn: <https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/invoke-command?view=powershell-5.1>

\[MS-PSRP]: PowerShell Remoting Protocol - Microsoft Learn: <https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-psrp/602ee78e-9a19-45ad-90fa-bb132b7cecec>

Running Remote Commands - Microsoft Learn: <https://learn.microsoft.com/en-us/powershell/scripting/security/remoting/running-remote-commands?view=powershell-5.1>
