Skip to content

Commit 50aaf33

Browse files
authored
Add MSADPT_enumerate_shares2.ps1 for share enumeration
This script enumerates network shares on discovered Domain Controllers and scans them for sensitive findings. It requires a CSV file of Domain Controllers and outputs results to a specified directory.
1 parent c49046c commit 50aaf33

1 file changed

Lines changed: 352 additions & 0 deletions

File tree

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
# Requires -Version 7.0
2+
3+
<#
4+
.SYNOPSIS
5+
MSADPT_enumerate_shares2.ps1 - Enumerates network shares on discovered Domain Controllers
6+
and scans them for findings.
7+
8+
.DESCRIPTION
9+
This script is part of the MSADPT toolchain.
10+
It consumes a CSV file of Domain Controllers produced by a previous MSADPT script,
11+
validates Active Directory connectivity, and prepares per-DC output locations.
12+
13+
All operational inputs are provided explicitly via command-line parameters.
14+
The script does not assume the host is domain joined and does not rely on
15+
config files or session-scoped credentials.
16+
17+
.PARAMETER InputDcCsvPath
18+
Path to the CSV file containing discovered Domain Controllers.
19+
Example:
20+
C:\temp\MSADPT_Output\MSADPT_DCs.csv
21+
22+
.PARAMETER OutputBaseDir
23+
Base output directory where per-DC output folders will be created.
24+
Example:
25+
C:\temp\MSADPT_Output\Shares
26+
27+
.PARAMETER Credential
28+
Domain credential to use for all Active Directory operations.
29+
Example:
30+
-Credential (Get-Credential)
31+
32+
.OUTPUTS
33+
Script-specific outputs should be documented here once the loop body is reinserted.
34+
35+
.EXAMPLE
36+
.\MSADPT_enumerate_shares2.ps1 `
37+
-InputDcCsvPath "C:\temp\MSADPT_Output\MSADPT_DCs.csv" `
38+
-OutputBaseDir "C:\temp\MSADPT_Output\Shares" `
39+
-Credential (Get-Credential)
40+
#>
41+
42+
param(
43+
[Parameter(Mandatory)]
44+
[ValidateScript({
45+
if (-not (Test-Path $_)) {
46+
throw "Input file '$_' does not exist."
47+
}
48+
$true
49+
})]
50+
[string]$InputDcCsvPath,
51+
52+
[Parameter(Mandatory)]
53+
[string]$OutputBaseDir,
54+
55+
[Parameter(Mandatory)]
56+
[PSCredential]$Credential
57+
)
58+
59+
Set-StrictMode -Version Latest
60+
61+
# ---------------------------------------------------------------------
62+
# Import helper module from same folder as script
63+
# ---------------------------------------------------------------------
64+
$helpersModulePath = Join-Path $PSScriptRoot 'MSADPT.Helpers.psm1'
65+
66+
if (-not (Test-Path -LiteralPath $helpersModulePath -PathType Leaf)) {
67+
Write-Error "Required helper module not found at '$helpersModulePath'. Aborting."
68+
exit 1
69+
}
70+
71+
Import-Module $helpersModulePath -Force -ErrorAction Stop
72+
73+
Write-MSADPTLog -Message "MSADPT_enumerate_shares2.ps1 starting." -Level 'INFO'
74+
Write-MSADPTLog -Message "Input CSV : $InputDcCsvPath" -Level 'INFO'
75+
Write-MSADPTLog -Message "Output Dir : $OutputBaseDir" -Level 'INFO'
76+
77+
# ---------------------------------------------------------------------
78+
# Ensure output directory exists
79+
# ---------------------------------------------------------------------
80+
if (-not (Test-Path -LiteralPath $OutputBaseDir -PathType Container)) {
81+
New-Item -Path $OutputBaseDir -ItemType Directory -Force | Out-Null
82+
Write-MSADPTLog -Message "Created output directory '$OutputBaseDir'." -Level 'INFO'
83+
}
84+
85+
86+
<#
87+
Write-MSADPTLog -Message "Pre-flight succeeded. DefaultNamingContext: $($rootDSE.defaultNamingContext)" -Level 'INFO'
88+
89+
$ConfigNamingContext = $rootDSE.configurationNamingContext
90+
$DefaultNamingContext = $rootDSE.defaultNamingContext
91+
$SchemaNamingContext = $rootDSE.schemaNamingContext #>
92+
93+
# ---------------------------------------------------------------------
94+
# Import DC list
95+
# ---------------------------------------------------------------------
96+
$DCs = Import-Csv -Path $InputDcCsvPath
97+
if (-not $DCs) {
98+
Write-MSADPTLog -Message "No Domain Controllers found in input CSV. Exiting." -Level 'WARNING'
99+
exit 0
100+
}
101+
102+
Write-MSADPTLog -Message "Imported $(@($DCs).Count) Domain Controller row(s) from '$InputDcCsvPath'." -Level 'INFO'
103+
104+
# ---------------------------------------------------------------------
105+
# Optional module pre-checks for code you may paste into the loop later
106+
# ---------------------------------------------------------------------
107+
$GroupPolicyModuleAvailable = [bool](Get-Module -ListAvailable -Name GroupPolicy)
108+
Write-MSADPTLog -Message "GroupPolicy module available: $GroupPolicyModuleAvailable" -Level 'INFO'
109+
110+
#no wildcard no leading dot
111+
$NetworkShareExcludeExtensions = @(
112+
'xlsx',
113+
'zip',
114+
'jpg',
115+
'jpeg',
116+
'png',
117+
'gif',
118+
'mp4',
119+
'avi',
120+
'mov',
121+
'iso',
122+
'dll',
123+
'exe'
124+
)
125+
126+
127+
$SensitiveFilePatterns = @(
128+
'*.kdbx', # KeePass databases
129+
'*.pfx', # certificate bundles
130+
'*.p12',
131+
'*.pem',
132+
'*.key',
133+
'*.ppk',
134+
'*.ovpn',
135+
'*.rdp',
136+
'*.env',
137+
'*.config',
138+
'*.ini',
139+
'*.xml',
140+
'unattend.xml',
141+
'groups.xml',
142+
'web.config',
143+
'appsettings*.json'
144+
)
145+
146+
$SensitiveKeywords = @(
147+
'password',
148+
'passwd',
149+
'pwd=',
150+
'secret',
151+
'token',
152+
'api key',
153+
'apikey',
154+
'client_secret',
155+
'client secret',
156+
'private key',
157+
'BEGIN PRIVATE KEY',
158+
'BEGIN RSA PRIVATE KEY',
159+
'BEGIN OPENSSH PRIVATE KEY',
160+
'connection string',
161+
'connectionstring',
162+
'ssh key',
163+
'certificate password',
164+
'vpn password',
165+
'service account',
166+
'admin password'
167+
)
168+
169+
170+
# ---------------------------------------------------------------------
171+
# Iterate and process each Domain Controller
172+
# ---------------------------------------------------------------------
173+
foreach ($DC in $DCs) {
174+
$DCName = $DC.Name
175+
$DCIpAddress = $DC.IPv4Address
176+
Write-MSADPTLog -Message "--------------------------------------------------------"
177+
Write-MSADPTLog -Message "Processing Domain Controller for Shares: $DCName ($DCIpAddress)" -Level 'INFO'
178+
Write-MSADPTLog -Message "--------------------------------------------------------"
179+
180+
$CurrentDCOutputDir = Join-Path $OutputBaseDir $DCName
181+
if (-not (Test-Path $CurrentDCOutputDir)) {
182+
New-Item -Path $CurrentDCOutputDir -ItemType Directory -Force | Out-Null
183+
}
184+
185+
$SharesFound = @()
186+
$SensitiveFilesFound = @()
187+
188+
# 1. Enumerate Shares on the DC
189+
if (Prompt-User -PromptText "Proceed to enumerate network shares on ${DCName} ($DCIpAddress) with WSMan/Negotiate?") {
190+
Write-MSADPTLog -Message "Running 'New-CimSession -ComputerName ${DCName}' to enumerate shares."
191+
try {
192+
# Use WMI to list shares on the remote DC
193+
<# $RemoteShares = Get-WmiObject -Class Win32_Share -ComputerName $DCName -Credential $Credential -ErrorAction Stop | Select-Object Name, Path, Description
194+
if ($RemoteShares) {
195+
Write-MSADPTLog -Message "Discovered $($RemoteShares.Count) share(s) on ${DCName}:"
196+
foreach ($Share in $RemoteShares) {
197+
$SharesFound += [PSCustomObject]@{
198+
Timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
199+
DCName = $DCName
200+
ShareName = $Share.Name
201+
SharePath = $Share.Path
202+
Description = $Share.Description
203+
}
204+
Write-MSADPTLog -Message " - \\${DCName}\${Share.Name} (${Share.Path})"
205+
} #>
206+
207+
$RemoteShares = @()
208+
$cimSession = $null
209+
210+
try {
211+
Write-MSADPTLog -Message "Creating CIM session to '$DCName' using WSMan/Negotiate." -Level 'INFO'
212+
$cimSession = New-CimSession -ComputerName $DCName -Credential $Credential -Authentication Negotiate -ErrorAction Stop
213+
214+
try {
215+
if (Get-Command -Name Get-SmbShare -ErrorAction SilentlyContinue) {
216+
Write-MSADPTLog -Message "Trying preferred method: Get-SmbShare -CimSession for '$DCName'." -Level 'INFO'
217+
218+
$RemoteShares = Get-SmbShare -CimSession $cimSession -ErrorAction Stop |
219+
Select-Object Name, Path, Description
220+
}
221+
else {
222+
throw "Get-SmbShare cmdlet is not available on this system."
223+
}
224+
}
225+
catch {
226+
Write-MSADPTLog -Message "Preferred method failed for '$DCName': $($_.Exception.Message). Falling back to Get-CimInstance Win32_Share." -Level 'WARNING'
227+
228+
$RemoteShares = Get-CimInstance -ClassName Win32_Share -CimSession $cimSession -ErrorAction Stop |
229+
Select-Object Name, Path, Description
230+
}
231+
232+
if ($RemoteShares) {
233+
Write-MSADPTLog -Message "Discovered $($RemoteShares.Count) share(s) on '$DCName'." -Level 'INFO'
234+
235+
foreach ($Share in $RemoteShares) {
236+
$SharesFound += [PSCustomObject]@{
237+
Timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
238+
DCName = $DCName
239+
ShareName = $Share.Name
240+
SharePath = $Share.Path
241+
Description = $Share.Description
242+
}
243+
244+
Write-MSADPTLog -Message " - \\$DCName\$($Share.Name) ($($Share.Path))" -Level 'INFO'
245+
}
246+
}
247+
else {
248+
Write-MSADPTLog -Message "No shares returned from '$DCName'." -Level 'INFO'
249+
}
250+
}
251+
catch {
252+
Write-MSADPTLog -Message "Failed to enumerate shares on '$DCName': $($_.Exception.Message)" -Level 'ERROR'
253+
}
254+
finally {
255+
if ($null -ne $cimSession) {
256+
Remove-CimSession $cimSession -ErrorAction SilentlyContinue
257+
Write-MSADPTLog -Message "Closed CIM session to '$DCName'." -Level 'INFO'
258+
}
259+
}
260+
261+
262+
<# $SharesCsvPath = Join-Path $CurrentDCOutputDir "MSADPT_Shares_Discovered_${DCName}_$ScriptStartTime.csv"
263+
$SharesFound | Export-Csv -Path $SharesCsvPath -NoTypeInformation -Force
264+
Write-MSADPTLog -Message "Discovered shares on ${DCName} saved to $SharesCsvPath." #>
265+
266+
267+
if (@($SharesFound).Count -gt 0) {
268+
$SharesCsvPath = Join-Path $CurrentDCOutputDir "MSADPT_Shares_Discovered_${DCName}_$ScriptStartTime.csv"
269+
$SharesFound | Export-Csv -Path $SharesCsvPath -NoTypeInformation -Force
270+
Write-MSADPTLog -Message "Discovered shares on ${DCName} saved to $SharesCsvPath."
271+
}
272+
273+
# 2. Iterate through each share and perform sensitive file scanning
274+
foreach ($Share in $SharesFound) {
275+
$FullSharePath = "\\${DCName}\${Share.Name}"
276+
if (Prompt-User -PromptText "Proceed to scan share '${FullSharePath}' for sensitive data? This may take time.") {
277+
Write-MSADPTLog -Message "Scanning share '${FullSharePath}' for sensitive files and content."
278+
try {
279+
# Get all files, excluding extensions defined in config, but explicitly include sensitive patterns
280+
# -File switch ensures only files, not directories, are returned
281+
<# $FilesToScan = Get-ChildItem -Path $FullSharePath -Recurse -File -ErrorAction SilentlyContinue | Where-Object {
282+
$IsExcluded = $NetworkShareExcludeExtensions -contains $_.Extension.TrimStart('.')
283+
$IsSensitivePattern = $SensitiveFilePatterns | Where-Object { $_ -like $_.FullName } # Check against full file name with wildcard
284+
-not $IsExcluded -or $IsSensitivePattern # Include if not excluded OR if it matches a sensitive pattern
285+
} #>
286+
287+
$FilesToScan = Get-ChildItem -Path $FullSharePath -Recurse -File -ErrorAction SilentlyContinue | Where-Object {
288+
$file = $_
289+
$IsExcluded = @($NetworkShareExcludeExtensions) -contains $file.Extension.TrimStart('.')
290+
$IsSensitivePattern = @(
291+
$SensitiveFilePatterns | Where-Object { $file.FullName -like $_ }
292+
).Count -gt 0
293+
(-not $IsExcluded) -or $IsSensitivePattern
294+
}
295+
296+
297+
foreach ($File in $FilesToScan) {
298+
$FilePath = $File.FullName
299+
$DetectedKeywords = @()
300+
301+
# Check file content for sensitive keywords
302+
if ($SensitiveKeywords.Count -gt 0) {
303+
Write-MSADPTLog -Message " - Checking file content: ${FilePath}"
304+
foreach ($Keyword in $SensitiveKeywords) {
305+
# Use Select-String for efficient keyword search, case-insensitive
306+
if (Get-Content -Path $FilePath -ErrorAction SilentlyContinue | Select-String -Pattern $Keyword -SimpleMatch -CaseSensitive:$false -Quiet) {
307+
$DetectedKeywords += $Keyword
308+
}
309+
}
310+
}
311+
312+
if ($DetectedKeywords.Count -gt 0 -or ($SensitiveFilePatterns | Where-Object { $File.FullName -like $_ }).Count -gt 0) {
313+
$Reason = if ($DetectedKeywords.Count -gt 0) {"Keywords: $($DetectedKeywords -join ', ')"} else {"Pattern match"}
314+
$SensitiveFilesFound += [PSCustomObject]@{
315+
Timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
316+
DCName = $DCName
317+
ShareName = $Share.Name
318+
FilePath = $FilePath
319+
SensitivityReason = $Reason
320+
}
321+
Write-MSADPTLog -Message " [!!!] Sensitive file found: ${FilePath} (Reason: ${Reason})" -Level 'WARNING'
322+
}
323+
}
324+
Write-MSADPTLog -Message "Finished scanning share '${FullSharePath}'. Found $($FilesToScan.Count) files."
325+
} catch {
326+
Write-MSADPTLog -Message "Failed to scan share '${FullSharePath}': $($_.Exception.Message)" -Level 'ERROR'
327+
}
328+
} else {
329+
Write-MSADPTLog -Message "Skipping scan for share '${FullSharePath}'."
330+
}
331+
}
332+
333+
if ($SensitiveFilesFound.Count -gt 0) {
334+
$SensitiveFilesCsvPath = Join-Path $CurrentDCOutputDir "MSADPT_Shares_SensitiveFiles_${DCName}_$ScriptStartTime.csv"
335+
$SensitiveFilesFound | Export-Csv -Path $SensitiveFilesCsvPath -NoTypeInformation -Force
336+
Write-MSADPTLog -Message "Sensitive files found on ${DCName} saved to $SensitiveFilesCsvPath." -Level 'WARNING'
337+
} else {
338+
Write-MSADPTLog -Message "No sensitive files found on any shares for ${DCName}."
339+
}
340+
341+
<# } else {
342+
Write-MSADPTLog -Message "No shares found on ${DCName}." -Level 'INFO'
343+
} #>
344+
} catch {
345+
Write-MSADPTLog -Message "Failed to enumerate shares on ${DCName}: $($_.Exception.Message)" -Level 'ERROR'
346+
}
347+
} else {
348+
Write-MSADPTLog -Message "Skipping network share enumeration for ${DCName}."
349+
}
350+
}
351+
352+
Write-MSADPTLog -Message "MSADPT_enumerate_shares2.ps1 completed." -Level 'INFO'

0 commit comments

Comments
 (0)