· 6 years ago · Jul 04, 2019, 02:22 PM
1filter Get-NetDomain {
2 param(
3 [Parameter(ValueFromPipeline=$True)]
4 [String]
5 $Domain,
6
7 [Management.Automation.PSCredential]
8 $Credential
9 )
10
11 if($Credential) {
12
13 Write-Verbose "Using alternate credentials for Get-NetDomain"
14
15 if(!$Domain) {
16 # if no domain is supplied, extract the logon domain from the PSCredential passed
17 $Domain = $Credential.GetNetworkCredential().Domain
18 Write-Verbose "Extracted domain '$Domain' from -Credential"
19 }
20
21 $DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain, $Credential.UserName, $Credential.GetNetworkCredential().Password)
22
23 try {
24 [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
25 }
26 catch {
27 Write-Verbose "The specified domain does '$Domain' not exist, could not be contacted, there isn't an existing trust, or the specified credentials are invalid."
28 $Null
29 }
30 }
31 elseif($Domain) {
32 $DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain)
33 try {
34 [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
35 }
36 catch {
37 Write-Verbose "The specified domain '$Domain' does not exist, could not be contacted, or there isn't an existing trust."
38 $Null
39 }
40 }
41 else {
42 [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
43 }
44}
45filter Get-NameField {
46 [CmdletBinding()]
47 param(
48 [Parameter(ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)]
49 [Object]
50 $Object,
51
52 [Parameter(ValueFromPipelineByPropertyName = $True)]
53 [String]
54 $DnsHostName,
55
56 [Parameter(ValueFromPipelineByPropertyName = $True)]
57 [String]
58 $Name
59 )
60
61 if($PSBoundParameters['DnsHostName']) {
62 $DnsHostName
63 }
64 elseif($PSBoundParameters['Name']) {
65 $Name
66 }
67 elseif($Object) {
68 if ( [bool]($Object.PSobject.Properties.name -match "dnshostname") ) {
69 # objects from Get-NetComputer
70 $Object.dnshostname
71 }
72 elseif ( [bool]($Object.PSobject.Properties.name -match "name") ) {
73 # objects from Get-NetDomainController
74 $Object.name
75 }
76 else {
77 # strings and catch alls
78 $Object
79 }
80 }
81 else {
82 return $Null
83 }
84}
85filter Get-NetShare {
86 [CmdletBinding()]
87 param(
88 [Parameter(ValueFromPipeline=$True)]
89 [Alias('HostName')]
90 [Object[]]
91 [ValidateNotNullOrEmpty()]
92 $ComputerName = 'localhost'
93 )
94
95 # extract the computer name from whatever object was passed on the pipeline
96 $Computer = $ComputerName | Get-NameField
97
98 # arguments for NetShareEnum
99 $QueryLevel = 1
100 $PtrInfo = [IntPtr]::Zero
101 $EntriesRead = 0
102 $TotalRead = 0
103 $ResumeHandle = 0
104
105 # get the share information
106 $Result = $Netapi32::NetShareEnum($Computer, $QueryLevel, [ref]$PtrInfo, -1, [ref]$EntriesRead, [ref]$TotalRead, [ref]$ResumeHandle)
107
108 # Locate the offset of the initial intPtr
109 $Offset = $PtrInfo.ToInt64()
110
111 # 0 = success
112 if (($Result -eq 0) -and ($Offset -gt 0)) {
113
114 # Work out how much to increment the pointer by finding out the size of the structure
115 $Increment = $SHARE_INFO_1::GetSize()
116
117 # parse all the result structures
118 for ($i = 0; ($i -lt $EntriesRead); $i++) {
119 # create a new int ptr at the given offset and cast the pointer as our result structure
120 $NewIntPtr = New-Object System.Intptr -ArgumentList $Offset
121 $Info = $NewIntPtr -as $SHARE_INFO_1
122
123 # return all the sections of the structure
124 $Shares = $Info | Select-Object *
125 $Shares | Add-Member Noteproperty 'ComputerName' $Computer
126 $Offset = $NewIntPtr.ToInt64()
127 $Offset += $Increment
128 $Shares
129 }
130
131 # free up the result buffer
132 $Null = $Netapi32::NetApiBufferFree($PtrInfo)
133 }
134 else {
135 Write-Verbose "Error: $(([ComponentModel.Win32Exception] $Result).Message)"
136 }
137}
138filter Get-DomainSearcher {
139 param(
140 [Parameter(ValueFromPipeline=$True)]
141 [String]
142 $Domain,
143
144 [String]
145 $DomainController,
146
147 [String]
148 $ADSpath,
149
150 [String]
151 $ADSprefix,
152
153 [ValidateRange(1,10000)]
154 [Int]
155 $PageSize = 200,
156
157 [Management.Automation.PSCredential]
158 $Credential
159 )
160
161 if(-not $Credential) {
162 if(-not $Domain) {
163 $Domain = (Get-NetDomain).name
164 }
165 elseif(-not $DomainController) {
166 try {
167 # if there's no -DomainController specified, try to pull the primary DC to reflect queries through
168 $DomainController = ((Get-NetDomain).PdcRoleOwner).Name
169 }
170 catch {
171 throw "Get-DomainSearcher: Error in retrieving PDC for current domain"
172 }
173 }
174 }
175 elseif (-not $DomainController) {
176 # if a DC isn't specified
177 try {
178 $DomainController = ((Get-NetDomain -Credential $Credential).PdcRoleOwner).Name
179 }
180 catch {
181 throw "Get-DomainSearcher: Error in retrieving PDC for current domain"
182 }
183
184 if(!$DomainController) {
185 throw "Get-DomainSearcher: Error in retrieving PDC for current domain"
186 }
187 }
188
189 $SearchString = "LDAP://"
190
191 if($DomainController) {
192 $SearchString += $DomainController
193 if($Domain){
194 $SearchString += '/'
195 }
196 }
197
198 if($ADSprefix) {
199 $SearchString += $ADSprefix + ','
200 }
201
202 if($ADSpath) {
203 if($ADSpath -Match '^GC://') {
204 # if we're searching the global catalog
205 $DN = $AdsPath.ToUpper().Trim('/')
206 $SearchString = ''
207 }
208 else {
209 if($ADSpath -match '^LDAP://') {
210 if($ADSpath -match "LDAP://.+/.+") {
211 $SearchString = ''
212 }
213 else {
214 $ADSpath = $ADSpath.Substring(7)
215 }
216 }
217 $DN = $ADSpath
218 }
219 }
220 else {
221 if($Domain -and ($Domain.Trim() -ne "")) {
222 $DN = "DC=$($Domain.Replace('.', ',DC='))"
223 }
224 }
225
226 $SearchString += $DN
227 Write-Verbose "Get-DomainSearcher search string: $SearchString"
228
229 if($Credential) {
230 Write-Verbose "Using alternate credentials for LDAP connection"
231 $DomainObject = New-Object DirectoryServices.DirectoryEntry($SearchString, $Credential.UserName, $Credential.GetNetworkCredential().Password)
232 $Searcher = New-Object System.DirectoryServices.DirectorySearcher($DomainObject)
233 }
234 else {
235 $Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$SearchString)
236 }
237
238 $Searcher.PageSize = $PageSize
239 $Searcher.CacheResults = $False
240 $Searcher
241}
242filter Get-NetForest {
243 param(
244 [Parameter(ValueFromPipeline=$True)]
245 [String]
246 $Forest,
247
248 [Management.Automation.PSCredential]
249 $Credential
250 )
251
252 if($Credential) {
253
254 Write-Verbose "Using alternate credentials for Get-NetForest"
255
256 if(!$Forest) {
257 # if no domain is supplied, extract the logon domain from the PSCredential passed
258 $Forest = $Credential.GetNetworkCredential().Domain
259 Write-Verbose "Extracted domain '$Forest' from -Credential"
260 }
261
262 $ForestContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Forest', $Forest, $Credential.UserName, $Credential.GetNetworkCredential().Password)
263
264 try {
265 $ForestObject = [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($ForestContext)
266 }
267 catch {
268 Write-Verbose "The specified forest '$Forest' does not exist, could not be contacted, there isn't an existing trust, or the specified credentials are invalid."
269 $Null
270 }
271 }
272 elseif($Forest) {
273 $ForestContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Forest', $Forest)
274 try {
275 $ForestObject = [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($ForestContext)
276 }
277 catch {
278 Write-Verbose "The specified forest '$Forest' does not exist, could not be contacted, or there isn't an existing trust."
279 return $Null
280 }
281 }
282 else {
283 # otherwise use the current forest
284 $ForestObject = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
285 }
286
287 if($ForestObject) {
288 # get the SID of the forest root
289 $ForestSid = (New-Object System.Security.Principal.NTAccount($ForestObject.RootDomain,"krbtgt")).Translate([System.Security.Principal.SecurityIdentifier]).Value
290 $Parts = $ForestSid -Split "-"
291 $ForestSid = $Parts[0..$($Parts.length-2)] -join "-"
292 $ForestObject | Add-Member NoteProperty 'RootDomainSid' $ForestSid
293 $ForestObject
294 }
295}
296filter Get-NetForestDomain {
297 param(
298 [Parameter(ValueFromPipeline=$True)]
299 [String]
300 $Forest,
301
302 [Management.Automation.PSCredential]
303 $Credential
304 )
305
306 $ForestObject = Get-NetForest -Forest $Forest -Credential $Credential
307
308 if($ForestObject) {
309 $ForestObject.Domains
310 }
311}
312filter Get-GptTmpl {
313 [CmdletBinding()]
314 Param (
315 [Parameter(Mandatory=$True, ValueFromPipeline=$True)]
316 [String]
317 $GptTmplPath,
318
319 [Switch]
320 $UsePSDrive
321 )
322
323 if($UsePSDrive) {
324 # if we're PSDrives, create a temporary mount point
325 $Parts = $GptTmplPath.split('\')
326 $FolderPath = $Parts[0..($Parts.length-2)] -join '\'
327 $FilePath = $Parts[-1]
328 $RandDrive = ("abcdefghijklmnopqrstuvwxyz".ToCharArray() | Get-Random -Count 7) -join ''
329
330 Write-Verbose "Mounting path $GptTmplPath using a temp PSDrive at $RandDrive"
331
332 try {
333 $Null = New-PSDrive -Name $RandDrive -PSProvider FileSystem -Root $FolderPath -ErrorAction Stop
334 }
335 catch {
336 Write-Verbose "Error mounting path $GptTmplPath : $_"
337 return $Null
338 }
339
340 # so we can cd/dir the new drive
341 $TargetGptTmplPath = $RandDrive + ":\" + $FilePath
342 }
343 else {
344 $TargetGptTmplPath = $GptTmplPath
345 }
346
347 Write-Verbose "GptTmplPath: $GptTmplPath"
348
349 try {
350 Write-Verbose "Parsing $TargetGptTmplPath"
351 $TargetGptTmplPath | Get-IniContent -ErrorAction SilentlyContinue
352 }
353 catch {
354 Write-Verbose "Error parsing $TargetGptTmplPath : $_"
355 }
356
357 if($UsePSDrive -and $RandDrive) {
358 Write-Verbose "Removing temp PSDrive $RandDrive"
359 Get-PSDrive -Name $RandDrive -ErrorAction SilentlyContinue | Remove-PSDrive -Force
360 }
361}
362
363function Get-NetUser {
364 param(
365 [Parameter(Position=0, ValueFromPipeline=$True)]
366 [String]
367 $UserName,
368
369 [String]
370 $Domain,
371
372 [String]
373 $DomainController,
374
375 [String]
376 $ADSpath,
377
378 [String]
379 $Filter,
380
381 [Switch]
382 $SPN,
383
384 [Switch]
385 $AdminCount,
386
387 [Switch]
388 $Unconstrained,
389
390 [Switch]
391 $AllowDelegation,
392
393 [ValidateRange(1,10000)]
394 [Int]
395 $PageSize = 200,
396
397 [Management.Automation.PSCredential]
398 $Credential
399 )
400
401 begin {
402 # so this isn't repeated if users are passed on the pipeline
403 $UserSearcher = Get-DomainSearcher -Domain $Domain -ADSpath $ADSpath -DomainController $DomainController -PageSize $PageSize -Credential $Credential
404 }
405
406 process {
407 if($UserSearcher) {
408
409 # if we're checking for unconstrained delegation
410 if($Unconstrained) {
411 Write-Verbose "Checking for unconstrained delegation"
412 $Filter += "(userAccountControl:1.2.840.113556.1.4.803:=524288)"
413 }
414 if($AllowDelegation) {
415 Write-Verbose "Checking for users who can be delegated"
416 # negation of "Accounts that are sensitive and not trusted for delegation"
417 $Filter += "(!(userAccountControl:1.2.840.113556.1.4.803:=1048574))"
418 }
419 if($AdminCount) {
420 Write-Verbose "Checking for adminCount=1"
421 $Filter += "(admincount=1)"
422 }
423
424 # check if we're using a username filter or not
425 if($UserName) {
426 # samAccountType=805306368 indicates user objects
427 $UserSearcher.filter="(&(samAccountType=805306368)(samAccountName=$UserName)$Filter)"
428 }
429 elseif($SPN) {
430 $UserSearcher.filter="(&(samAccountType=805306368)(servicePrincipalName=*)$Filter)"
431 }
432 else {
433 # filter is something like "(samAccountName=*blah*)" if specified
434 $UserSearcher.filter="(&(samAccountType=805306368)$Filter)"
435 }
436
437 $Results = $UserSearcher.FindAll()
438 $Results | Where-Object {$_} | ForEach-Object {
439 # convert/process the LDAP fields for each result
440 $User = Convert-LDAPProperty -Properties $_.Properties
441 $User.PSObject.TypeNames.Add('PowerView.User')
442 $User
443 }
444 $Results.dispose()
445 $UserSearcher.dispose()
446 }
447 }
448}
449
450function Invoke-ShareFinder {
451 [CmdletBinding()]
452 param(
453 [Parameter(Position=0,ValueFromPipeline=$True)]
454 [Alias('Hosts')]
455 [String[]]
456 $ComputerName,
457
458 [ValidateScript({Test-Path -Path $_ })]
459 [Alias('HostList')]
460 [String]
461 $ComputerFile,
462
463 [String]
464 $ComputerFilter,
465
466 [String]
467 $ComputerADSpath,
468
469 [Switch]
470 $ExcludeStandard,
471
472 [Switch]
473 $ExcludePrint,
474
475 [Switch]
476 $ExcludeIPC,
477
478 [Switch]
479 $NoPing,
480
481 [Switch]
482 $CheckShareAccess,
483
484 [Switch]
485 $CheckAdmin,
486
487 [UInt32]
488 $Delay = 0,
489
490 [Double]
491 $Jitter = .3,
492
493 [String]
494 $Domain,
495
496 [String]
497 $DomainController,
498
499 [Switch]
500 $SearchForest,
501
502 [ValidateRange(1,100)]
503 [Int]
504 $Threads
505 )
506
507 begin {
508 if ($PSBoundParameters['Debug']) {
509 $DebugPreference = 'Continue'
510 }
511
512 # random object for delay
513 $RandNo = New-Object System.Random
514
515 Write-Verbose "[*] Running Invoke-ShareFinder with delay of $Delay"
516
517 # figure out the shares we want to ignore
518 [String[]] $ExcludedShares = @('')
519
520 if ($ExcludePrint) {
521 $ExcludedShares = $ExcludedShares + "PRINT$"
522 }
523 if ($ExcludeIPC) {
524 $ExcludedShares = $ExcludedShares + "IPC$"
525 }
526 if ($ExcludeStandard) {
527 $ExcludedShares = @('', "ADMIN$", "IPC$", "C$", "PRINT$")
528 }
529
530 # if we're using a host file list, read the targets in and add them to the target list
531 if($ComputerFile) {
532 $ComputerName = Get-Content -Path $ComputerFile
533 }
534
535 if(!$ComputerName) {
536 [array]$ComputerName = @()
537
538 if($Domain) {
539 $TargetDomains = @($Domain)
540 }
541 elseif($SearchForest) {
542 # get ALL the domains in the forest to search
543 $TargetDomains = Get-NetForestDomain | ForEach-Object { $_.Name }
544 }
545 else {
546 # use the local domain
547 $TargetDomains = @( (Get-NetDomain).name )
548 }
549
550 ForEach ($Domain in $TargetDomains) {
551 Write-Verbose "[*] Querying domain $Domain for hosts"
552 $ComputerName += Get-NetComputer -Domain $Domain -DomainController $DomainController -Filter $ComputerFilter -ADSpath $ComputerADSpath
553 }
554
555 # remove any null target hosts, uniquify the list and shuffle it
556 $ComputerName = $ComputerName | Where-Object { $_ } | Sort-Object -Unique | Sort-Object { Get-Random }
557 if($($ComputerName.count) -eq 0) {
558 throw "No hosts found!"
559 }
560 }
561
562 # script block that enumerates a server
563 $HostEnumBlock = {
564 param($ComputerName, $Ping, $CheckShareAccess, $ExcludedShares, $CheckAdmin)
565
566 # optionally check if the server is up first
567 $Up = $True
568 if($Ping) {
569 $Up = Test-Connection -Count 1 -Quiet -ComputerName $ComputerName
570 }
571 if($Up) {
572 # get the shares for this host and check what we find
573 $Shares = Get-NetShare -ComputerName $ComputerName
574 ForEach ($Share in $Shares) {
575 Write-Verbose "[*] Server share: $Share"
576 $NetName = $Share.shi1_netname
577 $Remark = $Share.shi1_remark
578 $Path = '\\'+$ComputerName+'\'+$NetName
579
580 # make sure we get a real share name back
581 if (($NetName) -and ($NetName.trim() -ne '')) {
582 # if we're just checking for access to ADMIN$
583 if($CheckAdmin) {
584 if($NetName.ToUpper() -eq "ADMIN$") {
585 try {
586 $Null = [IO.Directory]::GetFiles($Path)
587 "\\$ComputerName\$NetName `t- $Remark"
588 }
589 catch {
590 Write-Verbose "Error accessing path $Path : $_"
591 }
592 }
593 }
594 # skip this share if it's in the exclude list
595 elseif ($ExcludedShares -NotContains $NetName.ToUpper()) {
596 # see if we want to check access to this share
597 if($CheckShareAccess) {
598 # check if the user has access to this path
599 try {
600 $Null = [IO.Directory]::GetFiles($Path)
601 "\\$ComputerName\$NetName `t- $Remark"
602 }
603 catch {
604 Write-Verbose "Error accessing path $Path : $_"
605 }
606 }
607 else {
608 "\\$ComputerName\$NetName `t- $Remark"
609 }
610 }
611 }
612 }
613 }
614 }
615
616 }
617
618 process {
619
620 if($Threads) {
621 Write-Verbose "Using threading with threads = $Threads"
622
623 # if we're using threading, kick off the script block with Invoke-ThreadedFunction
624 $ScriptParams = @{
625 'Ping' = $(-not $NoPing)
626 'CheckShareAccess' = $CheckShareAccess
627 'ExcludedShares' = $ExcludedShares
628 'CheckAdmin' = $CheckAdmin
629 }
630
631 # kick off the threaded script block + arguments
632 Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
633 }
634
635 else {
636 if(-not $NoPing -and ($ComputerName.count -ne 1)) {
637 # ping all hosts in parallel
638 $Ping = {param($ComputerName) if(Test-Connection -ComputerName $ComputerName -Count 1 -Quiet -ErrorAction Stop){$ComputerName}}
639 $ComputerName = Invoke-ThreadedFunction -NoImports -ComputerName $ComputerName -ScriptBlock $Ping -Threads 100
640 }
641
642 Write-Verbose "[*] Total number of active hosts: $($ComputerName.count)"
643 $Counter = 0
644
645 ForEach ($Computer in $ComputerName) {
646
647 $Counter = $Counter + 1
648
649 # sleep for our semi-randomized interval
650 Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay)
651
652 Write-Verbose "[*] Enumerating server $Computer ($Counter of $($ComputerName.count))"
653 Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $Computer, $False, $CheckShareAccess, $ExcludedShares, $CheckAdmin
654 }
655 }
656
657 }
658}
659
660function Invoke-FileFinder {
661 [CmdletBinding()]
662 param(
663 [Parameter(Position=0,ValueFromPipeline=$True)]
664 [Alias('Hosts')]
665 [String[]]
666 $ComputerName,
667
668 [ValidateScript({Test-Path -Path $_ })]
669 [Alias('HostList')]
670 [String]
671 $ComputerFile,
672
673 [String]
674 $ComputerFilter,
675
676 [String]
677 $ComputerADSpath,
678
679 [ValidateScript({Test-Path -Path $_ })]
680 [String]
681 $ShareList,
682
683 [Switch]
684 $OfficeDocs,
685
686 [Switch]
687 $FreshEXEs,
688
689 [Alias('Terms')]
690 [String[]]
691 $SearchTerms,
692
693 [ValidateScript({Test-Path -Path $_ })]
694 [String]
695 $TermList,
696
697 [String]
698 $LastAccessTime,
699
700 [String]
701 $LastWriteTime,
702
703 [String]
704 $CreationTime,
705
706 [Switch]
707 $IncludeC,
708
709 [Switch]
710 $IncludeAdmin,
711
712 [Switch]
713 $ExcludeFolders,
714
715 [Switch]
716 $ExcludeHidden,
717
718 [Switch]
719 $CheckWriteAccess,
720
721 [String]
722 $OutFile,
723
724 [Switch]
725 $NoClobber,
726
727 [Switch]
728 $NoPing,
729
730 [UInt32]
731 $Delay = 0,
732
733 [Double]
734 $Jitter = .3,
735
736 [String]
737 $Domain,
738
739 [String]
740 $DomainController,
741
742 [Switch]
743 $SearchForest,
744
745 [Switch]
746 $SearchSYSVOL,
747
748 [ValidateRange(1,100)]
749 [Int]
750 $Threads,
751
752 [Switch]
753 $UsePSDrive
754 )
755
756 begin {
757 if ($PSBoundParameters['Debug']) {
758 $DebugPreference = 'Continue'
759 }
760
761 # random object for delay
762 $RandNo = New-Object System.Random
763
764 Write-Verbose "[*] Running Invoke-FileFinder with delay of $Delay"
765
766 $Shares = @()
767
768 # figure out the shares we want to ignore
769 [String[]] $ExcludedShares = @("C$", "ADMIN$")
770
771 # see if we're specifically including any of the normally excluded sets
772 if ($IncludeC) {
773 if ($IncludeAdmin) {
774 $ExcludedShares = @()
775 }
776 else {
777 $ExcludedShares = @("ADMIN$")
778 }
779 }
780
781 if ($IncludeAdmin) {
782 if ($IncludeC) {
783 $ExcludedShares = @()
784 }
785 else {
786 $ExcludedShares = @("C$")
787 }
788 }
789
790 # delete any existing output file if it already exists
791 if(!$NoClobber) {
792 if ($OutFile -and (Test-Path -Path $OutFile)) { Remove-Item -Path $OutFile }
793 }
794
795 # if there's a set of terms specified to search for
796 if ($TermList) {
797 ForEach ($Term in Get-Content -Path $TermList) {
798 if (($Term -ne $Null) -and ($Term.trim() -ne '')) {
799 $SearchTerms += $Term
800 }
801 }
802 }
803
804 # if we're hard-passed a set of shares
805 if($ShareList) {
806 ForEach ($Item in Get-Content -Path $ShareList) {
807 if (($Item -ne $Null) -and ($Item.trim() -ne '')) {
808 # exclude any "[tab]- commants", i.e. the output from Invoke-ShareFinder
809 $Share = $Item.Split("`t")[0]
810 $Shares += $Share
811 }
812 }
813 }
814 else {
815 # if we're using a host file list, read the targets in and add them to the target list
816 if($ComputerFile) {
817 $ComputerName = Get-Content -Path $ComputerFile
818 }
819
820 if(!$ComputerName) {
821
822 if($Domain) {
823 $TargetDomains = @($Domain)
824 }
825 elseif($SearchForest) {
826 # get ALL the domains in the forest to search
827 $TargetDomains = Get-NetForestDomain | ForEach-Object { $_.Name }
828 }
829 else {
830 # use the local domain
831 $TargetDomains = @( (Get-NetDomain).name )
832 }
833
834 if($SearchSYSVOL) {
835 ForEach ($Domain in $TargetDomains) {
836 $DCSearchPath = "\\$Domain\SYSVOL\"
837 Write-Verbose "[*] Adding share search path $DCSearchPath"
838 $Shares += $DCSearchPath
839 }
840 if(!$SearchTerms) {
841 # search for interesting scripts on SYSVOL
842 $SearchTerms = @('.vbs', '.bat', '.ps1')
843 }
844 }
845 else {
846 [array]$ComputerName = @()
847
848 ForEach ($Domain in $TargetDomains) {
849 Write-Verbose "[*] Querying domain $Domain for hosts"
850 $ComputerName += Get-NetComputer -Filter $ComputerFilter -ADSpath $ComputerADSpath -Domain $Domain -DomainController $DomainController
851 }
852
853 # remove any null target hosts, uniquify the list and shuffle it
854 $ComputerName = $ComputerName | Where-Object { $_ } | Sort-Object -Unique | Sort-Object { Get-Random }
855 if($($ComputerName.Count) -eq 0) {
856 throw "No hosts found!"
857 }
858 }
859 }
860 }
861
862 # script block that enumerates shares and files on a server
863 $HostEnumBlock = {
864 param($ComputerName, $Ping, $ExcludedShares, $SearchTerms, $ExcludeFolders, $OfficeDocs, $ExcludeHidden, $FreshEXEs, $CheckWriteAccess, $OutFile, $UsePSDrive)
865
866 Write-Verbose "ComputerName: $ComputerName"
867 Write-Verbose "ExcludedShares: $ExcludedShares"
868 $SearchShares = @()
869
870 if($ComputerName.StartsWith("\\")) {
871 # if a share is passed as the server
872 $SearchShares += $ComputerName
873 }
874 else {
875 # if we're enumerating the shares on the target server first
876 $Up = $True
877 if($Ping) {
878 $Up = Test-Connection -Count 1 -Quiet -ComputerName $ComputerName
879 }
880 if($Up) {
881 # get the shares for this host and display what we find
882 $Shares = Get-NetShare -ComputerName $ComputerName
883 ForEach ($Share in $Shares) {
884
885 $NetName = $Share.shi1_netname
886 $Path = '\\'+$ComputerName+'\'+$NetName
887
888 # make sure we get a real share name back
889 if (($NetName) -and ($NetName.trim() -ne '')) {
890
891 # skip this share if it's in the exclude list
892 if ($ExcludedShares -NotContains $NetName.ToUpper()) {
893 # check if the user has access to this path
894 try {
895 $Null = [IO.Directory]::GetFiles($Path)
896 $SearchShares += $Path
897 }
898 catch {
899 Write-Verbose "[!] No access to $Path"
900 }
901 }
902 }
903 }
904 }
905 }
906
907 ForEach($Share in $SearchShares) {
908 $SearchArgs = @{
909 'Path' = $Share
910 'SearchTerms' = $SearchTerms
911 'OfficeDocs' = $OfficeDocs
912 'FreshEXEs' = $FreshEXEs
913 'LastAccessTime' = $LastAccessTime
914 'LastWriteTime' = $LastWriteTime
915 'CreationTime' = $CreationTime
916 'ExcludeFolders' = $ExcludeFolders
917 'ExcludeHidden' = $ExcludeHidden
918 'CheckWriteAccess' = $CheckWriteAccess
919 'OutFile' = $OutFile
920 'UsePSDrive' = $UsePSDrive
921 }
922
923 Find-InterestingFile @SearchArgs
924 }
925 }
926 }
927
928 process {
929
930 if($Threads) {
931 Write-Verbose "Using threading with threads = $Threads"
932
933 # if we're using threading, kick off the script block with Invoke-ThreadedFunction
934 $ScriptParams = @{
935 'Ping' = $(-not $NoPing)
936 'ExcludedShares' = $ExcludedShares
937 'SearchTerms' = $SearchTerms
938 'ExcludeFolders' = $ExcludeFolders
939 'OfficeDocs' = $OfficeDocs
940 'ExcludeHidden' = $ExcludeHidden
941 'FreshEXEs' = $FreshEXEs
942 'CheckWriteAccess' = $CheckWriteAccess
943 'OutFile' = $OutFile
944 'UsePSDrive' = $UsePSDrive
945 }
946
947 # kick off the threaded script block + arguments
948 if($Shares) {
949 # pass the shares as the hosts so the threaded function code doesn't have to be hacked up
950 Invoke-ThreadedFunction -ComputerName $Shares -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
951 }
952 else {
953 Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
954 }
955 }
956
957 else {
958 if($Shares){
959 $ComputerName = $Shares
960 }
961 elseif(-not $NoPing -and ($ComputerName.count -gt 1)) {
962 # ping all hosts in parallel
963 $Ping = {param($ComputerName) if(Test-Connection -ComputerName $ComputerName -Count 1 -Quiet -ErrorAction Stop){$ComputerName}}
964 $ComputerName = Invoke-ThreadedFunction -NoImports -ComputerName $ComputerName -ScriptBlock $Ping -Threads 100
965 }
966
967 Write-Verbose "[*] Total number of active hosts: $($ComputerName.count)"
968 $Counter = 0
969
970 $ComputerName | Where-Object {$_} | ForEach-Object {
971 Write-Verbose "Computer: $_"
972 $Counter = $Counter + 1
973
974 # sleep for our semi-randomized interval
975 Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay)
976
977 Write-Verbose "[*] Enumerating server $_ ($Counter of $($ComputerName.count))"
978
979 Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $_, $False, $ExcludedShares, $SearchTerms, $ExcludeFolders, $OfficeDocs, $ExcludeHidden, $FreshEXEs, $CheckWriteAccess, $OutFile, $UsePSDrive
980 }
981 }
982 }
983}
984
985function Get-DomainPolicy {
986 [CmdletBinding()]
987 Param (
988 [String]
989 [ValidateSet("Domain","DC")]
990 $Source ="Domain",
991
992 [String]
993 $Domain,
994
995 [String]
996 $DomainController,
997
998 [Switch]
999 $ResolveSids,
1000
1001 [Switch]
1002 $UsePSDrive
1003 )
1004
1005 if($Source -eq "Domain") {
1006 # query the given domain for the default domain policy object
1007 $GPO = Get-NetGPO -Domain $Domain -DomainController $DomainController -GPOname "{31B2F340-016D-11D2-945F-00C04FB984F9}"
1008
1009 if($GPO) {
1010 # grab the GptTmpl.inf file and parse it
1011 $GptTmplPath = $GPO.gpcfilesyspath + "\MACHINE\Microsoft\Windows NT\SecEdit\GptTmpl.inf"
1012
1013 $ParseArgs = @{
1014 'GptTmplPath' = $GptTmplPath
1015 'UsePSDrive' = $UsePSDrive
1016 }
1017
1018 # parse the GptTmpl.inf
1019 Get-GptTmpl @ParseArgs
1020 }
1021
1022 }
1023 elseif($Source -eq "DC") {
1024 # query the given domain/dc for the default domain controller policy object
1025 $GPO = Get-NetGPO -Domain $Domain -DomainController $DomainController -GPOname "{6AC1786C-016F-11D2-945F-00C04FB984F9}"
1026
1027 if($GPO) {
1028 # grab the GptTmpl.inf file and parse it
1029 $GptTmplPath = $GPO.gpcfilesyspath + "\MACHINE\Microsoft\Windows NT\SecEdit\GptTmpl.inf"
1030
1031 $ParseArgs = @{
1032 'GptTmplPath' = $GptTmplPath
1033 'UsePSDrive' = $UsePSDrive
1034 }
1035
1036 # parse the GptTmpl.inf
1037 Get-GptTmpl @ParseArgs | ForEach-Object {
1038 if($ResolveSids) {
1039 # if we're resolving sids in PrivilegeRights to names
1040 $Policy = New-Object PSObject
1041 $_.psobject.properties | ForEach-Object {
1042 if( $_.Name -eq 'PrivilegeRights') {
1043
1044 $PrivilegeRights = New-Object PSObject
1045 # for every nested SID member of PrivilegeRights, try to unpack everything and resolve the SIDs as appropriate
1046 $_.Value.psobject.properties | ForEach-Object {
1047
1048 $Sids = $_.Value | ForEach-Object {
1049 try {
1050 if($_ -isnot [System.Array]) {
1051 Convert-SidToName $_
1052 }
1053 else {
1054 $_ | ForEach-Object { Convert-SidToName $_ }
1055 }
1056 }
1057 catch {
1058 Write-Verbose "Error resolving SID : $_"
1059 }
1060 }
1061
1062 $PrivilegeRights | Add-Member Noteproperty $_.Name $Sids
1063 }
1064
1065 $Policy | Add-Member Noteproperty 'PrivilegeRights' $PrivilegeRights
1066 }
1067 else {
1068 $Policy | Add-Member Noteproperty $_.Name $_.Value
1069 }
1070 }
1071 $Policy
1072 }
1073 else { $_ }
1074 }
1075 }
1076 }
1077}
1078
1079function Get-ExploitableSystem {
1080 [CmdletBinding()]
1081 Param(
1082 [Parameter(ValueFromPipeline=$True)]
1083 [Alias('HostName')]
1084 [String]
1085 $ComputerName = '*',
1086
1087 [String]
1088 $SPN,
1089
1090 [String]
1091 $OperatingSystem = '*',
1092
1093 [String]
1094 $ServicePack = '*',
1095
1096 [String]
1097 $Filter,
1098
1099 [Switch]
1100 $Ping,
1101
1102 [String]
1103 $Domain,
1104
1105 [String]
1106 $DomainController,
1107
1108 [String]
1109 $ADSpath,
1110
1111 [Switch]
1112 $Unconstrained,
1113
1114 [ValidateRange(1,10000)]
1115 [Int]
1116 $PageSize = 200,
1117
1118 [Management.Automation.PSCredential]
1119 $Credential
1120 )
1121
1122 Write-Verbose "[*] Grabbing computer accounts from Active Directory..."
1123
1124 # Create data table for hostnames, os, and service packs from LDAP
1125 $TableAdsComputers = New-Object System.Data.DataTable
1126 $Null = $TableAdsComputers.Columns.Add('Hostname')
1127 $Null = $TableAdsComputers.Columns.Add('OperatingSystem')
1128 $Null = $TableAdsComputers.Columns.Add('ServicePack')
1129 $Null = $TableAdsComputers.Columns.Add('LastLogon')
1130
1131 Get-NetComputer -FullData @PSBoundParameters | ForEach-Object {
1132
1133 $CurrentHost = $_.dnshostname
1134 $CurrentOs = $_.operatingsystem
1135 $CurrentSp = $_.operatingsystemservicepack
1136 $CurrentLast = $_.lastlogon
1137 $CurrentUac = $_.useraccountcontrol
1138
1139 $CurrentUacBin = [convert]::ToString($_.useraccountcontrol,2)
1140
1141 # Check the 2nd to last value to determine if its disabled
1142 $DisableOffset = $CurrentUacBin.Length - 2
1143 $CurrentDisabled = $CurrentUacBin.Substring($DisableOffset,1)
1144
1145 # Add computer to list if it's enabled
1146 if ($CurrentDisabled -eq 0) {
1147 # Add domain computer to data table
1148 $Null = $TableAdsComputers.Rows.Add($CurrentHost,$CurrentOS,$CurrentSP,$CurrentLast)
1149 }
1150 }
1151
1152 # Status user
1153 Write-Verbose "[*] Loading exploit list for critical missing patches..."
1154
1155 # ----------------------------------------------------------------
1156 # Setup data table for list of msf exploits
1157 # ----------------------------------------------------------------
1158
1159 # Create data table for list of patches levels with a MSF exploit
1160 $TableExploits = New-Object System.Data.DataTable
1161 $Null = $TableExploits.Columns.Add('OperatingSystem')
1162 $Null = $TableExploits.Columns.Add('ServicePack')
1163 $Null = $TableExploits.Columns.Add('MsfModule')
1164 $Null = $TableExploits.Columns.Add('CVE')
1165
1166 # Add exploits to data table
1167 $Null = $TableExploits.Rows.Add("Windows 7","","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1168 $Null = $TableExploits.Rows.Add("Windows Server 2000","Server Pack 1","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1169 $Null = $TableExploits.Rows.Add("Windows Server 2000","Server Pack 1","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059")
1170 $Null = $TableExploits.Rows.Add("Windows Server 2000","Server Pack 1","exploit/windows/iis/ms03_007_ntdll_webdav","http://www.cvedetails.com/cve/2003-0109")
1171 $Null = $TableExploits.Rows.Add("Windows Server 2000","Server Pack 1","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/")
1172 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 2","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1173 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 2","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059")
1174 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 2","exploit/windows/iis/ms03_007_ntdll_webdav","http://www.cvedetails.com/cve/2003-0109")
1175 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 2","exploit/windows/smb/ms04_011_lsass","http://www.cvedetails.com/cve/2003-0533/")
1176 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 2","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/")
1177 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 3","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1178 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 3","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059")
1179 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 3","exploit/windows/iis/ms03_007_ntdll_webdav","http://www.cvedetails.com/cve/2003-0109")
1180 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 3","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/")
1181 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1182 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059")
1183 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/dcerpc/ms07_029_msdns_zonename","http://www.cvedetails.com/cve/2007-1748")
1184 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/smb/ms04_011_lsass","http://www.cvedetails.com/cve/2003-0533/")
1185 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439")
1186 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/smb/ms06_066_nwapi","http://www.cvedetails.com/cve/2006-4688")
1187 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/smb/ms06_070_wkssvc","http://www.cvedetails.com/cve/2006-4691")
1188 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1189 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/")
1190 $Null = $TableExploits.Rows.Add("Windows Server 2000","","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1191 $Null = $TableExploits.Rows.Add("Windows Server 2000","","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059")
1192 $Null = $TableExploits.Rows.Add("Windows Server 2000","","exploit/windows/iis/ms03_007_ntdll_webdav","http://www.cvedetails.com/cve/2003-0109")
1193 $Null = $TableExploits.Rows.Add("Windows Server 2000","","exploit/windows/smb/ms05_039_pnp","http://www.cvedetails.com/cve/2005-1983")
1194 $Null = $TableExploits.Rows.Add("Windows Server 2000","","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/")
1195 $Null = $TableExploits.Rows.Add("Windows Server 2003","Server Pack 1","exploit/windows/dcerpc/ms07_029_msdns_zonename","http://www.cvedetails.com/cve/2007-1748")
1196 $Null = $TableExploits.Rows.Add("Windows Server 2003","Server Pack 1","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439")
1197 $Null = $TableExploits.Rows.Add("Windows Server 2003","Server Pack 1","exploit/windows/smb/ms06_066_nwapi","http://www.cvedetails.com/cve/2006-4688")
1198 $Null = $TableExploits.Rows.Add("Windows Server 2003","Server Pack 1","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1199 $Null = $TableExploits.Rows.Add("Windows Server 2003","Server Pack 1","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/")
1200 $Null = $TableExploits.Rows.Add("Windows Server 2003","Service Pack 2","exploit/windows/dcerpc/ms07_029_msdns_zonename","http://www.cvedetails.com/cve/2007-1748")
1201 $Null = $TableExploits.Rows.Add("Windows Server 2003","Service Pack 2","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1202 $Null = $TableExploits.Rows.Add("Windows Server 2003","Service Pack 2","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1203 $Null = $TableExploits.Rows.Add("Windows Server 2003","","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1204 $Null = $TableExploits.Rows.Add("Windows Server 2003","","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439")
1205 $Null = $TableExploits.Rows.Add("Windows Server 2003","","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1206 $Null = $TableExploits.Rows.Add("Windows Server 2003","","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/")
1207 $Null = $TableExploits.Rows.Add("Windows Server 2003 R2","","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1208 $Null = $TableExploits.Rows.Add("Windows Server 2003 R2","","exploit/windows/smb/ms04_011_lsass","http://www.cvedetails.com/cve/2003-0533/")
1209 $Null = $TableExploits.Rows.Add("Windows Server 2003 R2","","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439")
1210 $Null = $TableExploits.Rows.Add("Windows Server 2003 R2","","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/")
1211 $Null = $TableExploits.Rows.Add("Windows Server 2008","Service Pack 2","exploit/windows/smb/ms09_050_smb2_negotiate_func_index","http://www.cvedetails.com/cve/2009-3103")
1212 $Null = $TableExploits.Rows.Add("Windows Server 2008","Service Pack 2","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1213 $Null = $TableExploits.Rows.Add("Windows Server 2008","","exploit/windows/smb/ms09_050_smb2_negotiate_func_index","http://www.cvedetails.com/cve/2009-3103")
1214 $Null = $TableExploits.Rows.Add("Windows Server 2008","","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1215 $Null = $TableExploits.Rows.Add("Windows Server 2008 R2","","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1216 $Null = $TableExploits.Rows.Add("Windows Vista","Server Pack 1","exploit/windows/smb/ms09_050_smb2_negotiate_func_index","http://www.cvedetails.com/cve/2009-3103")
1217 $Null = $TableExploits.Rows.Add("Windows Vista","Server Pack 1","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1218 $Null = $TableExploits.Rows.Add("Windows Vista","Service Pack 2","exploit/windows/smb/ms09_050_smb2_negotiate_func_index","http://www.cvedetails.com/cve/2009-3103")
1219 $Null = $TableExploits.Rows.Add("Windows Vista","Service Pack 2","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1220 $Null = $TableExploits.Rows.Add("Windows Vista","","exploit/windows/smb/ms09_050_smb2_negotiate_func_index","http://www.cvedetails.com/cve/2009-3103")
1221 $Null = $TableExploits.Rows.Add("Windows XP","Server Pack 1","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1222 $Null = $TableExploits.Rows.Add("Windows XP","Server Pack 1","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059")
1223 $Null = $TableExploits.Rows.Add("Windows XP","Server Pack 1","exploit/windows/smb/ms04_011_lsass","http://www.cvedetails.com/cve/2003-0533/")
1224 $Null = $TableExploits.Rows.Add("Windows XP","Server Pack 1","exploit/windows/smb/ms05_039_pnp","http://www.cvedetails.com/cve/2005-1983")
1225 $Null = $TableExploits.Rows.Add("Windows XP","Server Pack 1","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439")
1226 $Null = $TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059")
1227 $Null = $TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439")
1228 $Null = $TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/smb/ms06_066_nwapi","http://www.cvedetails.com/cve/2006-4688")
1229 $Null = $TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/smb/ms06_070_wkssvc","http://www.cvedetails.com/cve/2006-4691")
1230 $Null = $TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1231 $Null = $TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1232 $Null = $TableExploits.Rows.Add("Windows XP","Service Pack 3","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1233 $Null = $TableExploits.Rows.Add("Windows XP","Service Pack 3","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1234 $Null = $TableExploits.Rows.Add("Windows XP","","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1235 $Null = $TableExploits.Rows.Add("Windows XP","","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059")
1236 $Null = $TableExploits.Rows.Add("Windows XP","","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439")
1237 $Null = $TableExploits.Rows.Add("Windows XP","","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1238
1239 # Status user
1240 Write-Verbose "[*] Checking computers for vulnerable OS and SP levels..."
1241
1242 # ----------------------------------------------------------------
1243 # Setup data table to store vulnerable systems
1244 # ----------------------------------------------------------------
1245
1246 # Create data table to house vulnerable server list
1247 $TableVulnComputers = New-Object System.Data.DataTable
1248 $Null = $TableVulnComputers.Columns.Add('ComputerName')
1249 $Null = $TableVulnComputers.Columns.Add('OperatingSystem')
1250 $Null = $TableVulnComputers.Columns.Add('ServicePack')
1251 $Null = $TableVulnComputers.Columns.Add('LastLogon')
1252 $Null = $TableVulnComputers.Columns.Add('MsfModule')
1253 $Null = $TableVulnComputers.Columns.Add('CVE')
1254
1255 # Iterate through each exploit
1256 $TableExploits | ForEach-Object {
1257
1258 $ExploitOS = $_.OperatingSystem
1259 $ExploitSP = $_.ServicePack
1260 $ExploitMsf = $_.MsfModule
1261 $ExploitCVE = $_.CVE
1262
1263 # Iterate through each ADS computer
1264 $TableAdsComputers | ForEach-Object {
1265
1266 $AdsHostname = $_.Hostname
1267 $AdsOS = $_.OperatingSystem
1268 $AdsSP = $_.ServicePack
1269 $AdsLast = $_.LastLogon
1270
1271 # Add exploitable systems to vul computers data table
1272 if ($AdsOS -like "$ExploitOS*" -and $AdsSP -like "$ExploitSP" ) {
1273 # Add domain computer to data table
1274 $Null = $TableVulnComputers.Rows.Add($AdsHostname,$AdsOS,$AdsSP,$AdsLast,$ExploitMsf,$ExploitCVE)
1275 }
1276 }
1277 }
1278
1279 # Display results
1280 $VulnComputer = $TableVulnComputers | Select-Object ComputerName -Unique | Measure-Object
1281 $VulnComputerCount = $VulnComputer.Count
1282
1283 if ($VulnComputer.Count -gt 0) {
1284 # Return vulnerable server list order with some hack date casting
1285 Write-Verbose "[+] Found $VulnComputerCount potentially vulnerable systems!"
1286 $TableVulnComputers | Sort-Object { $_.lastlogon -as [datetime]} -Descending
1287 }
1288 else {
1289 Write-Verbose "[-] No vulnerable systems were found."
1290 }
1291}
1292
1293function Get-NetFileServer {
1294
1295 [CmdletBinding()]
1296 param(
1297 [String]
1298 $Domain,
1299
1300 [String]
1301 $DomainController,
1302
1303 [String[]]
1304 $TargetUsers,
1305
1306 [ValidateRange(1,10000)]
1307 [Int]
1308 $PageSize = 200,
1309
1310 [Management.Automation.PSCredential]
1311 $Credential
1312 )
1313
1314 function SplitPath {
1315 # short internal helper to split UNC server paths
1316 param([String]$Path)
1317
1318 if ($Path -and ($Path.split("\\").Count -ge 3)) {
1319 $Temp = $Path.split("\\")[2]
1320 if($Temp -and ($Temp -ne '')) {
1321 $Temp
1322 }
1323 }
1324 }
1325 $filter = "(!(userAccountControl:1.2.840.113556.1.4.803:=2))(|(scriptpath=*)(homedirectory=*)(profilepath=*))"
1326 Get-NetUser -Domain $Domain -DomainController $DomainController -Credential $Credential -PageSize $PageSize -Filter $filter | Where-Object {$_} | Where-Object {
1327 # filter for any target users
1328 if($TargetUsers) {
1329 $TargetUsers -Match $_.samAccountName
1330 }
1331 else { $True }
1332 } | ForEach-Object {
1333 # split out every potential file server path
1334 if($_.homedirectory) {
1335 SplitPath($_.homedirectory)
1336 }
1337 if($_.scriptpath) {
1338 SplitPath($_.scriptpath)
1339 }
1340 if($_.profilepath) {
1341 SplitPath($_.profilepath)
1342 }
1343
1344 } | Where-Object {$_} | Sort-Object -Unique
1345}
1346
1347function Get-NetComputer {
1348
1349 [CmdletBinding()]
1350 Param (
1351 [Parameter(ValueFromPipeline=$True)]
1352 [Alias('HostName')]
1353 [String]
1354 $ComputerName = '*',
1355
1356 [String]
1357 $SPN,
1358
1359 [String]
1360 $OperatingSystem,
1361
1362 [String]
1363 $ServicePack,
1364
1365 [String]
1366 $Filter,
1367
1368 [Switch]
1369 $Printers,
1370
1371 [Switch]
1372 $Ping,
1373
1374 [Switch]
1375 $FullData,
1376
1377 [String]
1378 $Domain,
1379
1380 [String]
1381 $DomainController,
1382
1383 [String]
1384 $ADSpath,
1385
1386 [String]
1387 $SiteName,
1388
1389 [Switch]
1390 $Unconstrained,
1391
1392 [ValidateRange(1,10000)]
1393 [Int]
1394 $PageSize = 200,
1395
1396 [Management.Automation.PSCredential]
1397 $Credential
1398 )
1399
1400 begin {
1401 # so this isn't repeated if multiple computer names are passed on the pipeline
1402 $CompSearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -ADSpath $ADSpath -PageSize $PageSize -Credential $Credential
1403 }
1404
1405 process {
1406
1407 if ($CompSearcher) {
1408
1409 # if we're checking for unconstrained delegation
1410 if($Unconstrained) {
1411 Write-Verbose "Searching for computers with for unconstrained delegation"
1412 $Filter += "(userAccountControl:1.2.840.113556.1.4.803:=524288)"
1413 }
1414 # set the filters for the seracher if it exists
1415 if($Printers) {
1416 Write-Verbose "Searching for printers"
1417 # $CompSearcher.filter="(&(objectCategory=printQueue)$Filter)"
1418 $Filter += "(objectCategory=printQueue)"
1419 }
1420 if($SPN) {
1421 Write-Verbose "Searching for computers with SPN: $SPN"
1422 $Filter += "(servicePrincipalName=$SPN)"
1423 }
1424 if($OperatingSystem) {
1425 $Filter += "(operatingsystem=$OperatingSystem)"
1426 }
1427 if($ServicePack) {
1428 $Filter += "(operatingsystemservicepack=$ServicePack)"
1429 }
1430 if($SiteName) {
1431 $Filter += "(serverreferencebl=$SiteName)"
1432 }
1433
1434 $CompFilter = "(&(sAMAccountType=805306369)(dnshostname=$ComputerName)$Filter)"
1435 Write-Verbose "Get-NetComputer filter : '$CompFilter'"
1436 $CompSearcher.filter = $CompFilter
1437
1438 try {
1439 $Results = $CompSearcher.FindAll()
1440 $Results | Where-Object {$_} | ForEach-Object {
1441 $Up = $True
1442 if($Ping) {
1443 # TODO: how can these results be piped to ping for a speedup?
1444 $Up = Test-Connection -Count 1 -Quiet -ComputerName $_.properties.dnshostname
1445 }
1446 if($Up) {
1447 # return full data objects
1448 if ($FullData) {
1449 # convert/process the LDAP fields for each result
1450 $Computer = Convert-LDAPProperty -Properties $_.Properties
1451 $Computer.PSObject.TypeNames.Add('PowerView.Computer')
1452 $Computer
1453 }
1454 else {
1455 # otherwise we're just returning the DNS host name
1456 $_.properties.dnshostname
1457 }
1458 }
1459 }
1460 $Results.dispose()
1461 $CompSearcher.dispose()
1462 }
1463 catch {
1464 Write-Warning "Error: $_"
1465 }
1466 }
1467 }
1468}
1469
1470function Get-NetGPO {
1471 [CmdletBinding()]
1472 Param (
1473 [Parameter(ValueFromPipeline=$True)]
1474 [String]
1475 $GPOname = '*',
1476
1477 [String]
1478 $DisplayName,
1479
1480 [String]
1481 $ComputerName,
1482
1483 [String]
1484 $Domain,
1485
1486 [String]
1487 $DomainController,
1488
1489 [String]
1490 $ADSpath,
1491
1492 [ValidateRange(1,10000)]
1493 [Int]
1494 $PageSize = 200,
1495
1496 [Management.Automation.PSCredential]
1497 $Credential
1498 )
1499
1500 begin {
1501 $GPOSearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -Credential $Credential -ADSpath $ADSpath -PageSize $PageSize
1502 }
1503
1504 process {
1505 if ($GPOSearcher) {
1506
1507 if($ComputerName) {
1508 $GPONames = @()
1509 $Computers = Get-NetComputer -ComputerName $ComputerName -Domain $Domain -DomainController $DomainController -FullData -PageSize $PageSize
1510
1511 if(!$Computers) {
1512 throw "Computer $ComputerName in domain '$Domain' not found! Try a fully qualified host name"
1513 }
1514
1515 # get the given computer's OU
1516 $ComputerOUs = @()
1517 ForEach($Computer in $Computers) {
1518 # extract all OUs a computer is a part of
1519 $DN = $Computer.distinguishedname
1520
1521 $ComputerOUs += $DN.split(",") | ForEach-Object {
1522 if($_.startswith("OU=")) {
1523 $DN.substring($DN.indexof($_))
1524 }
1525 }
1526 }
1527
1528 Write-Verbose "ComputerOUs: $ComputerOUs"
1529
1530 # find all the GPOs linked to the computer's OU
1531 ForEach($ComputerOU in $ComputerOUs) {
1532 $GPONames += Get-NetOU -Domain $Domain -DomainController $DomainController -ADSpath $ComputerOU -FullData -PageSize $PageSize | ForEach-Object {
1533 # get any GPO links
1534 write-verbose "blah: $($_.name)"
1535 $_.gplink.split("][") | ForEach-Object {
1536 if ($_.startswith("LDAP")) {
1537 $_.split(";")[0]
1538 }
1539 }
1540 }
1541 }
1542
1543 Write-Verbose "GPONames: $GPONames"
1544
1545 # find any GPOs linked to the site for the given computer
1546 $ComputerSite = (Get-SiteName -ComputerName $ComputerName).SiteName
1547 if($ComputerSite -and ($ComputerSite -notlike 'Error*')) {
1548 $GPONames += Get-NetSite -SiteName $ComputerSite -FullData | ForEach-Object {
1549 if($_.gplink) {
1550 $_.gplink.split("][") | ForEach-Object {
1551 if ($_.startswith("LDAP")) {
1552 $_.split(";")[0]
1553 }
1554 }
1555 }
1556 }
1557 }
1558
1559 $GPONames | Where-Object{$_ -and ($_ -ne '')} | ForEach-Object {
1560
1561 # use the gplink as an ADS path to enumerate all GPOs for the computer
1562 $GPOSearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -Credential $Credential -ADSpath $_ -PageSize $PageSize
1563 $GPOSearcher.filter="(&(objectCategory=groupPolicyContainer)(name=$GPOname))"
1564
1565 try {
1566 $Results = $GPOSearcher.FindAll()
1567 $Results | Where-Object {$_} | ForEach-Object {
1568 $Out = Convert-LDAPProperty -Properties $_.Properties
1569 $Out | Add-Member Noteproperty 'ComputerName' $ComputerName
1570 $Out
1571 }
1572 $Results.dispose()
1573 $GPOSearcher.dispose()
1574 }
1575 catch {
1576 Write-Warning $_
1577 }
1578 }
1579 }
1580
1581 else {
1582 if($DisplayName) {
1583 $GPOSearcher.filter="(&(objectCategory=groupPolicyContainer)(displayname=$DisplayName))"
1584 }
1585 else {
1586 $GPOSearcher.filter="(&(objectCategory=groupPolicyContainer)(name=$GPOname))"
1587 }
1588
1589 try {
1590 $Results = $GPOSearcher.FindAll()
1591 $Results | Where-Object {$_} | ForEach-Object {
1592 if($ADSPath -and ($ADSpath -Match '^GC://')) {
1593 $Properties = Convert-LDAPProperty -Properties $_.Properties
1594 try {
1595 $GPODN = $Properties.distinguishedname
1596 $GPODomain = $GPODN.subString($GPODN.IndexOf("DC=")) -replace 'DC=','' -replace ',','.'
1597 $gpcfilesyspath = "\\$GPODomain\SysVol\$GPODomain\Policies\$($Properties.cn)"
1598 $Properties | Add-Member Noteproperty 'gpcfilesyspath' $gpcfilesyspath
1599 $Properties
1600 }
1601 catch {
1602 $Properties
1603 }
1604 }
1605 else {
1606 # convert/process the LDAP fields for each result
1607 Convert-LDAPProperty -Properties $_.Properties
1608 }
1609 }
1610 $Results.dispose()
1611 $GPOSearcher.dispose()
1612 }
1613 catch {
1614 Write-Warning $_
1615 }
1616 }
1617 }
1618 }
1619}
1620
1621function Invoke-ThreadedFunction {
1622 # Helper used by any threaded host enumeration functions
1623 [CmdletBinding()]
1624 param(
1625 [Parameter(Position=0,Mandatory=$True)]
1626 [String[]]
1627 $ComputerName,
1628
1629 [Parameter(Position=1,Mandatory=$True)]
1630 [System.Management.Automation.ScriptBlock]
1631 $ScriptBlock,
1632
1633 [Parameter(Position=2)]
1634 [Hashtable]
1635 $ScriptParameters,
1636
1637 [Int]
1638 [ValidateRange(1,100)]
1639 $Threads = 20,
1640
1641 [Switch]
1642 $NoImports
1643 )
1644
1645 begin {
1646
1647 if ($PSBoundParameters['Debug']) {
1648 $DebugPreference = 'Continue'
1649 }
1650
1651 Write-Verbose "[*] Total number of hosts: $($ComputerName.count)"
1652
1653 # Adapted from:
1654 # http://powershell.org/wp/forums/topic/invpke-parallel-need-help-to-clone-the-current-runspace/
1655 $SessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
1656 $SessionState.ApartmentState = [System.Threading.Thread]::CurrentThread.GetApartmentState()
1657
1658 # import the current session state's variables and functions so the chained PowerView
1659 # functionality can be used by the threaded blocks
1660 if(!$NoImports) {
1661
1662 # grab all the current variables for this runspace
1663 $MyVars = Get-Variable -Scope 2
1664
1665 # these Variables are added by Runspace.Open() Method and produce Stop errors if you add them twice
1666 $VorbiddenVars = @("?","args","ConsoleFileName","Error","ExecutionContext","false","HOME","Host","input","InputObject","MaximumAliasCount","MaximumDriveCount","MaximumErrorCount","MaximumFunctionCount","MaximumHistoryCount","MaximumVariableCount","MyInvocation","null","PID","PSBoundParameters","PSCommandPath","PSCulture","PSDefaultParameterValues","PSHOME","PSScriptRoot","PSUICulture","PSVersionTable","PWD","ShellId","SynchronizedHash","true")
1667
1668 # Add Variables from Parent Scope (current runspace) into the InitialSessionState
1669 ForEach($Var in $MyVars) {
1670 if($VorbiddenVars -NotContains $Var.Name) {
1671 $SessionState.Variables.Add((New-Object -TypeName System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList $Var.name,$Var.Value,$Var.description,$Var.options,$Var.attributes))
1672 }
1673 }
1674
1675 # Add Functions from current runspace to the InitialSessionState
1676 ForEach($Function in (Get-ChildItem Function:)) {
1677 $SessionState.Commands.Add((New-Object -TypeName System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList $Function.Name, $Function.Definition))
1678 }
1679 }
1680
1681 # threading adapted from
1682 # https://github.com/darkoperator/Posh-SecMod/blob/master/Discovery/Discovery.psm1#L407
1683 # Thanks Carlos!
1684
1685 # create a pool of maxThread runspaces
1686 $Pool = [runspacefactory]::CreateRunspacePool(1, $Threads, $SessionState, $Host)
1687 $Pool.Open()
1688
1689 $method = $null
1690 ForEach ($m in [PowerShell].GetMethods() | Where-Object { $_.Name -eq "BeginInvoke" }) {
1691 $methodParameters = $m.GetParameters()
1692 if (($methodParameters.Count -eq 2) -and $methodParameters[0].Name -eq "input" -and $methodParameters[1].Name -eq "output") {
1693 $method = $m.MakeGenericMethod([Object], [Object])
1694 break
1695 }
1696 }
1697
1698 $Jobs = @()
1699 }
1700
1701 process {
1702
1703 ForEach ($Computer in $ComputerName) {
1704
1705 # make sure we get a server name
1706 if ($Computer -ne '') {
1707 # Write-Verbose "[*] Enumerating server $Computer ($($Counter+1) of $($ComputerName.count))"
1708
1709 While ($($Pool.GetAvailableRunspaces()) -le 0) {
1710 Start-Sleep -MilliSeconds 500
1711 }
1712
1713 # create a "powershell pipeline runner"
1714 $p = [powershell]::create()
1715
1716 $p.runspacepool = $Pool
1717
1718 # add the script block + arguments
1719 $Null = $p.AddScript($ScriptBlock).AddParameter('ComputerName', $Computer)
1720 if($ScriptParameters) {
1721 ForEach ($Param in $ScriptParameters.GetEnumerator()) {
1722 $Null = $p.AddParameter($Param.Name, $Param.Value)
1723 }
1724 }
1725
1726 $o = New-Object Management.Automation.PSDataCollection[Object]
1727
1728 $Jobs += @{
1729 PS = $p
1730 Output = $o
1731 Result = $method.Invoke($p, @($null, [Management.Automation.PSDataCollection[Object]]$o))
1732 }
1733 }
1734 }
1735 }
1736
1737 end {
1738 Write-Verbose "Waiting for threads to finish..."
1739
1740 Do {
1741 ForEach ($Job in $Jobs) {
1742 $Job.Output.ReadAll()
1743 }
1744 } While (($Jobs | Where-Object { ! $_.Result.IsCompleted }).Count -gt 0)
1745
1746 ForEach ($Job in $Jobs) {
1747 $Job.PS.Dispose()
1748 }
1749
1750 $Pool.Dispose()
1751 Write-Verbose "All threads completed!"
1752 }
1753}
1754
1755
1756$Mod = New-InMemoryModule -ModuleName Win32
1757
1758# all of the Win32 API functions we need
1759$FunctionDefinitions = @(
1760 (func netapi32 NetShareEnum ([Int]) @([String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
1761 (func netapi32 NetWkstaUserEnum ([Int]) @([String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
1762 (func netapi32 NetSessionEnum ([Int]) @([String], [String], [String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
1763 (func netapi32 NetLocalGroupGetMembers ([Int]) @([String], [String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
1764 (func netapi32 DsGetSiteName ([Int]) @([String], [IntPtr].MakeByRefType())),
1765 (func netapi32 DsEnumerateDomainTrusts ([Int]) @([String], [UInt32], [IntPtr].MakeByRefType(), [IntPtr].MakeByRefType())),
1766 (func netapi32 NetApiBufferFree ([Int]) @([IntPtr])),
1767 (func advapi32 ConvertSidToStringSid ([Int]) @([IntPtr], [String].MakeByRefType()) -SetLastError),
1768 (func advapi32 OpenSCManagerW ([IntPtr]) @([String], [String], [Int]) -SetLastError),
1769 (func advapi32 CloseServiceHandle ([Int]) @([IntPtr])),
1770 (func wtsapi32 WTSOpenServerEx ([IntPtr]) @([String])),
1771 (func wtsapi32 WTSEnumerateSessionsEx ([Int]) @([IntPtr], [Int32].MakeByRefType(), [Int], [IntPtr].MakeByRefType(), [Int32].MakeByRefType()) -SetLastError),
1772 (func wtsapi32 WTSQuerySessionInformation ([Int]) @([IntPtr], [Int], [Int], [IntPtr].MakeByRefType(), [Int32].MakeByRefType()) -SetLastError),
1773 (func wtsapi32 WTSFreeMemoryEx ([Int]) @([Int32], [IntPtr], [Int32])),
1774 (func wtsapi32 WTSFreeMemory ([Int]) @([IntPtr])),
1775 (func wtsapi32 WTSCloseServer ([Int]) @([IntPtr]))
1776)
1777
1778# enum used by $WTS_SESSION_INFO_1 below
1779$WTSConnectState = psenum $Mod WTS_CONNECTSTATE_CLASS UInt16 @{
1780 Active = 0
1781 Connected = 1
1782 ConnectQuery = 2
1783 Shadow = 3
1784 Disconnected = 4
1785 Idle = 5
1786 Listen = 6
1787 Reset = 7
1788 Down = 8
1789 Init = 9
1790}
1791
1792# the WTSEnumerateSessionsEx result structure
1793$WTS_SESSION_INFO_1 = struct $Mod WTS_SESSION_INFO_1 @{
1794 ExecEnvId = field 0 UInt32
1795 State = field 1 $WTSConnectState
1796 SessionId = field 2 UInt32
1797 pSessionName = field 3 String -MarshalAs @('LPWStr')
1798 pHostName = field 4 String -MarshalAs @('LPWStr')
1799 pUserName = field 5 String -MarshalAs @('LPWStr')
1800 pDomainName = field 6 String -MarshalAs @('LPWStr')
1801 pFarmName = field 7 String -MarshalAs @('LPWStr')
1802}
1803
1804# the particular WTSQuerySessionInformation result structure
1805$WTS_CLIENT_ADDRESS = struct $mod WTS_CLIENT_ADDRESS @{
1806 AddressFamily = field 0 UInt32
1807 Address = field 1 Byte[] -MarshalAs @('ByValArray', 20)
1808}
1809
1810# the NetShareEnum result structure
1811$SHARE_INFO_1 = struct $Mod SHARE_INFO_1 @{
1812 shi1_netname = field 0 String -MarshalAs @('LPWStr')
1813 shi1_type = field 1 UInt32
1814 shi1_remark = field 2 String -MarshalAs @('LPWStr')
1815}
1816
1817# the NetWkstaUserEnum result structure
1818$WKSTA_USER_INFO_1 = struct $Mod WKSTA_USER_INFO_1 @{
1819 wkui1_username = field 0 String -MarshalAs @('LPWStr')
1820 wkui1_logon_domain = field 1 String -MarshalAs @('LPWStr')
1821 wkui1_oth_domains = field 2 String -MarshalAs @('LPWStr')
1822 wkui1_logon_server = field 3 String -MarshalAs @('LPWStr')
1823}
1824
1825# the NetSessionEnum result structure
1826$SESSION_INFO_10 = struct $Mod SESSION_INFO_10 @{
1827 sesi10_cname = field 0 String -MarshalAs @('LPWStr')
1828 sesi10_username = field 1 String -MarshalAs @('LPWStr')
1829 sesi10_time = field 2 UInt32
1830 sesi10_idle_time = field 3 UInt32
1831}
1832
1833# enum used by $LOCALGROUP_MEMBERS_INFO_2 below
1834$SID_NAME_USE = psenum $Mod SID_NAME_USE UInt16 @{
1835 SidTypeUser = 1
1836 SidTypeGroup = 2
1837 SidTypeDomain = 3
1838 SidTypeAlias = 4
1839 SidTypeWellKnownGroup = 5
1840 SidTypeDeletedAccount = 6
1841 SidTypeInvalid = 7
1842 SidTypeUnknown = 8
1843 SidTypeComputer = 9
1844}
1845
1846# the NetLocalGroupGetMembers result structure
1847$LOCALGROUP_MEMBERS_INFO_2 = struct $Mod LOCALGROUP_MEMBERS_INFO_2 @{
1848 lgrmi2_sid = field 0 IntPtr
1849 lgrmi2_sidusage = field 1 $SID_NAME_USE
1850 lgrmi2_domainandname = field 2 String -MarshalAs @('LPWStr')
1851}
1852
1853# enums used in DS_DOMAIN_TRUSTS
1854$DsDomainFlag = psenum $Mod DsDomain.Flags UInt32 @{
1855 IN_FOREST = 1
1856 DIRECT_OUTBOUND = 2
1857 TREE_ROOT = 4
1858 PRIMARY = 8
1859 NATIVE_MODE = 16
1860 DIRECT_INBOUND = 32
1861} -Bitfield
1862$DsDomainTrustType = psenum $Mod DsDomain.TrustType UInt32 @{
1863 DOWNLEVEL = 1
1864 UPLEVEL = 2
1865 MIT = 3
1866 DCE = 4
1867}
1868$DsDomainTrustAttributes = psenum $Mod DsDomain.TrustAttributes UInt32 @{
1869 NON_TRANSITIVE = 1
1870 UPLEVEL_ONLY = 2
1871 FILTER_SIDS = 4
1872 FOREST_TRANSITIVE = 8
1873 CROSS_ORGANIZATION = 16
1874 WITHIN_FOREST = 32
1875 TREAT_AS_EXTERNAL = 64
1876}
1877
1878# the DsEnumerateDomainTrusts result structure
1879$DS_DOMAIN_TRUSTS = struct $Mod DS_DOMAIN_TRUSTS @{
1880 NetbiosDomainName = field 0 String -MarshalAs @('LPWStr')
1881 DnsDomainName = field 1 String -MarshalAs @('LPWStr')
1882 Flags = field 2 $DsDomainFlag
1883 ParentIndex = field 3 UInt32
1884 TrustType = field 4 $DsDomainTrustType
1885 TrustAttributes = field 5 $DsDomainTrustAttributes
1886 DomainSid = field 6 IntPtr
1887 DomainGuid = field 7 Guid
1888}
1889
1890$Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32'
1891$Netapi32 = $Types['netapi32']
1892$Advapi32 = $Types['advapi32']
1893$Wtsapi32 = $Types['wtsapi32']