diff --git a/PowerShell_HowToo_1 b/PowerShell_HowToo_1 new file mode 100644 index 0000000..1c48a33 --- /dev/null +++ b/PowerShell_HowToo_1 @@ -0,0 +1,838 @@ +# Windows SysAdmin PowerShell Command Reference +> Practical commands for day-to-day Windows Server administration — remote connections, file transfers, system management, and more. + +--- + +## Table of Contents +1. [Connecting to Remote Servers](#connecting-to-remote-servers) +2. [WinRM & PowerShell Remoting](#winrm--powershell-remoting) +3. [SSH from PowerShell](#ssh-from-powershell) +4. [Alternatives When WinRM Is Not Available](#alternatives-when-winrm-is-not-available) +5. [Remote File Copies & Transfers](#remote-file-copies--transfers) +6. [Remote System Administration](#remote-system-administration) +7. [Active Directory](#active-directory) +8. [DNS & DHCP Management](#dns--dhcp-management) +9. [Disk & Storage Management](#disk--storage-management) +10. [Event Logs](#event-logs) +11. [Windows Updates](#windows-updates) +12. [Certificates](#certificates) +13. [Scheduled Tasks (Remote)](#scheduled-tasks-remote) +14. [Registry (Remote)](#registry-remote) +15. [Firewall Management](#firewall-management) +16. [Performance & Health Checks](#performance--health-checks) +17. [Quick Diagnostic One-Liners](#quick-diagnostic-one-liners) + +--- + +## Connecting to Remote Servers + +### Enter-PSSession — Interactive Remote Shell +```powershell +Enter-PSSession -ComputerName SERVER01 +Enter-PSSession -ComputerName SERVER01 -Credential (Get-Credential) +Enter-PSSession -ComputerName SERVER01 -Credential "DOMAIN\adminuser" +``` +> Opens an **interactive PowerShell session** on the remote machine — similar to RDP but command-line only. Everything you type runs on the remote server. Type `Exit-PSSession` to disconnect. Requires WinRM to be enabled on the target. + +--- + +### Invoke-Command — Run Commands Remotely (Non-Interactive) +```powershell +# Run a single command on one server +Invoke-Command -ComputerName SERVER01 -ScriptBlock { Get-Service } + +# Run against multiple servers at once +Invoke-Command -ComputerName SERVER01, SERVER02, SERVER03 -ScriptBlock { + Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 5 +} + +# Pass a variable from your local machine into the remote block +$serviceName = "Spooler" +Invoke-Command -ComputerName SERVER01 -ScriptBlock { + Get-Service -Name $using:serviceName +} + +# Run a local script file on a remote server +Invoke-Command -ComputerName SERVER01 -FilePath "C:\Scripts\CheckHealth.ps1" + +# Run with alternate credentials +Invoke-Command -ComputerName SERVER01 -Credential "DOMAIN\admin" -ScriptBlock { + hostname +} +``` +> Best for **running commands or scripts on one or many servers without an interactive session**. Great for bulk administration — patch checks, service restarts, config audits. The `$using:` prefix passes local variables into the remote script block. + +--- + +### New-PSSession — Persistent Reusable Session +```powershell +# Create a session (stays open) +$session = New-PSSession -ComputerName SERVER01 -Credential "DOMAIN\admin" + +# Use the session multiple times +Invoke-Command -Session $session -ScriptBlock { Get-Process } +Invoke-Command -Session $session -ScriptBlock { Get-EventLog -LogName System -Newest 10 } + +# Copy files using the session (see also Copy-Item section) +Copy-Item "C:\Scripts\deploy.ps1" -Destination "C:\Scripts\" -ToSession $session + +# Enter interactively when needed +Enter-PSSession -Session $session + +# Clean up when done +Remove-PSSession $session + +# Manage multiple open sessions +Get-PSSession +Get-PSSession | Remove-PSSession # Close all sessions +``` +> Use persistent sessions when you need to **run multiple commands against the same server** without re-authenticating each time. Much more efficient than opening a new connection for every command. + +--- + +## WinRM & PowerShell Remoting + +> **WinRM (Windows Remote Management)** is the underlying service that enables PowerShell remoting. It must be configured on the target server before `Enter-PSSession` or `Invoke-Command` will work. + +### Enable WinRM on a Target Server +```powershell +# Run this ON the target server (or via GPO) +Enable-PSRemoting -Force + +# Verify WinRM is running +Get-Service WinRM +Test-WSMan -ComputerName SERVER01 +``` +> `Enable-PSRemoting` starts the WinRM service, sets it to automatic startup, and configures the firewall rules. Run this once on any server you want to manage remotely. + +### Configure Trusted Hosts (Workgroup / Non-Domain) +```powershell +# If servers are NOT domain-joined, you must explicitly trust them +Set-Item WSMan:\localhost\Client\TrustedHosts -Value "SERVER01" +Set-Item WSMan:\localhost\Client\TrustedHosts -Value "SERVER01,SERVER02,10.0.0.5" +Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" # Trust all (lab use only) + +# View current trusted hosts +Get-Item WSMan:\localhost\Client\TrustedHosts +``` +> Domain-joined machines trust each other automatically via Kerberos. In workgroup or cross-domain environments you must add the target to TrustedHosts. **Avoid `*` in production.** + +### Test WinRM Connectivity +```powershell +Test-WSMan SERVER01 # Quick WinRM connectivity test +Test-WSMan SERVER01 -Credential (Get-Credential) # With credentials +Test-NetConnection SERVER01 -Port 5985 # Test WinRM HTTP port +Test-NetConnection SERVER01 -Port 5986 # Test WinRM HTTPS port +``` + +--- + +## SSH from PowerShell + +> OpenSSH is built into Windows 10/Server 2019 and later. PowerShell 7+ also supports SSH-based remoting natively — useful for Linux servers or when WinRM is unavailable. + +### Basic SSH Connection +```powershell +ssh username@SERVER01 # Connect to server +ssh admin@192.168.1.50 # Connect by IP +ssh -p 2222 admin@SERVER01 # Custom port +ssh admin@SERVER01 "hostname && uptime" # Run a command without interactive shell +``` + +### SSH Key Management +```powershell +# Generate an SSH key pair +ssh-keygen -t ed25519 -C "admin@company.com" + +# Copy public key to remote server (Linux target) +ssh-copy-id admin@linuxserver01 + +# For Windows targets, append to authorized_keys manually +$key = Get-Content "$env:USERPROFILE\.ssh\id_ed25519.pub" +Invoke-Command -HostName SERVER01 -UserName admin -ScriptBlock { + Add-Content "C:\ProgramData\ssh\administrators_authorized_keys" $using:key +} +``` + +### SSH Config File (~/.ssh/config) +``` +# Create C:\Users\YourName\.ssh\config to save connection shortcuts + +Host webserver + HostName 10.0.0.20 + User admin + IdentityFile ~/.ssh/id_ed25519 + +Host jumpbox + HostName bastion.company.com + User sysadmin + ForwardAgent yes +``` +```powershell +ssh webserver # Now connects using saved config +``` +> The SSH config file saves connection shortcuts so you don't need to retype IPs, usernames, and key paths every time. + +### PowerShell 7 SSH Remoting (Invoke-Command over SSH) +```powershell +# Works with both Windows and Linux targets +Invoke-Command -HostName linux01 -UserName root -ScriptBlock { uname -a } +Enter-PSSession -HostName SERVER01 -UserName admin + +# Create persistent SSH-based session +$sshSession = New-PSSession -HostName SERVER01 -UserName admin +Invoke-Command -Session $sshSession -ScriptBlock { Get-Process } +``` +> PowerShell 7 SSH remoting is particularly useful for **managing Linux servers from Windows** using the same PowerShell commands you already know. + +--- + +## Alternatives When WinRM Is Not Available + +> WinRM may be blocked by firewalls, disabled by policy, or not yet configured. These are your options. + +### Option 1 — RDP (Remote Desktop) via PowerShell +```powershell +# Launch RDP session to a server +mstsc /v:SERVER01 +mstsc /v:SERVER01 /admin # Connect to console session +mstsc /v:SERVER01:3390 # Custom RDP port + +# Check if RDP port is open before connecting +Test-NetConnection SERVER01 -Port 3389 + +# Enable RDP on a remote machine (requires admin share access) +Invoke-Command -ComputerName SERVER01 -ScriptBlock { + Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Terminal Server" ` + -Name "fDenyTSConnections" -Value 0 + Enable-NetFirewallRule -DisplayGroup "Remote Desktop" +} +``` + +### Option 2 — PsExec (Sysinternals) +```powershell +# Download from Microsoft Sysinternals, then: +.\PsExec.exe \\SERVER01 cmd +.\PsExec.exe \\SERVER01 -u DOMAIN\admin -p password cmd +.\PsExec.exe \\SERVER01 powershell -Command "Get-Service" +.\PsExec.exe \\SERVER01 -s powershell # Run as SYSTEM account +``` +> PsExec uses **admin shares (C$, IPC$) over SMB** — it does not need WinRM. Very useful for one-off command execution on servers where remoting isn't set up. Requires the admin$ share to be accessible and the Remote Registry service running. + +### Option 3 — Admin Shares (UNC Path Access) +```powershell +# Access a remote server's filesystem directly via admin shares +Get-ChildItem \\SERVER01\C$\Logs +Get-ChildItem \\SERVER01\C$\Windows\System32\winevt\Logs + +# Copy files to/from remote server +Copy-Item \\SERVER01\C$\Logs\app.log C:\LocalLogs\ +Copy-Item C:\Scripts\fix.ps1 \\SERVER01\C$\Scripts\ + +# Map a drive to a remote share +New-PSDrive -Name S -PSProvider FileSystem -Root \\SERVER01\C$ -Credential "DOMAIN\admin" +Get-ChildItem S:\Logs +Remove-PSDrive S +``` +> Admin shares (`\\server\C$`, `\\server\Admin$`) let you **browse and copy files without WinRM** as long as you have admin rights and SMB (port 445) is accessible. Works even on older servers. + +### Option 4 — WMI / CIM (Windows Management Instrumentation) +```powershell +# Query remote system info via WMI (older, uses DCOM — port 135 + dynamic ports) +Get-WmiObject -Class Win32_OperatingSystem -ComputerName SERVER01 +Get-WmiObject -Class Win32_Service -ComputerName SERVER01 | Where-Object {$_.State -eq "Running"} + +# CIM is the modern replacement for WMI (uses WinRM by default, falls back to DCOM) +Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName SERVER01 +Get-CimInstance -ClassName Win32_LogicalDisk -ComputerName SERVER01 +Get-CimInstance -ClassName Win32_Service -ComputerName SERVER01 -Filter "State='Stopped'" + +# CIM over DCOM session (bypasses WinRM requirement) +$dcomOption = New-CimSessionOption -Protocol Dcom +$cimSession = New-CimSession -ComputerName SERVER01 -SessionOption $dcomOption -Credential "DOMAIN\admin" +Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $cimSession +Remove-CimSession $cimSession +``` +> WMI/CIM is powerful for **querying system info, hardware details, and running processes** without WinRM. CIM over DCOM is the go-to fallback when WinRM is blocked — uses port 135 and dynamic high ports. + +### Option 5 — Remote Registry +```powershell +# Requires Remote Registry service running on target +$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("LocalMachine", "SERVER01") +$key = $reg.OpenSubKey("SOFTWARE\Microsoft\Windows NT\CurrentVersion") +$key.GetValue("ProductName") +$reg.Close() +``` +> Useful for **reading or writing registry keys on remote servers** without any remoting protocol. Requires the Remote Registry service to be started on the target. + +### Option 6 — Scheduled Tasks (Push-and-Run Pattern) +```powershell +# 1. Copy your script to the remote server via admin share +Copy-Item C:\Scripts\RunMe.ps1 \\SERVER01\C$\Scripts\ + +# 2. Register a scheduled task to run it immediately +$action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-File C:\Scripts\RunMe.ps1" +$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddSeconds(10) +Register-ScheduledTask -TaskName "AdminRemoteRun" -Action $action -Trigger $trigger ` + -RunLevel Highest -CimSession (New-CimSession SERVER01) +``` +> The **push-and-run** pattern works when you can write files via admin shares but can't run commands interactively. Copy the script over SMB, schedule it to run, and collect output from a log file. + +### Option 7 — PowerShell Web Access (PSWA) +```powershell +# Install on a gateway server (run once, as Admin) +Install-WindowsFeature WindowsPowerShellWebAccess -IncludeManagementTools +Install-PswaWebApplication -UseTestCertificate +Add-PswaAuthorizationRule -UserName "DOMAIN\admin" -ComputerName * -ConfigurationName * +``` +> PSWA provides a **browser-based PowerShell console** over HTTPS — useful when you need remote admin access without VPN or direct RDP. Access via `https://gateway/pswa`. + +--- + +## Remote File Copies & Transfers + +### Copy-Item Over PSSession +```powershell +# Copy FROM remote server TO local machine +$s = New-PSSession -ComputerName SERVER01 +Copy-Item -Path "C:\Logs\app.log" -Destination "C:\LocalLogs\" -FromSession $s + +# Copy FROM local machine TO remote server +Copy-Item -Path "C:\Scripts\deploy.ps1" -Destination "C:\Scripts\" -ToSession $s + +# Copy an entire folder recursively +Copy-Item -Path "C:\App\Config" -Destination "C:\App\" -ToSession $s -Recurse + +Remove-PSSession $s +``` +> The most reliable way to copy files when WinRM is available. **Works through the existing PS session** — no file share needed. + +### Robocopy — Robust File Copy for Servers +```powershell +# Basic copy +robocopy \\SERVER01\C$\Logs C:\LocalLogs + +# Mirror a folder (exact copy, deletes extras at destination) +robocopy \\SERVER01\C$\WebApp C:\Backup\WebApp /MIR + +# Copy with logging +robocopy \\SERVER01\C$\Data C:\Backup\Data /E /LOG:C:\Logs\robocopy.log + +# Copy only changed files, retry on failure +robocopy \\SERVER01\C$\Data C:\Backup /E /Z /R:3 /W:5 + +# Useful flags +# /E = include subdirectories (including empty) +# /MIR = mirror (sync + delete) +# /Z = restartable mode (resume interrupted transfers) +# /R:3 = retry 3 times on failure +# /W:5 = wait 5 seconds between retries +# /LOG = write output to log file +# /NP = no progress (cleaner log output) +# /XF = exclude files, e.g. /XF *.tmp *.log +# /XD = exclude directories +``` +> Robocopy is the **standard tool for large or reliable file transfers** in Windows environments. Handles network interruptions, permissions, and large directory trees far better than Copy-Item. + +### SCP — Secure Copy (SSH-based) +```powershell +# Copy file TO a remote server +scp C:\Scripts\deploy.sh admin@linuxserver01:/opt/scripts/ + +# Copy file FROM a remote server +scp admin@linuxserver01:/var/log/app.log C:\Logs\ + +# Copy entire folder +scp -r C:\Config admin@linuxserver01:/opt/config/ + +# Use a specific identity file +scp -i ~/.ssh/id_ed25519 C:\file.txt admin@server01:/tmp/ +``` +> SCP is ideal for **transferring files to/from Linux servers or any SSH-accessible host**. Available natively in Windows 10/Server 2019+. + +### SFTP — Interactive File Transfer +```powershell +sftp admin@linuxserver01 + +# Inside SFTP session: +# ls - list remote files +# lls - list local files +# get remote.txt - download file +# put local.txt - upload file +# cd /var/log - change remote directory +# lcd C:\Logs - change local directory +# exit - quit +``` + +### BitsTransfer — Background File Transfer +```powershell +# Download a file in the background +Start-BitsTransfer -Source "\\SERVER01\Share\largefile.zip" ` + -Destination "C:\Downloads\largefile.zip" -Asynchronous + +# Check transfer status +Get-BitsTransfer + +# Wait for all transfers to complete +Get-BitsTransfer | Complete-BitsTransfer +``` +> BITS (Background Intelligent Transfer Service) is designed for **large file transfers that can be paused and resumed**, throttled to not saturate the network. Originally designed for Windows Update, it's great for large deployment files. + +--- + +## Remote System Administration + +### Restart & Shutdown +```powershell +Restart-Computer -ComputerName SERVER01 -Force +Restart-Computer -ComputerName SERVER01 -Credential "DOMAIN\admin" -Force +Restart-Computer -ComputerName SERVER01 -Wait -For PowerShell -Timeout 300 # Wait for reboot + +Restart-Computer -ComputerName SERVER01, SERVER02, SERVER03 -Force # Reboot multiple + +Stop-Computer -ComputerName SERVER01 -Force # Shutdown +``` + +### Remote Service Management +```powershell +# Check service status on remote server +Get-Service -ComputerName SERVER01 -Name "Spooler" +Get-Service -ComputerName SERVER01 | Where-Object {$_.Status -eq "Stopped"} + +# Start/stop/restart +(Get-Service -ComputerName SERVER01 -Name "Spooler").Start() +(Get-Service -ComputerName SERVER01 -Name "Spooler").Stop() + +# Via Invoke-Command for more control +Invoke-Command -ComputerName SERVER01 -ScriptBlock { + Restart-Service -Name "W3SVC" -Force + Get-Service "W3SVC" | Select-Object Name, Status +} +``` + +### Remote Process Management +```powershell +# List processes on remote server +Get-Process -ComputerName SERVER01 +Get-Process -ComputerName SERVER01 | Sort-Object CPU -Descending | Select-Object -First 10 + +# Kill a process remotely +Stop-Process -Id 1234 -Force # (Must be inside Invoke-Command for remote) +Invoke-Command -ComputerName SERVER01 -ScriptBlock { Stop-Process -Name "app.exe" -Force } +``` + +### Check Who Is Logged On +```powershell +# Query logged-in users (uses query.exe) +Invoke-Command -ComputerName SERVER01 -ScriptBlock { query user } + +# Via WMI +Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName SERVER01 | Select-Object UserName +``` + +### Remote Hotfix / Patch Check +```powershell +# Check installed patches on a remote server +Get-HotFix -ComputerName SERVER01 +Get-HotFix -ComputerName SERVER01 | Sort-Object InstalledOn -Descending | Select-Object -First 10 + +# Check multiple servers +$servers = @("SERVER01", "SERVER02", "SERVER03") +Invoke-Command -ComputerName $servers -ScriptBlock { + Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 1 +} | Select-Object PSComputerName, HotFixID, InstalledOn +``` + +--- + +## Active Directory + +> Requires the `ActiveDirectory` module (part of RSAT — Remote Server Administration Tools). +> Install: `Add-WindowsCapability -Name Rsat.ActiveDirectory* -Online` + +```powershell +Import-Module ActiveDirectory # Load the module + +# --- Users --- +Get-ADUser -Identity jsmith # Find a user +Get-ADUser -Filter {Name -like "John*"} # Search by name +Get-ADUser -Identity jsmith -Properties * # All properties +Get-ADUser -Filter {Enabled -eq $false} # Disabled accounts +Get-ADUser -Filter * -SearchBase "OU=Staff,DC=corp,DC=com" # Users in specific OU + +# Unlock, enable, disable +Unlock-ADAccount -Identity jsmith +Enable-ADAccount -Identity jsmith +Disable-ADAccount -Identity jsmith + +# Reset password +Set-ADAccountPassword -Identity jsmith -Reset ` + -NewPassword (ConvertTo-SecureString "NewP@ss123!" -AsPlainText -Force) +Set-ADUser -Identity jsmith -ChangePasswordAtLogon $true + +# --- Groups --- +Get-ADGroup -Identity "Domain Admins" +Get-ADGroupMember -Identity "Domain Admins" +Add-ADGroupMember -Identity "VPN_Users" -Members jsmith +Remove-ADGroupMember -Identity "VPN_Users" -Members jsmith -Confirm:$false + +# --- Computers --- +Get-ADComputer -Identity SERVER01 +Get-ADComputer -Filter {OperatingSystem -like "*Server 2022*"} +Get-ADComputer -Filter * | Where-Object {$_.LastLogonDate -lt (Get-Date).AddDays(-90)} # Stale + +# --- Password expiry --- +Get-ADUser -Filter * -Properties PasswordLastSet, PasswordExpired | + Where-Object { $_.PasswordExpired -eq $true } | + Select-Object Name, PasswordLastSet +``` + +--- + +## DNS & DHCP Management + +```powershell +# --- DNS (requires DnsServer module or RSAT) --- +Get-DnsServerZone -ComputerName DNS01 # List DNS zones +Get-DnsServerResourceRecord -ZoneName "corp.com" -ComputerName DNS01 # All records + +# Add an A record +Add-DnsServerResourceRecordA -Name "webserver" -ZoneName "corp.com" ` + -IPv4Address "10.0.0.50" -ComputerName DNS01 + +# Remove a record +Remove-DnsServerResourceRecord -ZoneName "corp.com" -RRType "A" -Name "webserver" -Force + +# Flush DNS cache on remote server +Invoke-Command -ComputerName SERVER01 -ScriptBlock { Clear-DnsClientCache } +Invoke-Command -ComputerName DNS01 -ScriptBlock { Clear-DnsServerCache } + +# --- DHCP (requires DhcpServer module or RSAT) --- +Get-DhcpServerv4Scope -ComputerName DHCP01 # List scopes +Get-DhcpServerv4Lease -ScopeId 10.0.0.0 -ComputerName DHCP01 # Active leases +Get-DhcpServerv4Reservation -ScopeId 10.0.0.0 -ComputerName DHCP01 # Reservations + +# Add a DHCP reservation +Add-DhcpServerv4Reservation -ScopeId 10.0.0.0 -IPAddress 10.0.0.100 ` + -ClientId "AA-BB-CC-DD-EE-FF" -Description "Printer" -ComputerName DHCP01 +``` + +--- + +## Disk & Storage Management + +```powershell +# Local and remote disk info +Get-PSDrive -PSProvider FileSystem # Drives and free space +Get-Volume # Volume details +Get-Disk # Physical disks +Get-Partition # Partition layout + +# Remote disk check via CIM +Get-CimInstance Win32_LogicalDisk -ComputerName SERVER01 | + Select-Object DeviceID, + @{N="SizeGB";E={[math]::Round($_.Size/1GB,1)}}, + @{N="FreeGB";E={[math]::Round($_.FreeSpace/1GB,1)}}, + @{N="Free%";E={[math]::Round($_.FreeSpace/$_.Size*100,1)}} + +# Check all servers for low disk space (under 15% free) +$servers = @("SERVER01","SERVER02","SERVER03") +Invoke-Command -ComputerName $servers -ScriptBlock { + Get-PSDrive -PSProvider FileSystem | + Where-Object { ($_.Free / ($_.Used + $_.Free)) -lt 0.15 } | + Select-Object Name, Used, Free, + @{N="Free%";E={[math]::Round($_.Free/($_.Used+$_.Free)*100,1)}} +} | Select-Object PSComputerName, Name, Free, "Free%" +``` + +--- + +## Event Logs + +```powershell +# Read event logs (local or remote) +Get-EventLog -LogName System -Newest 50 +Get-EventLog -LogName System -ComputerName SERVER01 -Newest 50 +Get-EventLog -LogName Application -EntryType Error -Newest 20 +Get-EventLog -LogName System -Source "Service Control Manager" -Newest 20 +Get-EventLog -LogName System -After (Get-Date).AddHours(-24) # Last 24 hours + +# Modern method using Get-WinEvent (more powerful, supports all logs) +Get-WinEvent -LogName System -MaxEvents 50 +Get-WinEvent -LogName "Microsoft-Windows-TaskScheduler/Operational" -MaxEvents 20 + +# Filter by event ID +Get-WinEvent -FilterHashtable @{ + LogName = "System" + Id = 7036 # Service started/stopped events + StartTime = (Get-Date).AddDays(-1) +} + +# Search for failed logins (Event ID 4625) +Get-WinEvent -ComputerName SERVER01 -FilterHashtable @{ + LogName = "Security" + Id = 4625 + StartTime = (Get-Date).AddHours(-24) +} | Select-Object TimeCreated, Message + +# Export event log to CSV +Get-EventLog -LogName System -Newest 100 | + Select-Object TimeGenerated, EntryType, Source, Message | + Export-Csv "C:\Logs\system-events.csv" -NoTypeInformation +``` + +--- + +## Windows Updates + +> Requires `PSWindowsUpdate` module: `Install-Module PSWindowsUpdate -Force` + +```powershell +Import-Module PSWindowsUpdate + +# Check for available updates +Get-WindowsUpdate + +# Install all updates +Install-WindowsUpdate -AcceptAll -AutoReboot + +# Install on a remote server +Invoke-WUJob -ComputerName SERVER01 -Script { + Import-Module PSWindowsUpdate + Install-WindowsUpdate -AcceptAll -AutoReboot | Out-File C:\Logs\WU.log +} -Confirm:$false + +# Check update history +Get-WUHistory | Select-Object -First 20 +Get-WUHistory -ComputerName SERVER01 | Where-Object {$_.Result -ne "Succeeded"} + +# Check last update time without module +Get-HotFix -ComputerName SERVER01 | Sort-Object InstalledOn -Descending | Select-Object -First 1 +``` + +--- + +## Certificates + +```powershell +# List certificates in local stores +Get-ChildItem Cert:\LocalMachine\My # Personal (server certs) +Get-ChildItem Cert:\LocalMachine\Root # Trusted root CAs +Get-ChildItem Cert:\CurrentUser\My # Current user certs + +# Find expiring certificates (within 60 days) +Get-ChildItem -Path Cert:\LocalMachine\My | + Where-Object { $_.NotAfter -lt (Get-Date).AddDays(60) } | + Select-Object Subject, Thumbprint, NotAfter + +# Check certs on a remote server +Invoke-Command -ComputerName SERVER01 -ScriptBlock { + Get-ChildItem Cert:\LocalMachine\My | + Where-Object { $_.NotAfter -lt (Get-Date).AddDays(60) } | + Select-Object Subject, NotAfter +} + +# Export a certificate (no private key) +Export-Certificate -Cert (Get-Item Cert:\LocalMachine\My\) ` + -FilePath "C:\Certs\server.cer" + +# Import a certificate +Import-Certificate -FilePath "C:\Certs\server.cer" -CertStoreLocation Cert:\LocalMachine\Root +``` + +--- + +## Scheduled Tasks (Remote) + +```powershell +# List tasks on a remote server +Get-ScheduledTask -CimSession (New-CimSession SERVER01) +Get-ScheduledTask -CimSession (New-CimSession SERVER01) | Where-Object {$_.State -eq "Ready"} + +# Run a scheduled task immediately on a remote server +Invoke-Command -ComputerName SERVER01 -ScriptBlock { + Start-ScheduledTask -TaskName "DailyBackup" +} + +# Check last run result of a task +Get-ScheduledTaskInfo -TaskName "DailyBackup" -CimSession (New-CimSession SERVER01) | + Select-Object LastRunTime, LastTaskResult, NextRunTime + +# 0 = success; anything else is an error code +``` + +--- + +## Registry (Remote) + +```powershell +# Read a remote registry key via Invoke-Command +Invoke-Command -ComputerName SERVER01 -ScriptBlock { + Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" | + Select-Object ProductName, CurrentBuild, ReleaseId +} + +# Write a registry value remotely +Invoke-Command -ComputerName SERVER01 -ScriptBlock { + Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" ` + -Name "SMB1" -Value 0 -Type DWORD +} + +# Check if SMBv1 is enabled across multiple servers +$servers = @("SERVER01","SERVER02","SERVER03") +Invoke-Command -ComputerName $servers -ScriptBlock { + $val = Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" ` + -Name "SMB1" -ErrorAction SilentlyContinue + [PSCustomObject]@{ + Server = $env:COMPUTERNAME + SMBv1 = if ($val.SMB1 -eq 0) { "Disabled" } else { "Enabled or Not Set" } + } +} +``` + +--- + +## Firewall Management + +```powershell +# View rules +Get-NetFirewallRule | Where-Object {$_.Enabled -eq "True" -and $_.Direction -eq "Inbound"} +Get-NetFirewallRule -DisplayName "*Remote*" +Get-NetFirewallRule | Where-Object {$_.Action -eq "Block"} + +# Add a rule +New-NetFirewallRule -DisplayName "Allow HTTPS Inbound" ` + -Direction Inbound -Protocol TCP -LocalPort 443 -Action Allow + +New-NetFirewallRule -DisplayName "Block Telnet" ` + -Direction Inbound -Protocol TCP -LocalPort 23 -Action Block + +# Enable/disable a rule +Enable-NetFirewallRule -DisplayName "Remote Desktop - User Mode (TCP-In)" +Disable-NetFirewallRule -DisplayName "Remote Desktop - User Mode (TCP-In)" + +# Remote firewall management via Invoke-Command +Invoke-Command -ComputerName SERVER01 -ScriptBlock { + New-NetFirewallRule -DisplayName "Allow App Port 8080" ` + -Direction Inbound -Protocol TCP -LocalPort 8080 -Action Allow +} +``` + +--- + +## Performance & Health Checks + +```powershell +# CPU usage (top processes) +Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 Name, Id, CPU + +# Memory usage +Get-CimInstance Win32_OperatingSystem | + Select-Object @{N="TotalGB";E={[math]::Round($_.TotalVisibleMemorySize/1MB,1)}}, + @{N="FreeGB"; E={[math]::Round($_.FreePhysicalMemory/1MB,1)}} + +# Remote CPU and memory check across multiple servers +$servers = @("SERVER01","SERVER02","SERVER03") +Invoke-Command -ComputerName $servers -ScriptBlock { + $os = Get-CimInstance Win32_OperatingSystem + $cpu = (Get-CimInstance Win32_Processor | Measure-Object LoadPercentage -Average).Average + [PSCustomObject]@{ + Server = $env:COMPUTERNAME + "CPU%" = $cpu + "MemFreeGB" = [math]::Round($os.FreePhysicalMemory/1MB, 1) + "Uptime" = (Get-Date) - $os.LastBootUpTime + } +} | Select-Object PSComputerName, "CPU%", MemFreeGB, Uptime + +# Check uptime +(Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime + +# Remote uptime check +Invoke-Command -ComputerName SERVER01 -ScriptBlock { + $os = Get-CimInstance Win32_OperatingSystem + $up = (Get-Date) - $os.LastBootUpTime + "Uptime: {0} days, {1} hours, {2} min" -f $up.Days, $up.Hours, $up.Minutes +} +``` + +--- + +## Quick Diagnostic One-Liners + +```powershell +# Is a server reachable? +Test-Connection SERVER01 -Count 2 -Quiet + +# What ports are listening on a server? +Invoke-Command -ComputerName SERVER01 -ScriptBlock { + Get-NetTCPConnection -State Listen | Sort-Object LocalPort +} + +# Who has a file locked? +Invoke-Command -ComputerName FILESERVER01 -ScriptBlock { + Get-SmbOpenFile | Where-Object { $_.Path -like "*report.xlsx*" } +} + +# What's sharing on a server? +Get-SmbShare -CimSession (New-CimSession SERVER01) + +# Which servers in a list are online? +$servers = @("SERVER01","SERVER02","SERVER03","SERVER04") +$servers | ForEach-Object { + [PSCustomObject]@{ + Server = $_ + Online = (Test-Connection $_ -Count 1 -Quiet) + } +} + +# Check if a service exists and is running on multiple servers +$servers = @("SERVER01","SERVER02") +Invoke-Command -ComputerName $servers -ScriptBlock { + Get-Service -Name "W3SVC" -ErrorAction SilentlyContinue | + Select-Object MachineName, Name, Status +} + +# Get last reboot time across servers +$servers = @("SERVER01","SERVER02","SERVER03") +Invoke-Command -ComputerName $servers -ScriptBlock { + (Get-CimInstance Win32_OperatingSystem).LastBootUpTime +} | Select-Object PSComputerName, @{N="LastBoot";E={$_}} + +# Find large files on a remote server +Invoke-Command -ComputerName SERVER01 -ScriptBlock { + Get-ChildItem C:\Logs -Recurse -File | + Sort-Object Length -Descending | + Select-Object FullName, @{N="SizeMB";E={[math]::Round($_.Length/1MB,1)}} | + Select-Object -First 20 +} + +# Check pending reboots +Invoke-Command -ComputerName SERVER01 -ScriptBlock { + $rebootKeys = @( + "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending", + "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" + ) + $pending = $rebootKeys | Where-Object { Test-Path $_ } + if ($pending) { "REBOOT PENDING" } else { "No reboot required" } +} +``` + +--- + +## Connection Method Summary + +| Method | Requires | Port | Best For | +|--------|----------|------|----------| +| `Enter-PSSession` | WinRM enabled | 5985/5986 | Interactive remote shell | +| `Invoke-Command` | WinRM enabled | 5985/5986 | Run scripts on one or many servers | +| SSH (`ssh`) | OpenSSH service | 22 | Linux targets, no WinRM | +| PsExec | Admin share, SMB | 445 | Quick commands, no WinRM setup | +| Admin Shares (`\\server\C$`) | SMB, admin rights | 445 | File access without remoting | +| CIM over DCOM | DCOM, RPC | 135 + dynamic | WMI queries without WinRM | +| RDP (`mstsc`) | RDP enabled | 3389 | GUI access | +| Remote Registry | Remote Registry svc | 445 | Registry edits without remoting | +| PSWA | IIS + PSWA role | 443 | Browser-based shell, no VPN | + +--- + +*Last updated: 2026 | Tested on Windows Server 2016–2022 / PowerShell 5.1 and 7.x* \ No newline at end of file