Add PowerShell_HowToo_Part1.md

This commit is contained in:
2026-03-11 11:16:02 +00:00
parent eb77392e79
commit 018d3a9aa2

838
PowerShell_HowToo_Part1.md Normal file
View File

@@ -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\<Thumbprint>) `
-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 20162022 / PowerShell 5.1 and 7.x*