Skip to content

Commit 3f53b39

Browse files
author
Don Johnson
committed
change book
boom
1 parent d1f3393 commit 3f53b39

File tree

1 file changed

+197
-0
lines changed

1 file changed

+197
-0
lines changed

windows-server-check/check_2.ps1

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
<#
2+
.SYNOPSIS
3+
Secure Network OS-level discovery tool using a service account.
4+
5+
.DESCRIPTION
6+
- This refactored script avoids storing the service account password
7+
in plain text or script parameters.
8+
- Instead, it either prompts for credentials (Approach A) or retrieves
9+
them securely from the Windows Credential Manager (Approach B).
10+
- Recommends using WinRM over HTTPS or a secured WMI channel to mitigate
11+
network-level security concerns.
12+
13+
.NOTES
14+
- You must have RSAT (or equivalent AD modules) to run ActiveDirectory commands.
15+
- Ensure remote hosts allow secure WMI or WinRM communication.
16+
- Requires PowerShell 7+ for ThreadJobs (or adjust accordingly).
17+
#>
18+
19+
param(
20+
[switch]$UseWinRM # Toggle to demonstrate WinRM approach instead of WMI
21+
)
22+
23+
Import-Module ActiveDirectory -ErrorAction Stop
24+
25+
# -----------------------
26+
# Choose either Approach A or Approach B
27+
# -----------------------
28+
29+
# APPROACH A: Prompt the user for credentials at runtime.
30+
# $credential = Get-Credential -Message "Please enter the service account credentials"
31+
32+
# APPROACH B: Retrieve credentials from the Windows Credential Manager.
33+
# To use this approach:
34+
# 1) Ensure you've stored credentials in Windows Credential Manager
35+
# e.g., via cmdkey.exe:
36+
# cmdkey /add:MYDOMAIN\ServiceAccount /user:MYDOMAIN\ServiceAccount /pass
37+
# 2) Then set $TargetCredentialName accordingly.
38+
# 3) Use the CredentialManager module or a custom function (below) to retrieve it.
39+
40+
$TargetCredentialName = "MYDOMAIN\\ServiceAccount"
41+
42+
function Get-StoredCredential {
43+
param(
44+
[Parameter(Mandatory=$true)]
45+
[string]$TargetName
46+
)
47+
# This function requires the CredentialManager module or a custom method to pull from Windows.
48+
# In PowerShell 7+, you can install the 'CredentialManager' module from the PSGallery:
49+
# Install-Module CredentialManager
50+
# Then:
51+
# return Get-StoredCredential -Target $TargetName
52+
#
53+
# For demonstration, here's a simplified example:
54+
try {
55+
if (Get-Module -ListAvailable -Name CredentialManager) {
56+
Import-Module CredentialManager -ErrorAction Stop
57+
$cred = Get-StoredCredential -Target $TargetName
58+
if (!$cred) {
59+
throw "No stored credential found for $TargetName."
60+
}
61+
return $cred
62+
}
63+
else {
64+
throw "The CredentialManager module is not installed. Please install it or switch to Approach A."
65+
}
66+
}
67+
catch {
68+
Write-Error "[!] Failed to retrieve stored credential: $($_.Exception.Message)"
69+
return $null
70+
}
71+
}
72+
73+
# Uncomment whichever approach you prefer:
74+
# $credential = Get-Credential -Message "Please enter the service account credentials"
75+
$credential = Get-StoredCredential -TargetName $TargetCredentialName
76+
77+
if (-not $credential) {
78+
Write-Error "[!] No credential found or provided. Exiting script."
79+
return
80+
}
81+
82+
# -----------------------
83+
# 1. Get all domain-joined computers
84+
# -----------------------
85+
Write-Host "[*] Retrieving computers from Active Directory..."
86+
87+
try {
88+
# Example: Retrieve all computers
89+
# For security, consider filtering by specific OU or computer name pattern
90+
$computers = Get-ADComputer -Filter * -Properties OperatingSystem, DNSHostName | Select-Object -Unique
91+
}
92+
catch {
93+
Write-Host "[!] Error retrieving AD computers: $($_.Exception.Message)"
94+
return
95+
}
96+
97+
Write-Host "[*] Found $($computers.Count) computers in Active Directory."
98+
99+
# -----------------------
100+
# 2. Functions for OS-level discovery
101+
# -----------------------
102+
function Get-OSInfoWMI {
103+
param(
104+
[string]$ComputerName,
105+
[System.Management.Automation.PSCredential]$Cred
106+
)
107+
# In a secure environment, you might set up IPsec or other encryption for WMI
108+
# to protect these queries over the network.
109+
# Also ensure the account has appropriate permissions on the remote system.
110+
$osInfo = Get-WmiObject -Class Win32_OperatingSystem `
111+
-ComputerName $ComputerName `
112+
-Credential $Cred `
113+
-ErrorAction Stop
114+
return $osInfo
115+
}
116+
117+
function Get-OSInfoWinRM {
118+
param(
119+
[string]$ComputerName,
120+
[System.Management.Automation.PSCredential]$Cred
121+
)
122+
# For best security, consider configuring WinRM over HTTPS.
123+
# See: https://docs.microsoft.com/powershell/scripting/learn/remoting/winrmsecurity
124+
$session = $null
125+
try {
126+
$session = New-PSSession -ComputerName $ComputerName -UseSSL -Credential $Cred -ErrorAction Stop
127+
$osInfo = Invoke-Command -Session $session -ScriptBlock {
128+
Get-CimInstance Win32_OperatingSystem
129+
}
130+
}
131+
finally {
132+
if ($session) {
133+
Remove-PSSession -Session $session
134+
}
135+
}
136+
return $osInfo
137+
}
138+
139+
# -----------------------
140+
# 3. Enumerate systems concurrently
141+
# -----------------------
142+
$jobs = foreach ($comp in $computers) {
143+
Start-ThreadJob -ScriptBlock {
144+
param($c, $useWinRM, $cred)
145+
146+
$result = [PSCustomObject]@{
147+
ComputerName = $c.Name
148+
DNSHostName = $c.DNSHostName
149+
OS = $null
150+
ServicePack = $null
151+
Version = $null
152+
LastBootUp = $null
153+
Status = "Failed"
154+
}
155+
156+
try {
157+
if ($useWinRM) {
158+
$osData = Get-OSInfoWinRM -ComputerName $c.DNSHostName -Cred $cred
159+
} else {
160+
$osData = Get-OSInfoWMI -ComputerName $c.DNSHostName -Cred $cred
161+
}
162+
163+
$result.OS = $osData.Caption
164+
$result.ServicePack = $osData.ServicePackMajorVersion
165+
$result.Version = $osData.Version
166+
$result.LastBootUp = $osData.ConvertToDateTime($osData.LastBootUpTime)
167+
$result.Status = "Success"
168+
}
169+
catch {
170+
$result.Status = "Error: " + $_.Exception.Message
171+
}
172+
173+
return $result
174+
} -ArgumentList $comp, $UseWinRM, $credential
175+
}
176+
177+
Write-Host "[*] Waiting for discovery jobs to complete..."
178+
Wait-Job -Job $jobs | Out-Null
179+
180+
# Collect results
181+
$finalResults = Receive-Job -Job $jobs
182+
183+
# Clean up
184+
Remove-Job -Job $jobs | Out-Null
185+
186+
# -----------------------
187+
# 4. Output the final results
188+
# -----------------------
189+
Write-Host "`n===== Discovery Results ====="
190+
$finalResults |
191+
Select-Object ComputerName, DNSHostName, OS, ServicePack, Version, LastBootUp, Status |
192+
Format-Table -AutoSize
193+
194+
# Optional: export to CSV
195+
# $finalResults | Export-Csv -NoTypeInformation -Path .\DiscoveryResults.csv
196+
197+
Write-Host "`n[*] Discovery complete!"

0 commit comments

Comments
 (0)