Added NetLocalGroupGetMembers enumeration method for Get-NetLocalGroup with the -API flag

Fixed threading specification in most threaded functions.
This commit is contained in:
Harmj0y 2016-03-07 02:00:00 -05:00
parent 26ca1a922e
commit b4891eb371
1 changed files with 339 additions and 188 deletions

View File

@ -6570,6 +6570,11 @@ function Get-NetLocalGroup {
Switch. If the local member member is a domain group, recursively try to resolve its members to get a list of domain users who can access this machine. Switch. If the local member member is a domain group, recursively try to resolve its members to get a list of domain users who can access this machine.
.PARAMETER API
Switch. Use API calls instead of the WinNT service provider. Less information,
but the results are faster.
.EXAMPLE .EXAMPLE
PS C:\> Get-NetLocalGroup PS C:\> Get-NetLocalGroup
@ -6595,42 +6600,52 @@ function Get-NetLocalGroup {
Returns all local groups on the WINDOWS7 host. Returns all local groups on the WINDOWS7 host.
.EXAMPLE
PS C:\> "WINDOWS7", "WINDOWSSP" | Get-NetLocalGroup -API
Returns all local groups on the the passed hosts using API calls instead of the
WinNT service provider.
.LINK .LINK
http://stackoverflow.com/questions/21288220/get-all-local-members-and-groups-displayed-together http://stackoverflow.com/questions/21288220/get-all-local-members-and-groups-displayed-together
http://msdn.microsoft.com/en-us/library/aa772211(VS.85).aspx http://msdn.microsoft.com/en-us/library/aa772211(VS.85).aspx
#> #>
[CmdletBinding()] [CmdletBinding(DefaultParameterSetName = 'WinNT')]
param( param(
[Parameter(ValueFromPipeline=$True)] [Parameter(ParameterSetName = 'API', Position=0, ValueFromPipeline=$True)]
[Parameter(ParameterSetName = 'WinNT', Position=0, ValueFromPipeline=$True)]
[Alias('HostName')] [Alias('HostName')]
[String[]] [String[]]
$ComputerName = 'localhost', $ComputerName = 'localhost',
[Parameter(ParameterSetName = 'WinNT')]
[Parameter(ParameterSetName = 'API')]
[ValidateScript({Test-Path -Path $_ })] [ValidateScript({Test-Path -Path $_ })]
[Alias('HostList')] [Alias('HostList')]
[String] [String]
$ComputerFile, $ComputerFile,
[Parameter(ParameterSetName = 'WinNT')]
[Parameter(ParameterSetName = 'API')]
[String] [String]
$GroupName, $GroupName = 'Administrators',
[Parameter(ParameterSetName = 'WinNT')]
[Switch] [Switch]
$ListGroups, $ListGroups,
[Parameter(ParameterSetName = 'WinNT')]
[Switch] [Switch]
$Recurse $Recurse,
[Parameter(ParameterSetName = 'API')]
[Switch]
$API
) )
begin {
if ((-not $ListGroups) -and (-not $GroupName)) {
# resolve the SID for the local admin group - this should usually default to "Administrators"
$ObjSID = New-Object System.Security.Principal.SecurityIdentifier('S-1-5-32-544')
$Objgroup = $ObjSID.Translate( [System.Security.Principal.NTAccount])
$GroupName = ($Objgroup.Value).Split('\')[1]
}
}
process { process {
$Servers = @() $Servers = @()
@ -6647,168 +6662,262 @@ function Get-NetLocalGroup {
# query the specified group using the WINNT provider, and # query the specified group using the WINNT provider, and
# extract fields as appropriate from the results # extract fields as appropriate from the results
ForEach($Server in $Servers) { ForEach($Server in $Servers) {
try {
if($ListGroups) {
# if we're listing the group names on a remote server
$Computer = [ADSI]"WinNT://$Server,computer"
$Computer.psbase.children | Where-Object { $_.psbase.schemaClassName -eq 'group' } | ForEach-Object { if($API) {
$Group = New-Object PSObject # if we're using the Netapi32 NetLocalGroupGetMembers API call to
$Group | Add-Member Noteproperty 'Server' $Server # get the local group information
$Group | Add-Member Noteproperty 'Group' ($_.name[0])
$Group | Add-Member Noteproperty 'SID' ((New-Object System.Security.Principal.SecurityIdentifier $_.objectsid[0],0).Value) # arguments for NetLocalGroupGetMembers
$Group | Add-Member Noteproperty 'Description' ($_.Description[0]) $QueryLevel = 2
$Group $PtrInfo = [IntPtr]::Zero
$EntriesRead = 0
$TotalRead = 0
$ResumeHandle = 0
# get the local user information
$Result = $Netapi32::NetLocalGroupGetMembers($Server, $GroupName, $QueryLevel, [ref]$PtrInfo, -1, [ref]$EntriesRead, [ref]$TotalRead, [ref]$ResumeHandle)
# Locate the offset of the initial intPtr
$Offset = $PtrInfo.ToInt64()
Write-Debug "NetLocalGroupGetMembers result for $Server : $Result"
$LocalUsers = @()
# 0 = success
if (($Result -eq 0) -and ($Offset -gt 0)) {
# Work out how mutch to increment the pointer by finding out the size of the structure
$Increment = $LOCALGROUP_MEMBERS_INFO_2::GetSize()
# parse all the result structures
for ($i = 0; ($i -lt $EntriesRead); $i++) {
# create a new int ptr at the given offset and cast
# the pointer as our result structure
$NewIntPtr = New-Object System.Intptr -ArgumentList $Offset
$Info = $NewIntPtr -as $LOCALGROUP_MEMBERS_INFO_2
$SidString = ""
$Result = $Advapi32::ConvertSidToStringSid($Info.lgrmi2_sid, [ref]$SidString)
Write-Debug "Result of ConvertSidToStringSid: $Result"
if($Result -eq 0) {
# error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
$Err = $Kernel32::GetLastError()
Write-Error "ConvertSidToStringSid LastError: $Err"
}
else {
$LocalUser = New-Object PSObject
$LocalUser | Add-Member Noteproperty 'ComputerName' $Server
$LocalUser | Add-Member Noteproperty 'MemberName' $Info.lgrmi2_domainandname
$LocalUser | Add-Member Noteproperty 'SID' $SidString
$LocalUser | Add-Member Noteproperty 'SidType' $Info.lgrmi2_sidusage
$Offset = $NewIntPtr.ToInt64()
$Offset += $Increment
$LocalUsers += $LocalUser
}
} }
# free up the result buffer
$Null = $Netapi32::NetApiBufferFree($PtrInfo)
# try to extract out the machine SID by using the -500 account as a reference
$MachineSid = $LocalUsers | Where-Object {$_.SID -like '*-500'}
$Parts = $MachineSid.SID.Split('-')
$MachineSid = $Parts[0..($Parts.Length -2)] -join '-'
$LocalUsers | ForEach-Object {
if($_.SID -match $MachineSid) {
$_ | Add-Member Noteproperty 'IsDomain' $False
}
else {
$_ | Add-Member Noteproperty 'IsDomain' $True
}
}
$LocalUsers
} }
else { else
# otherwise we're listing the group members {
$Members = @($([ADSI]"WinNT://$Server/$GroupName,group").psbase.Invoke('Members')) switch ($Result) {
(5) {Write-Debug 'The user does not have access to the requested information.'}
$Members | ForEach-Object { (124) {Write-Debug 'The value specified for the level parameter is not valid.'}
(87) {Write-Debug 'The specified parameter is not valid.'}
$Member = New-Object PSObject (234) {Write-Debug 'More entries are available. Specify a large enough buffer to receive all entries.'}
$Member | Add-Member Noteproperty 'ComputerName' $Server (8) {Write-Debug 'Insufficient memory is available.'}
(2312) {Write-Debug 'A session does not exist with the computer name.'}
$AdsPath = ($_.GetType().InvokeMember('Adspath', 'GetProperty', $Null, $_, $Null)).Replace('WinNT://', '') (2351) {Write-Debug 'The computer name is not valid.'}
(2221) {Write-Debug 'Username not found.'}
# try to translate the NT4 domain to a FQDN if possible (53) {Write-Debug 'Hostname could not be found'}
$Name = Convert-NT4toCanonical -ObjectName $AdsPath
if($Name) {
$FQDN = $Name.split("/")[0]
$ObjName = $AdsPath.split("/")[-1]
$Name = "$FQDN/$ObjName"
$IsDomain = $True
}
else {
$Name = $AdsPath
$IsDomain = $False
}
$Member | Add-Member Noteproperty 'AccountName' $Name
if($IsDomain) {
# translate the binary sid to a string
$Member | Add-Member Noteproperty 'SID' ((New-Object System.Security.Principal.SecurityIdentifier($_.GetType().InvokeMember('ObjectSID', 'GetProperty', $Null, $_, $Null),0)).Value)
$Member | Add-Member Noteproperty 'Description' ""
$Member | Add-Member Noteproperty 'Disabled' $False
# check if the member is a group
$IsGroup = ($_.GetType().InvokeMember('Class', 'GetProperty', $Null, $_, $Null) -eq 'group')
$Member | Add-Member Noteproperty 'IsGroup' $IsGroup
$Member | Add-Member Noteproperty 'IsDomain' $IsDomain
if($IsGroup) {
$Member | Add-Member Noteproperty 'LastLogin' $Null
}
else {
try {
$Member | Add-Member Noteproperty 'LastLogin' ( $_.GetType().InvokeMember('LastLogin', 'GetProperty', $Null, $_, $Null))
}
catch {
$Member | Add-Member Noteproperty 'LastLogin' $Null
}
}
$Member | Add-Member Noteproperty 'PwdLastSet' ""
$Member | Add-Member Noteproperty 'PwdExpired' ""
$Member | Add-Member Noteproperty 'UserFlags' ""
}
else {
# repull this user object so we can ensure correct information
$LocalUser = $([ADSI] "WinNT://$AdsPath")
# translate the binary sid to a string
$Member | Add-Member Noteproperty 'SID' ((New-Object System.Security.Principal.SecurityIdentifier($LocalUser.objectSid.value,0)).Value)
$Member | Add-Member Noteproperty 'Description' ($LocalUser.Description[0])
# UAC flags of 0x2 mean the account is disabled
$Member | Add-Member Noteproperty 'Disabled' $(($LocalUser.userFlags.value -band 2) -eq 2)
# check if the member is a group
$Member | Add-Member Noteproperty 'IsGroup' ($LocalUser.SchemaClassName -like 'group')
$Member | Add-Member Noteproperty 'IsDomain' $IsDomain
if($IsGroup) {
$Member | Add-Member Noteproperty 'LastLogin' ""
}
else {
try {
$Member | Add-Member Noteproperty 'LastLogin' ( $LocalUser.LastLogin[0])
}
catch {
$Member | Add-Member Noteproperty 'LastLogin' ""
}
}
$Member | Add-Member Noteproperty 'PwdLastSet' ( (Get-Date).AddSeconds(-$LocalUser.PasswordAge[0]))
$Member | Add-Member Noteproperty 'PwdExpired' ( $LocalUser.PasswordExpired[0] -eq '1')
$Member | Add-Member Noteproperty 'UserFlags' ( $LocalUser.UserFlags[0] )
}
$Member
# if the result is a group domain object and we're recursing,
# try to resolve all the group member results
if($Recurse -and $IsDomain -and $IsGroup) {
$FQDN = $Name.split("/")[0]
$GroupName = $Name.split("/")[1].trim()
Get-NetGroupMember -GroupName $GroupName -Domain $FQDN -FullData -Recurse | ForEach-Object {
$Member = New-Object PSObject
$Member | Add-Member Noteproperty 'ComputerName' "$FQDN/$($_.GroupName)"
$MemberDN = $_.distinguishedName
# extract the FQDN from the Distinguished Name
$MemberDomain = $MemberDN.subString($MemberDN.IndexOf("DC=")) -replace 'DC=','' -replace ',','.'
if ($_.samAccountType -ne "805306368") {
$MemberIsGroup = $True
}
else {
$MemberIsGroup = $False
}
if ($_.samAccountName) {
# forest users have the samAccountName set
$MemberName = $_.samAccountName
}
else {
try {
# external trust users have a SID, so convert it
try {
$MemberName = Convert-SidToName $_.cn
}
catch {
# if there's a problem contacting the domain to resolve the SID
$MemberName = $_.cn
}
}
catch {
Write-Debug "Error resolving SID : $_"
}
}
$Member | Add-Member Noteproperty 'AccountName' "$MemberDomain/$MemberName"
$Member | Add-Member Noteproperty 'SID' $_.objectsid
$Member | Add-Member Noteproperty 'Description' $_.description
$Member | Add-Member Noteproperty 'Disabled' $False
$Member | Add-Member Noteproperty 'IsGroup' $MemberIsGroup
$Member | Add-Member Noteproperty 'IsDomain' $True
$Member | Add-Member Noteproperty 'LastLogin' ''
$Member | Add-Member Noteproperty 'PwdLastSet' $_.pwdLastSet
$Member | Add-Member Noteproperty 'PwdExpired' ''
$Member | Add-Member Noteproperty 'UserFlags' $_.userAccountControl
$Member
}
}
} }
} }
} }
catch {
Write-Warning "[!] Error: $_" else {
# otherwise we're using the WinNT service provider
try {
if($ListGroups) {
# if we're listing the group names on a remote server
$Computer = [ADSI]"WinNT://$Server,computer"
$Computer.psbase.children | Where-Object { $_.psbase.schemaClassName -eq 'group' } | ForEach-Object {
$Group = New-Object PSObject
$Group | Add-Member Noteproperty 'Server' $Server
$Group | Add-Member Noteproperty 'Group' ($_.name[0])
$Group | Add-Member Noteproperty 'SID' ((New-Object System.Security.Principal.SecurityIdentifier $_.objectsid[0],0).Value)
$Group | Add-Member Noteproperty 'Description' ($_.Description[0])
$Group
}
}
else {
# otherwise we're listing the group members
$Members = @($([ADSI]"WinNT://$Server/$GroupName,group").psbase.Invoke('Members'))
$Members | ForEach-Object {
$Member = New-Object PSObject
$Member | Add-Member Noteproperty 'ComputerName' $Server
$AdsPath = ($_.GetType().InvokeMember('Adspath', 'GetProperty', $Null, $_, $Null)).Replace('WinNT://', '')
# try to translate the NT4 domain to a FQDN if possible
$Name = Convert-NT4toCanonical -ObjectName $AdsPath
if($Name) {
$FQDN = $Name.split("/")[0]
$ObjName = $AdsPath.split("/")[-1]
$Name = "$FQDN/$ObjName"
$IsDomain = $True
}
else {
$Name = $AdsPath
$IsDomain = $False
}
$Member | Add-Member Noteproperty 'AccountName' $Name
if($IsDomain) {
# translate the binary sid to a string
$Member | Add-Member Noteproperty 'SID' ((New-Object System.Security.Principal.SecurityIdentifier($_.GetType().InvokeMember('ObjectSID', 'GetProperty', $Null, $_, $Null),0)).Value)
$Member | Add-Member Noteproperty 'Description' ""
$Member | Add-Member Noteproperty 'Disabled' $False
# check if the member is a group
$IsGroup = ($_.GetType().InvokeMember('Class', 'GetProperty', $Null, $_, $Null) -eq 'group')
$Member | Add-Member Noteproperty 'IsGroup' $IsGroup
$Member | Add-Member Noteproperty 'IsDomain' $IsDomain
if($IsGroup) {
$Member | Add-Member Noteproperty 'LastLogin' $Null
}
else {
try {
$Member | Add-Member Noteproperty 'LastLogin' ( $_.GetType().InvokeMember('LastLogin', 'GetProperty', $Null, $_, $Null))
}
catch {
$Member | Add-Member Noteproperty 'LastLogin' $Null
}
}
$Member | Add-Member Noteproperty 'PwdLastSet' ""
$Member | Add-Member Noteproperty 'PwdExpired' ""
$Member | Add-Member Noteproperty 'UserFlags' ""
}
else {
# repull this user object so we can ensure correct information
$LocalUser = $([ADSI] "WinNT://$AdsPath")
# translate the binary sid to a string
$Member | Add-Member Noteproperty 'SID' ((New-Object System.Security.Principal.SecurityIdentifier($LocalUser.objectSid.value,0)).Value)
$Member | Add-Member Noteproperty 'Description' ($LocalUser.Description[0])
# UAC flags of 0x2 mean the account is disabled
$Member | Add-Member Noteproperty 'Disabled' $(($LocalUser.userFlags.value -band 2) -eq 2)
# check if the member is a group
$Member | Add-Member Noteproperty 'IsGroup' ($LocalUser.SchemaClassName -like 'group')
$Member | Add-Member Noteproperty 'IsDomain' $IsDomain
if($IsGroup) {
$Member | Add-Member Noteproperty 'LastLogin' ""
}
else {
try {
$Member | Add-Member Noteproperty 'LastLogin' ( $LocalUser.LastLogin[0])
}
catch {
$Member | Add-Member Noteproperty 'LastLogin' ""
}
}
$Member | Add-Member Noteproperty 'PwdLastSet' ( (Get-Date).AddSeconds(-$LocalUser.PasswordAge[0]))
$Member | Add-Member Noteproperty 'PwdExpired' ( $LocalUser.PasswordExpired[0] -eq '1')
$Member | Add-Member Noteproperty 'UserFlags' ( $LocalUser.UserFlags[0] )
}
$Member
# if the result is a group domain object and we're recursing,
# try to resolve all the group member results
if($Recurse -and $IsDomain -and $IsGroup) {
$FQDN = $Name.split("/")[0]
$GroupName = $Name.split("/")[1].trim()
Get-NetGroupMember -GroupName $GroupName -Domain $FQDN -FullData -Recurse | ForEach-Object {
$Member = New-Object PSObject
$Member | Add-Member Noteproperty 'ComputerName' "$FQDN/$($_.GroupName)"
$MemberDN = $_.distinguishedName
# extract the FQDN from the Distinguished Name
$MemberDomain = $MemberDN.subString($MemberDN.IndexOf("DC=")) -replace 'DC=','' -replace ',','.'
if ($_.samAccountType -ne "805306368") {
$MemberIsGroup = $True
}
else {
$MemberIsGroup = $False
}
if ($_.samAccountName) {
# forest users have the samAccountName set
$MemberName = $_.samAccountName
}
else {
try {
# external trust users have a SID, so convert it
try {
$MemberName = Convert-SidToName $_.cn
}
catch {
# if there's a problem contacting the domain to resolve the SID
$MemberName = $_.cn
}
}
catch {
Write-Debug "Error resolving SID : $_"
}
}
$Member | Add-Member Noteproperty 'AccountName' "$MemberDomain/$MemberName"
$Member | Add-Member Noteproperty 'SID' $_.objectsid
$Member | Add-Member Noteproperty 'Description' $_.description
$Member | Add-Member Noteproperty 'Disabled' $False
$Member | Add-Member Noteproperty 'IsGroup' $MemberIsGroup
$Member | Add-Member Noteproperty 'IsDomain' $True
$Member | Add-Member Noteproperty 'LastLogin' ''
$Member | Add-Member Noteproperty 'PwdLastSet' $_.pwdLastSet
$Member | Add-Member Noteproperty 'PwdExpired' ''
$Member | Add-Member Noteproperty 'UserFlags' $_.userAccountControl
$Member
}
}
}
}
}
catch {
Write-Warning "[!] Error: $_"
}
} }
} }
} }
@ -7288,7 +7397,7 @@ filter Get-NetRDPSession {
# otherwise it failed - get the last error # otherwise it failed - get the last error
# error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
$Err = $Kernel32::GetLastError() $Err = $Kernel32::GetLastError()
Write-Verbuse "LastError: $Err" Write-Verbose "LastError: $Err"
} }
} }
@ -8580,7 +8689,7 @@ function Invoke-UserHunter {
} }
# kick off the threaded script block + arguments # kick off the threaded script block + arguments
Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
} }
else { else {
@ -9036,7 +9145,7 @@ function Invoke-ProcessHunter {
} }
# kick off the threaded script block + arguments # kick off the threaded script block + arguments
Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
} }
else { else {
@ -9367,7 +9476,7 @@ function Invoke-EventHunter {
} }
# kick off the threaded script block + arguments # kick off the threaded script block + arguments
Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
} }
else { else {
@ -9684,7 +9793,7 @@ function Invoke-ShareFinder {
} }
# kick off the threaded script block + arguments # kick off the threaded script block + arguments
Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
} }
else { else {
@ -10164,10 +10273,10 @@ function Invoke-FileFinder {
# kick off the threaded script block + arguments # kick off the threaded script block + arguments
if($Shares) { if($Shares) {
# pass the shares as the hosts so the threaded function code doesn't have to be hacked up # pass the shares as the hosts so the threaded function code doesn't have to be hacked up
Invoke-ThreadedFunction -ComputerName $Shares -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams Invoke-ThreadedFunction -ComputerName $Shares -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
} }
else { else {
Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
} }
} }
@ -10416,7 +10525,7 @@ function Find-LocalAdminAccess {
} }
# kick off the threaded script block + arguments # kick off the threaded script block + arguments
Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
} }
else { else {
@ -10848,6 +10957,11 @@ function Invoke-EnumerateLocalAdmin {
Switch. Search all domains in the forest for target users instead of just Switch. Search all domains in the forest for target users instead of just
a single domain. a single domain.
.PARAMETER API
Switch. Use API calls instead of the WinNT service provider. Less information,
but the results are faster.
.PARAMETER Threads .PARAMETER Threads
The maximum concurrent threads to execute. The maximum concurrent threads to execute.
@ -10917,7 +11031,10 @@ function Invoke-EnumerateLocalAdmin {
[ValidateRange(1,100)] [ValidateRange(1,100)]
[Int] [Int]
$Threads $Threads,
[Switch]
$API
) )
begin { begin {
@ -10986,7 +11103,7 @@ function Invoke-EnumerateLocalAdmin {
# script block that enumerates a server # script block that enumerates a server
$HostEnumBlock = { $HostEnumBlock = {
param($ComputerName, $Ping, $OutFile, $DomainSID, $TrustGroupsSIDs) param($ComputerName, $Ping, $OutFile, $DomainSID, $TrustGroupsSIDs, $API)
# optionally check if the server is up first # optionally check if the server is up first
$Up = $True $Up = $True
@ -10995,7 +11112,12 @@ function Invoke-EnumerateLocalAdmin {
} }
if($Up) { if($Up) {
# grab the users for the local admins on this server # grab the users for the local admins on this server
$LocalAdmins = Get-NetLocalGroup -ComputerName $ComputerName if($API) {
$LocalAdmins = Get-NetLocalGroup -ComputerName $ComputerName -API
}
else {
$LocalAdmins = Get-NetLocalGroup -ComputerName $ComputerName
}
# if we just want to return cross-trust users # if we just want to return cross-trust users
if($DomainSID -and $TrustGroupSIDS) { if($DomainSID -and $TrustGroupSIDS) {
@ -11038,8 +11160,12 @@ function Invoke-EnumerateLocalAdmin {
'TrustGroupsSIDs' = $TrustGroupsSIDs 'TrustGroupsSIDs' = $TrustGroupsSIDs
} }
# kick off the threaded script block + arguments # kick off the threaded script block + arguments
Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams if($API) {
$ScriptParams['API'] = $True
}
Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams -Threads $Threads
} }
else { else {
@ -11058,9 +11184,14 @@ function Invoke-EnumerateLocalAdmin {
# sleep for our semi-randomized interval # sleep for our semi-randomized interval
Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay)
Write-Verbose "[*] Enumerating server $Computer ($Counter of $($ComputerName.count))" Write-Verbose "[*] Enumerating server $Computer ($Counter of $($ComputerName.count))"
Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $Computer, $False, $OutFile, $DomainSID, $TrustGroupsSIDs
if($API) {
Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $Computer, $False, $OutFile, $DomainSID, $TrustGroupsSIDs, $True
}
else {
Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $Computer, $False, $OutFile, $DomainSID, $TrustGroupsSIDs
}
} }
} }
} }
@ -11512,6 +11643,7 @@ function Find-ForeignGroup {
} }
} }
function Find-ManagedSecurityGroups { function Find-ManagedSecurityGroups {
<# <#
.SYNOPSIS .SYNOPSIS
@ -11577,13 +11709,11 @@ function Find-ManagedSecurityGroups {
if ($xacl.ObjectType -eq 'bf9679c0-0de6-11d0-a285-00aa003049e2' -and $xacl.AccessControlType -eq 'Allow' -and $xacl.IdentityReference.Value.Contains($group_manager.samaccountname)) { if ($xacl.ObjectType -eq 'bf9679c0-0de6-11d0-a285-00aa003049e2' -and $xacl.AccessControlType -eq 'Allow' -and $xacl.IdentityReference.Value.Contains($group_manager.samaccountname)) {
$results_object.CanManagerWrite = $TRUE $results_object.CanManagerWrite = $TRUE
} }
$results_object $results_object
} }
} }
function Invoke-MapDomainTrust { function Invoke-MapDomainTrust {
<# <#
.SYNOPSIS .SYNOPSIS
@ -11720,11 +11850,13 @@ $FunctionDefinitions = @(
(func netapi32 NetShareEnum ([Int]) @([String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())), (func netapi32 NetShareEnum ([Int]) @([String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
(func netapi32 NetWkstaUserEnum ([Int]) @([String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())), (func netapi32 NetWkstaUserEnum ([Int]) @([String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
(func netapi32 NetSessionEnum ([Int]) @([String], [String], [String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())), (func netapi32 NetSessionEnum ([Int]) @([String], [String], [String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
(func netapi32 NetLocalGroupGetMembers ([Int]) @([String], [String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
(func advapi32 ConvertSidToStringSid ([Int]) @([IntPtr], [String].MakeByRefType())),
(func netapi32 NetApiBufferFree ([Int]) @([IntPtr])), (func netapi32 NetApiBufferFree ([Int]) @([IntPtr])),
(func advapi32 OpenSCManagerW ([IntPtr]) @([String], [String], [Int])), (func advapi32 OpenSCManagerW ([IntPtr]) @([String], [String], [Int])),
(func advapi32 CloseServiceHandle ([Int]) @([IntPtr])), (func advapi32 CloseServiceHandle ([Int]) @([IntPtr])),
(func wtsapi32 WTSOpenServerEx ([IntPtr]) @([String])), (func wtsapi32 WTSOpenServerEx ([IntPtr]) @([String])),
(func wtsapi32 WTSEnumerateSessionsEx ([Int]) @([IntPtr], [Int32].MakeByRefType(), [Int], [IntPtr].MakeByRefType(), [Int32].MakeByRefType())), (func wtsapi32 WTSEnumerateSessionsEx ([Int]) @([IntPtr], [Int32].MakeByRefType(), [Int], [IntPtr].MakeByRefType(), [Int32].MakeByRefType())),
(func wtsapi32 WTSQuerySessionInformation ([Int]) @([IntPtr], [Int], [Int], [IntPtr].MakeByRefType(), [Int32].MakeByRefType())), (func wtsapi32 WTSQuerySessionInformation ([Int]) @([IntPtr], [Int], [Int], [IntPtr].MakeByRefType(), [Int32].MakeByRefType())),
(func wtsapi32 WTSFreeMemoryEx ([Int]) @([Int32], [IntPtr], [Int32])), (func wtsapi32 WTSFreeMemoryEx ([Int]) @([Int32], [IntPtr], [Int32])),
(func wtsapi32 WTSFreeMemory ([Int]) @([IntPtr])), (func wtsapi32 WTSFreeMemory ([Int]) @([IntPtr])),
@ -11787,10 +11919,29 @@ $SESSION_INFO_10 = struct $Mod SESSION_INFO_10 @{
sesi10_idle_time = field 3 UInt32 sesi10_idle_time = field 3 UInt32
} }
# enum used by $LOCALGROUP_MEMBERS_INFO_2 below
$SID_NAME_USE = psenum $Mod SID_NAME_USE UInt16 @{
SidTypeUser = 1
SidTypeGroup = 2
SidTypeDomain = 3
SidTypeAlias = 4
SidTypeWellKnownGroup = 5
SidTypeDeletedAccount = 6
SidTypeInvalid = 7
SidTypeUnknown = 8
SidTypeComputer = 9
}
# the NetLocalGroupGetMembers result structure
$LOCALGROUP_MEMBERS_INFO_2 = struct $Mod LOCALGROUP_MEMBERS_INFO_2 @{
lgrmi2_sid = field 0 IntPtr
lgrmi2_sidusage = field 1 $SID_NAME_USE
lgrmi2_domainandname = field 2 String -MarshalAs @('LPWStr')
}
$Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32' $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32'
$Netapi32 = $Types['netapi32'] $Netapi32 = $Types['netapi32']
$Advapi32 = $Types['advapi32'] $Advapi32 = $Types['advapi32']
$Kernel32 = $Types['kernel32'] $Kernel32 = $Types['kernel32']
$Wtsapi32 = $Types['wtsapi32'] $Wtsapi32 = $Types['wtsapi32']