CodeToLive

PowerShell Remoting

PowerShell Remoting enables you to run commands on remote computers using WS-Management (WinRM) protocol.

Basic Remoting Setup

Enabling Remoting

# Enable remoting on local machine (admin required)
Enable-PSRemoting -Force

# Verify remoting status
Get-PSSessionConfiguration

# Configure trusted hosts
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" -Force  # For testing only
Restart-Service WinRM

Basic Remote Commands

# One-time command execution
Invoke-Command -ComputerName "Server01" -ScriptBlock { Get-Service }

# Multiple computers
$servers = "Server01", "Server02", "Server03"
Invoke-Command -ComputerName $servers -ScriptBlock { Get-Process }

# With credentials
$cred = Get-Credential
Invoke-Command -ComputerName "Server01" -Credential $cred -ScriptBlock { 
    Get-ChildItem "C:\Important"
}

Persistent Sessions

# Create persistent session
$session = New-PSSession -ComputerName "Server01" -Credential $cred

# Use existing session
Invoke-Command -Session $session -ScriptBlock { Get-EventLog -LogName System -Newest 10 }

# Interactive session
Enter-PSSession -ComputerName "Server01"  # Exit with 'exit' command

# Multiple sessions
$sessions = New-PSSession -ComputerName $servers -Credential $cred
Invoke-Command -Session $sessions -ScriptBlock { Get-Service }

Advanced Remoting Techniques

Passing Local Variables

$localVar = "ImportantData"
Invoke-Command -ComputerName "Server01" -ScriptBlock { 
    param($data)
    "Received: $data"
} -ArgumentList $localVar

Returning Complex Objects

$results = Invoke-Command -ComputerName "Server01" -ScriptBlock {
    Get-Process | Select-Object Name, CPU, Id
}

# Process results locally
$results | Where-Object { $_.CPU -gt 100 } | Sort-Object CPU -Descending

Throttling and Parallel Execution

# Throttle concurrent connections
Invoke-Command -ComputerName $servers -ScriptBlock { 
    Get-Service 
} -ThrottleLimit 10

# Asynchronous execution
$jobs = Invoke-Command -ComputerName $servers -ScriptBlock {
    Start-Sleep -Seconds 10
    "Done"
} -AsJob

# Monitor jobs
$jobs | Receive-Job -Wait

Implicit Remoting

# Import remote commands locally
$session = New-PSSession -ComputerName "ExchangeServer"
Import-PSSession -Session $session -Module "Exchange" -Prefix "Remote"

# Use imported commands
Get-RemoteMailbox -Identity "user@domain.com"

Security Considerations

# Configure HTTPS listener
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Subject -match "Server01" }
New-PSWSManInstance -Name "PSRemoting" -CertificateThumbprint $cert.Thumbprint

# JEA (Just Enough Administration)
# Create role capability file
New-PSRoleCapabilityFile -Path ".\BasicUser.psrc" -VisibleCmdlets "Get-Service"

# Create session configuration
Register-PSSessionConfiguration -Name "BasicUser" -RoleDefinitions @{
    "DOMAIN\BasicUsers" = @{ RoleCapabilities = "BasicUser" }
}

Troubleshooting Remoting

# Test connection
Test-WSMan -ComputerName "Server01"

# Check firewall rules
Get-NetFirewallRule -Name *WinRM*

# Enable logging
Set-WSManQuickConfig -LogLevel "Debug"

Cross-Platform Remoting

# Linux/macOS setup
# Install PowerShell and configure SSH
sudo apt install openssh-client openssh-server
sudo systemctl enable ssh
sudo systemctl start ssh

# Windows to Linux remoting
Enter-PSSession -HostName "linux-server" -UserName "admin" -SSHTransport

# Linux to Windows remoting
ssh admin@windows-server "powershell -Command { Get-Process }"

Practical Examples

Multi-Server Management

# Get disk space across servers
$diskReport = Invoke-Command -ComputerName $servers -ScriptBlock {
    Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" |
    Select-Object DeviceID, 
                @{Name="SizeGB";Expression={[math]::Round($_.Size/1GB,2)}},
                @{Name="FreeGB";Expression={[math]::Round($_.FreeSpace/1GB,2)}}
}

$diskReport | Group-Object PSComputerName | Format-Table

Software Deployment

# Deploy software to multiple machines
Invoke-Command -ComputerName $servers -FilePath "C:\Scripts\DeploySoftware.ps1"

# Or with script block
$installScript = {
    $tempFile = "C:\Temp\installer.msi"
    Copy-Item -Path "\\fileshare\installer.msi" -Destination $tempFile
    Start-Process -FilePath "msiexec.exe" -ArgumentList "/i $tempFile /quiet" -Wait
    Remove-Item -Path $tempFile
}

Invoke-Command -ComputerName $servers -ScriptBlock $installScript

Configuration Management

# Ensure consistent configuration
Invoke-Command -ComputerName $servers -ScriptBlock {
    # Set power plan
    powercfg /setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c  # High performance
    
    # Configure Windows Update
    Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" `
                    -Name "NoAutoUpdate" -Value 0
}