Add PowerShell_HowToo_Part1.md
This commit is contained in:
838
PowerShell_HowToo_Part1.md
Normal file
838
PowerShell_HowToo_Part1.md
Normal 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 2016–2022 / PowerShell 5.1 and 7.x*
|
||||
Reference in New Issue
Block a user