Files
TestRepo/PowerShell_HowToo_Part1.md
2026-03-11 11:16:02 +00:00

838 lines
30 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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*