Skip to content

Instantly share code, notes, and snippets.

@fbogner
Last active November 4, 2024 09:46
Show Gist options
  • Select an option

  • Save fbogner/1caac69163f2fdf47baf882549693282 to your computer and use it in GitHub Desktop.

Select an option

Save fbogner/1caac69163f2fdf47baf882549693282 to your computer and use it in GitHub Desktop.
Invoke-Sharefinder-Ignore-Empty-Folder
#requires -version 2
<#
Implementation of Sharefinder that utilizes
https://github.com/mattifestation/psreflect to
stay off of disk.
By @harmj0y
#>
function New-InMemoryModule
{
<#
.SYNOPSIS
Creates an in-memory assembly and module
Author: Matthew Graeber (@mattifestation)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
.DESCRIPTION
When defining custom enums, structs, and unmanaged functions, it is
necessary to associate to an assembly module. This helper function
creates an in-memory module that can be passed to the 'enum',
'struct', and Add-Win32Type functions.
.PARAMETER ModuleName
Specifies the desired name for the in-memory assembly and module. If
ModuleName is not provided, it will default to a GUID.
.EXAMPLE
$Module = New-InMemoryModule -ModuleName Win32
#>
[OutputType([Reflection.Emit.ModuleBuilder])]
Param
(
[Parameter(Position = 0)]
[ValidateNotNullOrEmpty()]
[String]
$ModuleName = [Guid]::NewGuid().ToString()
)
$DynAssembly = New-Object Reflection.AssemblyName($ModuleName)
$Domain = [AppDomain]::CurrentDomain
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, 'Run')
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule($ModuleName, $False)
return $ModuleBuilder
}
# A helper function used to reduce typing while defining function
# prototypes for Add-Win32Type.
# Author: Matthew Graeber (@mattifestation)
function func
{
Param
(
[Parameter(Position = 0, Mandatory = $True)]
[String]
$DllName,
[Parameter(Position = 1, Mandatory = $True)]
[string]
$FunctionName,
[Parameter(Position = 2, Mandatory = $True)]
[Type]
$ReturnType,
[Parameter(Position = 3)]
[Type[]]
$ParameterTypes,
[Parameter(Position = 4)]
[Runtime.InteropServices.CallingConvention]
$NativeCallingConvention,
[Parameter(Position = 5)]
[Runtime.InteropServices.CharSet]
$Charset,
[Switch]
$SetLastError
)
$Properties = @{
DllName = $DllName
FunctionName = $FunctionName
ReturnType = $ReturnType
}
if ($ParameterTypes) { $Properties['ParameterTypes'] = $ParameterTypes }
if ($NativeCallingConvention) { $Properties['NativeCallingConvention'] = $NativeCallingConvention }
if ($Charset) { $Properties['Charset'] = $Charset }
if ($SetLastError) { $Properties['SetLastError'] = $SetLastError }
New-Object PSObject -Property $Properties
}
function Add-Win32Type
{
<#
.SYNOPSIS
Creates a .NET type for an unmanaged Win32 function.
Author: Matthew Graeber (@mattifestation)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: func
.DESCRIPTION
Add-Win32Type enables you to easily interact with unmanaged (i.e.
Win32 unmanaged) functions in PowerShell. After providing
Add-Win32Type with a function signature, a .NET type is created
using reflection (i.e. csc.exe is never called like with Add-Type).
The 'func' helper function can be used to reduce typing when defining
multiple function definitions.
.PARAMETER DllName
The name of the DLL.
.PARAMETER FunctionName
The name of the target function.
.PARAMETER ReturnType
The return type of the function.
.PARAMETER ParameterTypes
The function parameters.
.PARAMETER NativeCallingConvention
Specifies the native calling convention of the function. Defaults to
stdcall.
.PARAMETER Charset
If you need to explicitly call an 'A' or 'W' Win32 function, you can
specify the character set.
.PARAMETER SetLastError
Indicates whether the callee calls the SetLastError Win32 API
function before returning from the attributed method.
.PARAMETER Module
The in-memory module that will host the functions. Use
New-InMemoryModule to define an in-memory module.
.PARAMETER Namespace
An optional namespace to prepend to the type. Add-Win32Type defaults
to a namespace consisting only of the name of the DLL.
.EXAMPLE
$Mod = New-InMemoryModule -ModuleName Win32
$FunctionDefinitions = @(
(func kernel32 GetProcAddress ([IntPtr]) @([IntPtr], [String]) -Charset Ansi -SetLastError),
(func kernel32 GetModuleHandle ([Intptr]) @([String]) -SetLastError),
(func ntdll RtlGetCurrentPeb ([IntPtr]) @())
)
$Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32'
$Kernel32 = $Types['kernel32']
$Ntdll = $Types['ntdll']
$Ntdll::RtlGetCurrentPeb()
$ntdllbase = $Kernel32::GetModuleHandle('ntdll')
$Kernel32::GetProcAddress($ntdllbase, 'RtlGetCurrentPeb')
.NOTES
Inspired by Lee Holmes' Invoke-WindowsApi http://poshcode.org/2189
When defining multiple function prototypes, it is ideal to provide
Add-Win32Type with an array of function signatures. That way, they
are all incorporated into the same in-memory module.
#>
[OutputType([Hashtable])]
Param(
[Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
[String]
$DllName,
[Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
[String]
$FunctionName,
[Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
[Type]
$ReturnType,
[Parameter(ValueFromPipelineByPropertyName = $True)]
[Type[]]
$ParameterTypes,
[Parameter(ValueFromPipelineByPropertyName = $True)]
[Runtime.InteropServices.CallingConvention]
$NativeCallingConvention = [Runtime.InteropServices.CallingConvention]::StdCall,
[Parameter(ValueFromPipelineByPropertyName = $True)]
[Runtime.InteropServices.CharSet]
$Charset = [Runtime.InteropServices.CharSet]::Auto,
[Parameter(ValueFromPipelineByPropertyName = $True)]
[Switch]
$SetLastError,
[Parameter(Mandatory = $True)]
[Reflection.Emit.ModuleBuilder]
$Module,
[ValidateNotNull()]
[String]
$Namespace = ''
)
BEGIN
{
$TypeHash = @{}
}
PROCESS
{
# Define one type for each DLL
if (!$TypeHash.ContainsKey($DllName))
{
if ($Namespace)
{
$TypeHash[$DllName] = $Module.DefineType("$Namespace.$DllName", 'Public,BeforeFieldInit')
}
else
{
$TypeHash[$DllName] = $Module.DefineType($DllName, 'Public,BeforeFieldInit')
}
}
$Method = $TypeHash[$DllName].DefineMethod(
$FunctionName,
'Public,Static,PinvokeImpl',
$ReturnType,
$ParameterTypes)
# Make each ByRef parameter an Out parameter
$i = 1
foreach($Parameter in $ParameterTypes)
{
if ($Parameter.IsByRef)
{
[void] $Method.DefineParameter($i, 'Out', $null)
}
$i++
}
$DllImport = [Runtime.InteropServices.DllImportAttribute]
$SetLastErrorField = $DllImport.GetField('SetLastError')
$CallingConventionField = $DllImport.GetField('CallingConvention')
$CharsetField = $DllImport.GetField('CharSet')
if ($SetLastError) { $SLEValue = $True } else { $SLEValue = $False }
# Equivalent to C# version of [DllImport(DllName)]
$Constructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor([String])
$DllImportAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($Constructor,
$DllName, [Reflection.PropertyInfo[]] @(), [Object[]] @(),
[Reflection.FieldInfo[]] @($SetLastErrorField, $CallingConventionField, $CharsetField),
[Object[]] @($SLEValue, ([Runtime.InteropServices.CallingConvention] $NativeCallingConvention), ([Runtime.InteropServices.CharSet] $Charset)))
$Method.SetCustomAttribute($DllImportAttribute)
}
END
{
$ReturnTypes = @{}
foreach ($Key in $TypeHash.Keys)
{
$Type = $TypeHash[$Key].CreateType()
$ReturnTypes[$Key] = $Type
}
return $ReturnTypes
}
}
# A helper function used to reduce typing while defining struct
# fields.
# Author: Matthew Graeber (@mattifestation)
function field
{
Param
(
[Parameter(Position = 0, Mandatory = $True)]
[UInt16]
$Position,
[Parameter(Position = 1, Mandatory = $True)]
[Type]
$Type,
[Parameter(Position = 2)]
[UInt16]
$Offset,
[Object[]]
$MarshalAs
)
@{
Position = $Position
Type = $Type -as [Type]
Offset = $Offset
MarshalAs = $MarshalAs
}
}
# Author: Matthew Graeber (@mattifestation)
function struct
{
<#
.SYNOPSIS
Creates an in-memory struct for use in your PowerShell session.
Author: Matthew Graeber (@mattifestation)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: field
.DESCRIPTION
The 'struct' function facilitates the creation of structs entirely in
memory using as close to a "C style" as PowerShell will allow. Struct
fields are specified using a hashtable where each field of the struct
is comprosed of the order in which it should be defined, its .NET
type, and optionally, its offset and special marshaling attributes.
One of the features of 'struct' is that after your struct is defined,
it will come with a built-in GetSize method as well as an explicit
converter so that you can easily cast an IntPtr to the struct without
relying upon calling SizeOf and/or PtrToStructure in the Marshal
class.
.PARAMETER Module
The in-memory module that will host the struct. Use
New-InMemoryModule to define an in-memory module.
.PARAMETER FullName
The fully-qualified name of the struct.
.PARAMETER StructFields
A hashtable of fields. Use the 'field' helper function to ease
defining each field.
.PARAMETER PackingSize
Specifies the memory alignment of fields.
.PARAMETER ExplicitLayout
Indicates that an explicit offset for each field will be specified.
.EXAMPLE
$Mod = New-InMemoryModule -ModuleName Win32
$ImageDosSignature = enum $Mod PE.IMAGE_DOS_SIGNATURE UInt16 @{
DOS_SIGNATURE = 0x5A4D
OS2_SIGNATURE = 0x454E
OS2_SIGNATURE_LE = 0x454C
VXD_SIGNATURE = 0x454C
}
$ImageDosHeader = struct $Mod PE.IMAGE_DOS_HEADER @{
e_magic = field 0 $ImageDosSignature
e_cblp = field 1 UInt16
e_cp = field 2 UInt16
e_crlc = field 3 UInt16
e_cparhdr = field 4 UInt16
e_minalloc = field 5 UInt16
e_maxalloc = field 6 UInt16
e_ss = field 7 UInt16
e_sp = field 8 UInt16
e_csum = field 9 UInt16
e_ip = field 10 UInt16
e_cs = field 11 UInt16
e_lfarlc = field 12 UInt16
e_ovno = field 13 UInt16
e_res = field 14 UInt16[] -MarshalAs @('ByValArray', 4)
e_oemid = field 15 UInt16
e_oeminfo = field 16 UInt16
e_res2 = field 17 UInt16[] -MarshalAs @('ByValArray', 10)
e_lfanew = field 18 Int32
}
# Example of using an explicit layout in order to create a union.
$TestUnion = struct $Mod TestUnion @{
field1 = field 0 UInt32 0
field2 = field 1 IntPtr 0
} -ExplicitLayout
.NOTES
PowerShell purists may disagree with the naming of this function but
again, this was developed in such a way so as to emulate a "C style"
definition as closely as possible. Sorry, I'm not going to name it
New-Struct. :P
#>
[OutputType([Type])]
Param
(
[Parameter(Position = 1, Mandatory = $True)]
[Reflection.Emit.ModuleBuilder]
$Module,
[Parameter(Position = 2, Mandatory = $True)]
[ValidateNotNullOrEmpty()]
[String]
$FullName,
[Parameter(Position = 3, Mandatory = $True)]
[ValidateNotNullOrEmpty()]
[Hashtable]
$StructFields,
[Reflection.Emit.PackingSize]
$PackingSize = [Reflection.Emit.PackingSize]::Unspecified,
[Switch]
$ExplicitLayout
)
[Reflection.TypeAttributes] $StructAttributes = 'AnsiClass,
Class,
Public,
Sealed,
BeforeFieldInit'
if ($ExplicitLayout)
{
$StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::ExplicitLayout
}
else
{
$StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::SequentialLayout
}
$StructBuilder = $Module.DefineType($FullName, $StructAttributes, [ValueType], $PackingSize)
$ConstructorInfo = [Runtime.InteropServices.MarshalAsAttribute].GetConstructors()[0]
$SizeConst = @([Runtime.InteropServices.MarshalAsAttribute].GetField('SizeConst'))
$Fields = New-Object Hashtable[]($StructFields.Count)
# Sort each field according to the orders specified
# Unfortunately, PSv2 doesn't have the luxury of the
# hashtable [Ordered] accelerator.
foreach ($Field in $StructFields.Keys)
{
$Index = $StructFields[$Field]['Position']
$Fields[$Index] = @{FieldName = $Field; Properties = $StructFields[$Field]}
}
foreach ($Field in $Fields)
{
$FieldName = $Field['FieldName']
$FieldProp = $Field['Properties']
$Offset = $FieldProp['Offset']
$Type = $FieldProp['Type']
$MarshalAs = $FieldProp['MarshalAs']
$NewField = $StructBuilder.DefineField($FieldName, $Type, 'Public')
if ($MarshalAs)
{
$UnmanagedType = $MarshalAs[0] -as ([Runtime.InteropServices.UnmanagedType])
if ($MarshalAs[1])
{
$Size = $MarshalAs[1]
$AttribBuilder = New-Object Reflection.Emit.CustomAttributeBuilder($ConstructorInfo,
$UnmanagedType, $SizeConst, @($Size))
}
else
{
$AttribBuilder = New-Object Reflection.Emit.CustomAttributeBuilder($ConstructorInfo, [Object[]] @($UnmanagedType))
}
$NewField.SetCustomAttribute($AttribBuilder)
}
if ($ExplicitLayout) { $NewField.SetOffset($Offset) }
}
# Make the struct aware of its own size.
# No more having to call [Runtime.InteropServices.Marshal]::SizeOf!
$SizeMethod = $StructBuilder.DefineMethod('GetSize',
'Public, Static',
[Int],
[Type[]] @())
$ILGenerator = $SizeMethod.GetILGenerator()
# Thanks for the help, Jason Shirk!
$ILGenerator.Emit([Reflection.Emit.OpCodes]::Ldtoken, $StructBuilder)
$ILGenerator.Emit([Reflection.Emit.OpCodes]::Call,
[Type].GetMethod('GetTypeFromHandle'))
$ILGenerator.Emit([Reflection.Emit.OpCodes]::Call,
[Runtime.InteropServices.Marshal].GetMethod('SizeOf', [Type[]] @([Type])))
$ILGenerator.Emit([Reflection.Emit.OpCodes]::Ret)
# Allow for explicit casting from an IntPtr
# No more having to call [Runtime.InteropServices.Marshal]::PtrToStructure!
$ImplicitConverter = $StructBuilder.DefineMethod('op_Implicit',
'PrivateScope, Public, Static, HideBySig, SpecialName',
$StructBuilder,
[Type[]] @([IntPtr]))
$ILGenerator2 = $ImplicitConverter.GetILGenerator()
$ILGenerator2.Emit([Reflection.Emit.OpCodes]::Nop)
$ILGenerator2.Emit([Reflection.Emit.OpCodes]::Ldarg_0)
$ILGenerator2.Emit([Reflection.Emit.OpCodes]::Ldtoken, $StructBuilder)
$ILGenerator2.Emit([Reflection.Emit.OpCodes]::Call,
[Type].GetMethod('GetTypeFromHandle'))
$ILGenerator2.Emit([Reflection.Emit.OpCodes]::Call,
[Runtime.InteropServices.Marshal].GetMethod('PtrToStructure', [Type[]] @([IntPtr], [Type])))
$ILGenerator2.Emit([Reflection.Emit.OpCodes]::Unbox_Any, $StructBuilder)
$ILGenerator2.Emit([Reflection.Emit.OpCodes]::Ret)
$StructBuilder.CreateType()
}
function Test-Server {
<#
.SYNOPSIS
Tests a connection to a remote server.
.DESCRIPTION
This function uses either ping (test-connection) or RPC
(through WMI) to test connectivity to a remote server.
.PARAMETER Server
The hostname/IP to test connectivity to.
.OUTPUTS
$True/$False
.EXAMPLE
> Test-Server -Server WINDOWS7
Tests ping connectivity to the WINDOWS7 server.
.EXAMPLE
> Test-Server -RPC -Server WINDOWS7
Tests RPC connectivity to the WINDOWS7 server.
.LINK
http://gallery.technet.microsoft.com/scriptcenter/Enhanced-Remote-Server-84c63560
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $True)]
[String]
$Server,
[Switch]
$RPC
)
if ($RPC){
$WMIParameters = @{
namespace = 'root\cimv2'
Class = 'win32_ComputerSystem'
ComputerName = $Name
ErrorAction = 'Stop'
}
if ($Credential -ne $null)
{
$WMIParameters.Credential = $Credential
}
try
{
Get-WmiObject @WMIParameters
}
catch {
Write-Verbose -Message 'Could not connect via WMI'
}
}
# otherwise, use ping
else{
Test-Connection -ComputerName $Server -count 1 -Quiet
}
}
function Get-ShuffledArray {
<#
.SYNOPSIS
Returns a randomly-shuffled version of a passed array.
.DESCRIPTION
This function takes an array and returns a randomly-shuffled
version.
.PARAMETER Array
The passed array to shuffle.
.OUTPUTS
System.Array. The passed array but shuffled.
.EXAMPLE
> $shuffled = Get-ShuffledArray $array
Get a shuffled version of $array.
.LINK
http://sqlchow.wordpress.com/2013/03/04/shuffle-the-deck-using-powershell/
#>
[CmdletBinding()]
param(
[Array]$Array
)
Begin{}
Process{
$len = $Array.Length
while($len){
$i = Get-Random ($len --)
$tmp = $Array[$len]
$Array[$len] = $Array[$i]
$Array[$i] = $tmp
}
$Array;
}
}
function Get-NetCurrentUser {
<#
.SYNOPSIS
Gets the name of the current user.
.DESCRIPTION
This function returns the username of the current user context,
with the domain appended if appropriate.
.OUTPUTS
System.String. The current username.
.EXAMPLE
> Get-NetCurrentUser
Return the current user.
#>
[System.Security.Principal.WindowsIdentity]::GetCurrent().Name
}
function Get-NetDomain {
<#
.SYNOPSIS
Returns the name of the current user's domain.
.DESCRIPTION
This function utilizes ADSI (Active Directory Service Interface) to
get the currect domain root and return its distinguished name.
It then formats the name into a single string.
.PARAMETER Base
Just return the base of the current domain (i.e. no .com)
.OUTPUTS
System.String. The full domain name.
.EXAMPLE
> Get-NetDomain
Return the current domain.
.EXAMPLE
> Get-NetDomain -base
Return just the base of the current domain.
.LINK
http://social.technet.microsoft.com/Forums/scriptcenter/en-US/0c5b3f83-e528-4d49-92a4-dee31f4b481c/finding-the-dn-of-the-the-domain-without-admodule-in-powershell?forum=ITCG
#>
[CmdletBinding()]
param(
[Switch]
$Base
)
# just get the base of the domain name
if ($Base){
$temp = [string] ([adsi]'').distinguishedname -replace 'DC=','' -replace ',','.'
$parts = $temp.split('.')
$parts[0..($parts.length-2)] -join '.'
}
else{
([adsi]'').distinguishedname -replace 'DC=','' -replace ',','.'
}
}
function Get-NetComputers {
<#
.SYNOPSIS
Gets an array of all current computers objects in a domain.
.DESCRIPTION
This function utilizes adsisearcher to query the current AD context
for current computer objects. Based off of Carlos Perez's Audit.psm1
script in Posh-SecMod (link below).
.PARAMETER HostName
Return computers with a specific name, wildcards accepted.
.PARAMETER SPN
Return computers with a specific service principal name, wildcards accepted.
.PARAMETER OperatingSystem
Return computers with a specific operating system, wildcards accepted.
.PARAMETER ServicePack
Return computers with a specific service pack, wildcards accepted.
.PARAMETER FullData
Return full user computer objects instead of just system names (the default).
.PARAMETER Domain
The domain to query for computers.
.OUTPUTS
System.Array. An array of found system objects.
.EXAMPLE
> Get-NetComputers
Returns the current computers in current domain.
.EXAMPLE
> Get-NetComputers -SPN mssql*
Returns all MS SQL servers on the domain.
.EXAMPLE
> Get-NetComputers -Domain testing
Returns the current computers in 'testing' domain.
> Get-NetComputers -Domain testing -FullData
Returns full computer objects in the 'testing' domain.
.LINK
https://github.com/darkoperator/Posh-SecMod/blob/master/Audit/Audit.psm1
#>
[CmdletBinding()]
Param (
[string]
$HostName = '*',
[string]
$SPN = '*',
[string]
$OperatingSystem = '*',
[string]
$ServicePack = '*',
[Switch]
$FullData,
[string]
$Domain
)
# if a domain is specified, try to grab that domain
if ($Domain){
# try to grab the primary DC for the current domain
try{
$PrimaryDC = ([Array](Get-NetDomainControllers))[0].Name
}
catch{
$PrimaryDC = $Null
}
try {
# reference - http://blogs.msdn.com/b/javaller/archive/2013/07/29/searching-across-active-directory-domains-in-powershell.aspx
$dn = "DC=$($Domain.Replace('.', ',DC='))"
# if we could grab the primary DC for the current domain, use that for the query
if($PrimaryDC){
$CompSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$PrimaryDC/$dn")
}
else{
# otherwise try to connect to the DC for the target domain
$CompSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$dn")
}
# create the searcher object with our specific filters
if ($ServicePack -ne '*'){
$CompSearcher.filter="(&(objectClass=Computer)(dnshostname=$HostName)(operatingsystem=$OperatingSystem)(operatingsystemservicepack=$ServicePack)(servicePrincipalName=$SPN))"
}
else{
# server 2012 peculiarity- remove any mention to service pack
$CompSearcher.filter="(&(objectClass=Computer)(dnshostname=$HostName)(operatingsystem=$OperatingSystem)(servicePrincipalName=$SPN))"
}
}
catch{
Write-Warning "The specified domain $Domain does not exist, could not be contacted, or there isn't an existing trust."
}
}
else{
# otherwise, use the current domain
if ($ServicePack -ne '*'){
$CompSearcher = [adsisearcher]"(&(objectClass=Computer)(dnshostname=$HostName)(operatingsystem=$OperatingSystem)(operatingsystemservicepack=$ServicePack)(servicePrincipalName=$SPN))"
}
else{
# server 2012 peculiarity- remove any mention to service pack
$CompSearcher = [adsisearcher]"(&(objectClass=Computer)(dnshostname=$HostName)(operatingsystem=$OperatingSystem)(servicePrincipalName=$SPN))"
}
}
if ($CompSearcher){
# eliminate that pesky 1000 system limit
$CompSearcher.PageSize = 200
$CompSearcher.FindAll() | ForEach-Object {
# return full data objects
if ($FullData){
$_.properties
}
else{
# otherwise we're just returning the DNS host name
$_.properties.dnshostname
}
}
}
}
function Get-NetShare {
<#
.SYNOPSIS
Gets share information for a specified server.
.DESCRIPTION
This function will execute the NetShareEnum Win32API call to query
a given host for open shares. This is a replacement for
"net share \\hostname"
.PARAMETER HostName
The hostname to query for shares.
.OUTPUTS
SHARE_INFO_1 structure. A representation of the SHARE_INFO_1
result structure which includes the name and note for each share.
.EXAMPLE
> Get-NetShare
Returns active shares on the local host.
.EXAMPLE
> Get-NetShare -HostName sqlserver
Returns active shares on the 'sqlserver' host
#>
[CmdletBinding()]
param(
[string]
$HostName = 'localhost'
)
If ($PSBoundParameters['Debug']) {
$DebugPreference = 'Continue'
}
# arguments for NetShareEnum
$QueryLevel = 1
$ptrInfo = [IntPtr]::Zero
$EntriesRead = 0
$TotalRead = 0
$ResumeHandle = 0
# get the share information
$Result = $Netapi32::NetShareEnum($HostName, $QueryLevel,[ref]$ptrInfo,-1,[ref]$EntriesRead,[ref]$TotalRead,[ref]$ResumeHandle)
# Locate the offset of the initial intPtr
$offset = $ptrInfo.ToInt64()
Write-Debug "Get-NetShare result: $Result"
# 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 = $SHARE_INFO_1::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 $SHARE_INFO_1
# return all the sections of the structure
$Info | Select-Object *
$offset = $newintptr.ToInt64()
$offset += $increment
}
# free up the result buffer
$Netapi32::NetApiBufferFree($ptrInfo) | Out-Null
}
else
{
switch ($Result) {
(5) {Write-Debug 'The user does not have access to the requested information.'}
(124) {Write-Debug 'The value specified for the level parameter is not valid.'}
(87) {Write-Debug 'The specified parameter is not valid.'}
(234) {Write-Debug 'More entries are available. Specify a large enough buffer to receive all entries.'}
(8) {Write-Debug 'Insufficient memory is available.'}
(2312) {Write-Debug 'A session does not exist with the computer name.'}
(2351) {Write-Debug 'The computer name is not valid.'}
(2221) {Write-Debug 'Username not found.'}
(53) {Write-Debug 'Hostname could not be found'}
}
}
}
function Invoke-ShareFinder {
<#
.SYNOPSIS
Finds (non-standard) shares on machines in the domain.
Author: @harmj0y
.DESCRIPTION
This function finds the local domain name for a host using Get-NetDomain,
queries the domain for all active machines with Get-NetComputers, then for
each server it lists of active shares with Get-NetShare. Non-standard shares
can be filtered out with -Exclude* flags.
.PARAMETER HostList
List of hostnames/IPs to search.
.PARAMETER ExcludeStandard
Exclude standard shares from display (C$, IPC$, print$ etc.)
.PARAMETER ExcludePrint
Exclude the print$ share
.PARAMETER ExcludeIPC
Exclude the IPC$ share
.PARAMETER CheckShareAccess
Only display found shares that the local user has access to.
.PARAMETER CheckAdmin
Only display ADMIN$ shares the local user has access to.
.PARAMETER Ping
Ping each host to ensure it's up before enumerating.
.PARAMETER NoPing
Ping each host to ensure it's up before enumerating.
.PARAMETER NoPing
Don't ping each host to ensure it's up before enumerating.
.PARAMETER Delay
Delay between enumerating hosts, defaults to 0
.PARAMETER Jitter
Jitter for the host delay, defaults to +/- 0.3
.PARAMETER Domain
Domain to query for machines.
.EXAMPLE
> Invoke-ShareFinder
Find shares on the domain.
.EXAMPLE
> Invoke-ShareFinder -ExcludeStandard
Find non-standard shares on the domain.
.EXAMPLE
> Invoke-ShareFinder -Delay 60
Find shares on the domain with a 60 second (+/- *.3)
randomized delay between touching each host.
.EXAMPLE
> Invoke-ShareFinder -HostList hosts.txt
Find shares for machines in the specified hostlist.
.LINK
http://blog.harmj0y.net
#>
[CmdletBinding()]
param(
[string]
$HostList,
[Switch]
$ExcludeStandard,
[Switch]
$ExcludePrint,
[Switch]
$ExcludeIPC,
[Switch]
$Ping,
[Switch]
$NoPing,
[Switch]
$CheckShareAccess,
[Switch]
$CheckAdmin,
[UInt32]
$Delay = 0,
[double]
$Jitter = .3,
[String]
$Domain
)
If ($PSBoundParameters['Debug']) {
$DebugPreference = 'Continue'
}
# figure out the shares we want to ignore
[String[]] $excludedShares = @('')
if ($ExcludePrint){
$excludedShares = $excludedShares + "PRINT$"
}
if ($ExcludeIPC){
$excludedShares = $excludedShares + "IPC$"
}
if ($ExcludeStandard){
$excludedShares = @('', "ADMIN$", "IPC$", "C$", "PRINT$")
}
# random object for delay
$randNo = New-Object System.Random
# get the current user
$CurrentUser = Get-NetCurrentUser
# get the target domain
if($Domain){
$targetDomain = $Domain
}
else{
# use the local domain
$targetDomain = Get-NetDomain
}
Write-Verbose "[*] Running ShareFinder on domain $targetDomain with delay of $Delay"
$servers = @()
# if we're using a host list, read the targets in and add them to the target list
if($HostList){
if (Test-Path -Path $HostList){
$servers = Get-Content -Path $HostList
}
else {
Write-Warning "`r`n[!] Input file '$HostList' doesn't exist!`r`n"
return $null
}
}
else{
# otherwise, query the domain for target servers
Write-Verbose "[*] Querying domain $targetDomain for hosts...`r`n"
$servers = Get-NetComputers -Domain $targetDomain
}
# randomize the server list
$servers = Get-ShuffledArray $servers
if (($servers -eq $null) -or ($servers.Count -eq 0)){
Write-Warning "`r`n[!] No hosts found!"
return $null
}
else{
# return/output the current status lines
$counter = 0
foreach ($server in $servers){
$counter = $counter + 1
Write-Verbose "[*] Enumerating server $server ($counter of $($servers.count))"
if ($server -ne ''){
# sleep for our semi-randomized interval
Start-Sleep -Seconds $randNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay)
# optionally check if the server is up first
$up = $true
if(-not $NoPing){
$up = Test-Server -Server $server
}
if($up){
# get the shares for this host and display what we find
$shares = Get-NetShare -HostName $server
foreach ($share in $shares) {
Write-Debug "[*] Server share: $share"
$netname = $share.shi1_netname
$remark = $share.shi1_remark
$path = '\\'+$server+'\'+$netname
# make sure we get a real share name back
if (($netname) -and ($netname.trim() -ne '')){
# if we're just checking for access to ADMIN$
if($CheckAdmin){
if($netname.ToUpper() -eq "ADMIN$"){
try{
$f=[IO.Directory]::GetFiles($path)
"\\$server\$netname `t- $remark"
}
catch {}
}
}
# skip this share if it's in the exclude list
elseif ($excludedShares -notcontains $netname.ToUpper()){
# see if we want to check access to this share
if($CheckShareAccess){
# check if the user has access to this path
try{
$f=[IO.Directory]::EnumerateFileSystemEntries($path).GetEnumerator().MoveNext()
# If the folder is empty we ignore the share
if ($f -eq $false) {
throw "Folder is empty - ignoring"
}
"\\$server\$netname `t- $remark"
}
catch {}
}
else{
"\\$server\$netname `t- $remark"
}
}
}
}
}
}
}
}
}
function Invoke-ShareFinderThreaded {
<#
.SYNOPSIS
Finds (non-standard) shares on machines in the domain.
Threaded version of Invoke-ShareFinder.
Author: @harmj0y
.DESCRIPTION
This function finds the local domain name for a host using Get-NetDomain,
queries the domain for all active machines with Get-NetComputers, then for
each server it lists of active shares with Get-NetShare. Non-standard shares
can be filtered out with -Exclude* flags.
Threaded version of Invoke-ShareFinder.
.PARAMETER HostList
List of hostnames/IPs to search.
.PARAMETER ExcludedShares
Shares to exclude from output, wildcards accepted (i.e. IPC*)
.PARAMETER CheckShareAccess
Only display found shares that the local user has access to.
.PARAMETER CheckAdmin
Only display ADMIN$ shares the local user has access to.
.PARAMETER NoPing
Don't ping each host to ensure it's up before enumerating.
.PARAMETER Domain
Domain to query for machines.
.PARAMETER MaxThreads
The maximum concurrent threads to execute.
.EXAMPLE
> Invoke-ShareFinder
Find shares on the domain.
.EXAMPLE
> Invoke-ShareFinder -ExcludedShares IPC$,PRINT$
Find shares on the domain excluding IPC$ and PRINT$
.EXAMPLE
> Invoke-ShareFinder -HostList hosts.txt
Find shares for machines in the specified hostlist.
.LINK
http://blog.harmj0y.net
#>
[CmdletBinding()]
param(
[string]
$HostList,
[string[]]
$ExcludedShares = @(),
[Switch]
$NoPing,
[Switch]
$CheckShareAccess,
[Switch]
$CheckAdmin,
[String]
$Domain,
[Int]
$MaxThreads = 10
)
If ($PSBoundParameters['Debug']) {
$DebugPreference = 'Continue'
}
# get the current user
$CurrentUser = Get-NetCurrentUser
# get the target domain
if($Domain){
$targetDomain = $Domain
}
else{
# use the local domain
$targetDomain = Get-NetDomain
}
Write-Verbose "[*] Running Invoke-ShareFinderThreaded on domain $targetDomain with delay of $Delay"
$servers = @()
# if we're using a host list, read the targets in and add them to the target list
if($HostList){
if (Test-Path -Path $HostList){
$servers = Get-Content -Path $HostList
}
else {
Write-Warning "`r`n[!] Input file '$HostList' doesn't exist!`r`n"
return $null
}
}
else{
# otherwise, query the domain for target servers
Write-Verbose "[*] Querying domain $targetDomain for hosts...`r`n"
$servers = Get-NetComputers -Domain $targetDomain
}
# randomize the server list
$servers = Get-ShuffledArray $servers
if (($servers -eq $null) -or ($servers.Count -eq 0)){
Write-Warning "`r`n[!] No hosts found!"
return $null
}
# script block that eunmerates a server
# this is called by the multi-threading code later
$EnumServerBlock = {
param($Server, $Ping, $CheckShareAccess, $ExcludedShares, $CheckAdmin)
# optionally check if the server is up first
$up = $true
if($Ping){
$up = Test-Server -Server $Server
}
if($up){
# get the shares for this host and check what we find
$shares = Get-NetShare -HostName $Server
foreach ($share in $shares) {
Write-Debug "[*] Server share: $share"
$netname = $share.shi1_netname
$remark = $share.shi1_remark
$path = '\\'+$server+'\'+$netname
# make sure we get a real share name back
if (($netname) -and ($netname.trim() -ne '')){
# if we're just checking for access to ADMIN$
if($CheckAdmin){
if($netname.ToUpper() -eq "ADMIN$"){
try{
$f=[IO.Directory]::GetFiles($path)
"\\$server\$netname `t- $remark"
}
catch {}
}
}
# skip this share if it's in the exclude list
elseif ($excludedShares -notcontains $netname.ToUpper()){
# see if we want to check access to this share
if($CheckShareAccess){
# check if the user has access to this path
try{
$f=[IO.Directory]::GetFiles($path)
"\\$server\$netname `t- $remark"
}
catch {}
}
else{
"\\$server\$netname `t- $remark"
}
}
}
}
}
}
# Adapted from:
# http://powershell.org/wp/forums/topic/invpke-parallel-need-help-to-clone-the-current-runspace/
$sessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
$sessionState.ApartmentState = [System.Threading.Thread]::CurrentThread.GetApartmentState()
# grab all the current variables for this runspace
$MyVars = Get-Variable -Scope 1
# these Variables are added by Runspace.Open() Method and produce Stop errors if you add them twice
$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")
# Add Variables from Parent Scope (current runspace) into the InitialSessionState
ForEach($Var in $MyVars) {
If($VorbiddenVars -notcontains $Var.Name) {
$sessionstate.Variables.Add((New-Object -TypeName System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList $Var.name,$Var.Value,$Var.description,$Var.options,$Var.attributes))
}
}
# Add Functions from current runspace to the InitialSessionState
ForEach($Function in (Get-ChildItem Function:)) {
$sessionState.Commands.Add((New-Object -TypeName System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList $Function.Name, $Function.Definition))
}
# threading adapted from
# https://github.com/darkoperator/Posh-SecMod/blob/master/Discovery/Discovery.psm1#L407
# Thanks Carlos!
$counter = 0
# create a pool of maxThread runspaces
$pool = [runspacefactory]::CreateRunspacePool(1, $MaxThreads, $sessionState, $host)
$pool.Open()
$jobs = @()
$ps = @()
$wait = @()
$serverCount = $servers.count
"`r`n[*] Enumerating $serverCount servers..."
foreach ($server in $servers){
# make sure we get a server name
if ($server -ne ''){
Write-Verbose "[*] Enumerating server $server ($counter of $($servers.count))"
While ($($pool.GetAvailableRunspaces()) -le 0) {
Start-Sleep -milliseconds 500
}
# create a "powershell pipeline runner"
$ps += [powershell]::create()
$ps[$counter].runspacepool = $pool
# add the script block + arguments
[void]$ps[$counter].AddScript($EnumServerBlock).AddParameter('Server', $server).AddParameter('Ping', -not $NoPing).AddParameter('CheckShareAccess', $CheckShareAccess).AddParameter('ExcludedShares', $ExcludedShares).AddParameter('CheckAdmin', $CheckAdmin)
# start job
$jobs += $ps[$counter].BeginInvoke();
# store wait handles for WaitForAll call
$wait += $jobs[$counter].AsyncWaitHandle
}
$counter = $counter + 1
}
Write-Verbose "Waiting for scanning threads to finish..."
$waitTimeout = Get-Date
while ($($jobs | ? {$_.IsCompleted -eq $false}).count -gt 0 -or $($($(Get-Date) - $waitTimeout).totalSeconds) -gt 60) {
Start-Sleep -milliseconds 500
}
# end async call
for ($y = 0; $y -lt $counter; $y++) {
try {
# complete async job
$ps[$y].EndInvoke($jobs[$y])
} catch {
Write-Warning "error: $_"
}
finally {
$ps[$y].Dispose()
}
}
$pool.Dispose()
}
$Mod = New-InMemoryModule -ModuleName Win32
# all of the Win32 API functions we need
$FunctionDefinitions = @(
(func netapi32 NetShareEnum ([Int]) @([string], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
(func netapi32 NetApiBufferFree ([Int]) @([IntPtr]))
)
# the NetShareEnum result structure
$SHARE_INFO_1 = struct $Mod SHARE_INFO_1 @{
shi1_netname = field 0 String -MarshalAs @('LPWStr')
shi1_type = field 1 UInt32
shi1_remark = field 2 String -MarshalAs @('LPWStr')
}
$Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32'
$Netapi32 = $Types['netapi32']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment