In today's fast-paced digital landscape, it is crucial for organizations to efficiently monitor and manage their infrastructure's resource utilization. High resource consumption or misconfigured open ports can lead to performance issues, downtimes, and security vulnerabilities. To address these concerns, we present a PowerShell script that provides valuable insights into the resource usage and open ports of the environment where an application is running. This script allows administrators to identify potential bottlenecks and optimize their systems for better performance and security.
Understanding the PowerShell Script:
The PowerShell script is designed to gather real-time data on CPU, memory, I/O usage, network interface status, open ports, and running processes. The data is collected periodically and stored in separate CSV files for further analysis.
Duration and Data Collection Interval:
The script is equipped with a customizable duration, allowing users to define how long the monitoring process should run. For instance, setting the duration to 20 minutes will continuously collect data for the specified timeframe.
Data Collected and Their Significance:
-
General Usage Data:
- CPU Usage: Monitors the CPU load percentage to identify potential performance bottlenecks.
- Memory Usage: Tracks the percentage of used memory to assess memory requirements and prevent memory-related issues.
-
Network Usage Data:
- Interface Status: Records the status (Up/Down) of all network interfaces, offering insights into connectivity health.
- Description and Name: Provides details about each network interface, facilitating identification and troubleshooting.
-
Ports Usage Data:
- Protocol: Logs the protocol used by each open port to ascertain potential security risks.
- Local and Foreign Addresses: Captures IP addresses and port numbers to identify incoming and outgoing connections.
- State: Reveals the state of each port (Listening, Established, etc.), aiding in identifying active connections.
- Process ID and Application Name: Associates open ports with corresponding processes, helping in resource allocation and security analysis.
-
Processes Usage Data:
- Process Name and ID: Lists all running processes along with their unique IDs for process identification.
- CPU, Memory, and Virtual Memory Usage: Provides resource consumption statistics for each running process.
- Handles: Indicates the number of handles used by each process, which can help identify resource leaks.
DNS Resolution Verification:
The script also performs DNS resolution verification for a specified list of server names. This ensures that DNS records are correctly resolving, preventing potential connectivity issues.
Conclusion:
With this comprehensive PowerShell script, administrators can gain deeper insights into their infrastructure's performance and resource utilization. By monitoring CPU, memory, I/O, network interfaces, open ports, and running processes, organizations can identify and address potential issues proactively. Armed with this knowledge, IT teams can optimize their systems for maximum efficiency and security, ensuring smooth and uninterrupted operations.
I hope this article provides valuable information about the PowerShell script as an example and its capabilities for monitoring resource usage and open ports.
# Define the duration for script execution (in minutes)
$durationMinutes = 20
$intervalSeconds = 120
$endTime = (Get-Date).AddMinutes($durationMinutes)
# User-specified output path
$outputPath = "C:\temp\OutputFolder" # Replace with the desired output folder path
# List of server names for DNS resolution verification
$serverNames = @(
"myserverexample.database.windows.net",
"example.com",
"nonexistentserver12345.com"
)
# Function to log messages to console and a log file
function Log-Message {
param (
[string]$Message,
[string]$timestamp
)
Write-Output "$timestamp - $Message"
$logFilePath = Join-Path -Path $outputPath -ChildPath "ScriptLog.log"
"$timestamp - $Message" | Out-File -FilePath $logFilePath -Append
}
# Function to gather general CPU, memory, and I/O usage
function Get-GeneralUsageData {
param (
[string]$timestamp
)
$cpuUsage = Get-WmiObject -Class Win32_Processor | Select-Object -ExpandProperty LoadPercentage
$memoryUsage = Get-WmiObject -Class Win32_OperatingSystem | Select-Object -Property @{Name = "MemoryUsage(%)"; Expression = { [math]::Round(($_.TotalVisibleMemorySize - $_.FreePhysicalMemory) / $_.TotalVisibleMemorySize * 100, 2) } }
$usageData = [PSCustomObject]@{
Timestamp = $timestamp
CPUUsage = $cpuUsage
MemoryUsage = $memoryUsage."MemoryUsage(%)"
}
return $usageData
}
# Function to gather network interface status, description, and name for UP adapters
function Get-NetworkUsageData {
param (
[string]$timestamp
)
$networkInfo = Get-NetAdapter | Where-Object { $_.Status -eq "Up" }
$networkData = foreach ($adapter in $networkInfo) {
$status = $adapter.Status
$description = $adapter.InterfaceDescription
[PSCustomObject]@{
Timestamp = $timestamp
Status = $status
Description = $description
}
}
return $networkData
}
# Function to gather ports usage data
function Get-PortsUsageData {
param (
[string]$timestamp
)
$netstatOutput = netstat -ano
$portsData = $netstatOutput | ForEach-Object {
$line = $_.Trim() -replace '\s+', ' '
$parts = $line -split ' '
$protocol = $parts[0]
$localAddress = $parts[1]
$foreignAddress = $parts[2]
$state = $parts[3]
$processId = $parts[-1]
if (-not [string]::IsNullOrWhiteSpace($processId) -and $processId -match '^\d+$') {
$process = Get-Process -Id $processId -ErrorAction SilentlyContinue
if ($process) {
$appName = $process.Name
}
else {
$appName = "N/A"
}
}
else {
$processId = "N/A"
$appName = "N/A"
}
[PSCustomObject]@{
Timestamp = $timestamp
Protocol = $protocol
LocalAddress = $localAddress
ForeignAddress = $foreignAddress
State = $state
ProcessId = $processId
ApplicationName = $appName
}
}
return $portsData
}
# Function to gather processes usage data
function Get-ProcessesUsageData {
param (
[string]$timestamp
)
$processes = Get-Process
$processesData = foreach ($process in $processes) {
$processName = $process.Name
$processId = $process.Id
$cpuUsage = $process.CPU
$memoryUsage = $process.WorkingSet
$virtualMemory = $process.VirtualMemorySize
$handles = $process.Handles
[PSCustomObject]@{
Timestamp = $timestamp
ProcessName = $processName
ProcessId = $processId
CPUUsage = $cpuUsage
MemoryUsage = $memoryUsage
VirtualMemory = $virtualMemory
Handles = $handles
}
}
return $processesData
}
# Function to test DNS resolution for a list of server names
function Test-DnsResolution {
param (
[string]$timestamp
)
$dnsResolutionData = foreach ($server in $serverNames) {
$startTime = Get-Date
try {
$ipAddress = [System.Net.Dns]::GetHostAddresses($server) | Select-Object -ExpandProperty IPAddressToString
$endTime = Get-Date
$timeTaken = ($endTime - $startTime).TotalMilliseconds
$result = "Resolved"
}
catch {
$ipAddress = "N/A"
$timeTaken = "N/A"
$result = "Failed to resolve"
}
[PSCustomObject]@{
Timestamp = $timestamp
ServerName = $server
IPAddress = $ipAddress
TimeTakenMilliseconds = $timeTaken
Result = $result
}
}
return $dnsResolutionData
}
# Function to save data to a CSV file
function Save-DataToCsv {
param(
[Parameter(Mandatory = $true)]
[string]$FilePath,
[Parameter(Mandatory = $true)]
[array]$Data
)
$logFilePath = Join-Path -Path $outputPath -ChildPath $FilePath
$Data | Export-Csv -Path $logFilePath -NoTypeInformation -Append
}
# Create the output folder if it doesn't exist
if (-Not (Test-Path -Path $outputPath -PathType Container)) {
New-Item -ItemType Directory -Path $outputPath | Out-Null
}
# Infinite loop for continuous monitoring until the specified duration
while ((Get-Date) -lt $endTime) {
$timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
Log-Message "Starting data collection iteration..." -timestamp $timestamp
# Gather data
Log-Message "Gathering general usage data..." -timestamp $timestamp
$generalUsageData = Get-GeneralUsageData -timestamp $timestamp
Log-Message "Gathering network usage data..." -timestamp $timestamp
$networkUsageData = Get-NetworkUsageData -timestamp $timestamp
Log-Message "Gathering ports usage data..." -timestamp $timestamp
$portsUsageData = Get-PortsUsageData -timestamp $timestamp
Log-Message "Gathering processes usage data..." -timestamp $timestamp
$processesUsageData = Get-ProcessesUsageData -timestamp $timestamp
Log-Message "Performing DNS resolution verification..." -timestamp $timestamp
$dnsResolutionData = Test-DnsResolution -timestamp $timestamp
# Save data to CSV
Save-DataToCsv -FilePath "GeneralUsage.csv" -Data $generalUsageData
Save-DataToCsv -FilePath "NetworkUsage.csv" -Data $networkUsageData
Save-DataToCsv -FilePath "PortsUsage.csv" -Data $portsUsageData
Save-DataToCsv -FilePath "ProcessesUsage.csv" -Data $processesUsageData
Save-DataToCsv -FilePath "DnsResolution.csv" -Data $dnsResolutionData
Log-Message "Data collection iteration completed." -timestamp $timestamp
# Wait for the interval before the next iteration
Start-Sleep -Seconds $intervalSeconds
}
I would like to share a small linux version about the previous code:
#!/bin/bash
# Define the duration for script execution (in minutes)
durationMinutes=20
intervalSeconds=120
endTime=$((SECONDS + durationMinutes*60))
# User-specified output path
outputPath="/tmp/OutputFolder" # Replace with the desired output folder path
# List of server names for DNS resolution verification
serverNames=(
"myserver.database.windows.net"
"example.com"
"nonexistentserver12345.com"
)
# Function to log messages to console and a log file
function log_message {
local message="$1"
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
echo "$timestamp - $message"
echo "$timestamp - $message" >> "$outputPath/ScriptLog.log"
}
# Function to gather general CPU, memory, and I/O usage
function get_general_usage_data {
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
local cpuUsage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}')
local memoryUsage=$(free | grep Mem | awk '{print ($3/$2)*100}')
echo "Timestamp,CPUUsage(%),MemoryUsage(%)"
echo "$timestamp,$cpuUsage,$memoryUsage"
}
# Function to gather network interface status and description for UP adapters
function get_network_usage_data {
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
local networkInfo=$(ip link show up)
echo "Timestamp,Status,Description"
while read -r line; do
local interface=$(echo "$line" | awk '{print $2}' | cut -d':' -f1)
local status=$(echo "$line" | grep -o 'state [^ ]*' | awk '{print $2}')
local description=$(echo "$line" | awk '{print $9}')
echo "$timestamp,$status,$description"
done <<< "$networkInfo"
}
# Function to gather ports usage data
function get_ports_usage_data {
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
local netstatOutput=$(netstat -anop)
echo "Timestamp,Protocol,LocalAddress,ForeignAddress,State,ProcessID,ApplicationName"
while read -r line; do
local protocol=$(echo "$line" | awk '{print $1}')
local localAddress=$(echo "$line" | awk '{print $4}')
local foreignAddress=$(echo "$line" | awk '{print $5}')
local state=$(echo "$line" | awk '{print $6}')
local processId=$(echo "$line" | awk '{print $7}')
local appName=""
if [[ ! -z "$processId" && "$processId" =~ ^[0-9]+$ ]]; then
appName=$(ps -p "$processId" -o comm=)
else
processId="N/A"
fi
echo "$timestamp,$protocol,$localAddress,$foreignAddress,$state,$processId,$appName"
done <<< "$netstatOutput"
}
# Function to gather processes usage data
function get_processes_usage_data {
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
local processes=$(ps -eo pid,comm,%cpu,%mem,rss,vsz,uname)
echo "Timestamp,ProcessID,ProcessName,CPUUsage(%),MemoryUsage(RSS KB),VirtualMemory(VSZ KB),UserName"
while read -r line; do
local processId=$(echo "$line" | awk '{print $1}')
local processName=$(echo "$line" | awk '{print $2}')
local cpuUsage=$(echo "$line" | awk '{print $3}')
local memoryUsage=$(echo "$line" | awk '{print $5}')
local virtualMemory=$(echo "$line" | awk '{print $6}')
local userName=$(echo "$line" | awk '{print $7}')
echo "$timestamp,$processId,$processName,$cpuUsage,$memoryUsage,$virtualMemory,$userName"
done <<< "$processes"
}
# Function to test DNS resolution for a list of server names
function test_dns_resolution {
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
echo "Timestamp,ServerName,IPAddress,TimeTakenMilliseconds,Result"
for server in "${serverNames[@]}"; do
local startTime=$(date +%s%3N)
ipAddress=$(getent ahosts "$server" | awk '/STREAM/ {print $1; exit}')
local endTime=$(date +%s%3N)
local timeTaken=$((endTime - startTime))
local result="Resolved"
if [ -z "$ipAddress" ]; then
ipAddress="N/A"
timeTaken="N/A"
result="Failed to resolve"
fi
echo "$timestamp,$server,$ipAddress,$timeTaken,$result"
done
}
# Function to save data to a CSV file
function save_data_to_csv {
local filePath="$1"
local data="$2"
echo "$data" >> "$outputPath/$filePath"
}
# Create the output folder if it doesn't exist
mkdir -p "$outputPath"
# Infinite loop for continuous monitoring until the specified duration
while [ $SECONDS -lt $endTime ]; do
timestamp=$(date +"%Y-%m-%d %H:%M:%S")
log_message "Starting data collection iteration..." "$timestamp"
# Gather data
log_message "Gathering general usage data..." "$timestamp"
generalUsageData=$(get_general_usage_data)
log_message "Gathering network usage data..." "$timestamp"
networkUsageData=$(get_network_usage_data)
log_message "Gathering ports usage data..." "$timestamp"
portsUsageData=$(get_ports_usage_data)
log_message "Gathering processes usage data..." "$timestamp"
processesUsageData=$(get_processes_usage_data)
log_message "Performing DNS resolution verification..." "$timestamp"
dnsResolutionData=$(test_dns_resolution)
# Save data to CSV
save_data_to_csv "GeneralUsage.csv" "$generalUsageData"
save_data_to_csv "NetworkUsage.csv" "$networkUsageData"
save_data_to_csv "PortsUsage.csv" "$portsUsageData"
save_data_to_csv "ProcessesUsage.csv" "$processesUsageData"
save_data_to_csv "DnsResolution.csv" "$dnsResolutionData"
log_message "Data collection iteration completed." "$timestamp"
# Wait for the interval before the next iteration
sleep $intervalSeconds
done
Enjoy!