DirectoryService/Get-DSComputer.ps1

<#
.SYNOPSIS
     Get computer objects in a given directory service.
.DESCRIPTION
     Get computer objects in a given directory service.
.EXAMPLE
    C:\PS> Get-DSComputer -OperatingSystem "*windows 7*","*Windows 10*"
    Find all computers in the current domain that are running Windows 7 or Windows 10.
.EXAMPLE
    C:\PS> Get-DSComputer -LogOnBefore (Get-Date).AddMonths(-3)
    Find all computers that have not logged on to the domain in the last 3 months.
.EXAMPLE
    C:\PS> Get-DSComputer -SPN '*TERMSRV*'
    Find all computers with a service Principal Name.for TERMSRV. This machine are offering the Remote Desktop service.
#>

function Get-DSComputer {
    [CmdletBinding(DefaultParameterSetName='Current')]
    param(
        # Domain controller.
        [Parameter(ParameterSetName = 'Remote',
                   Mandatory = $true)]
        [string]
        $ComputerName,
        
        # Credentials to use connection.
        [Parameter(ParameterSetName = 'Remote',
                   Mandatory = $true)]
        [Parameter(ParameterSetName = 'Alternate',
                   Mandatory = $true)]
        [Management.Automation.PSCredential]
        [Management.Automation.CredentialAttribute()]
        $Credential,
        
        [Parameter(Mandatory=$false,
                HelpMessage='Maximum number of Objects to pull from AD, limit is 1,000 .')]
        [int]
        $Limit = 1000,
        
        [Parameter(Mandatory=$false)]
        [string]
        $searchRoot,
        
        [Parameter(Mandatory=$false)]
        [int]
        $PageSize = 100,
        
        [Parameter(Mandatory=$false,
                   HelpMessage='scope of a search as either a base, one-level, or subtree search, default is subtree.')]
        [ValidateSet('Subtree',
                     'OneLevel',
                     'Base')]
        [string]
        $SearchScope = 'Subtree',
        
        [Parameter(Mandatory=$false,
                   HelpMessage='Specifies the available options for examining security information of a directory object')]
        [ValidateSet('None',
                     'Dacl',
                     'Group',
                     'Owner',
                     'Sacl')]
        [string[]]
        $SecurityMask = 'None',
        
        [Parameter(Mandatory=$false,
                   HelpMessage='Whether the search should also return deleted objects that match the search filter.')]
        [switch]
        $TombStone,
        
        [Parameter(Mandatory=$false,
                   HelpMessage='Only those trusted for delegation.')]
        [switch]
        $TrustedForDelegation,
        
        [Parameter(Mandatory=$false,
                   HelpMessage='Date to search for computers mofied on or after this date.')]
        [datetime]
        $ModifiedAfter,

        [Parameter(Mandatory=$false,
                   HelpMessage='Date to search for computers mofied on or before this date.')]
        [datetime]
        $ModifiedBefore,

        [Parameter(Mandatory=$false,
                   HelpMessage='Date to search for computers created on or after this date.')]
        [datetime]
        $CreatedAfter,

        [Parameter(Mandatory=$false,
                   HelpMessage='Date to search for computers created on or after this date.')]
        [datetime]
        $CreatedBefore,
        
        [Parameter(Mandatory=$false,
                   HelpMessage='Date to search for computers that logged on or after this date.')]
        [datetime]
        $LogOnAfter,

        [Parameter(Mandatory=$false,
            HelpMessage='Date to search for computers that logged on or after this date.')]
        [datetime]
        $LogOnBefore,
        
        [Parameter(Mandatory=$false,
            HelpMessage='Date to search for when the computer password was set after this date.')]
        [datetime]
        $PwSetAfter,

        [Parameter(Mandatory=$false,
            HelpMessage='Date to search for when the computer password was set before this date.')]
        [datetime]
        $PwSetBefore,

        [Parameter(Mandatory=$false,
                   HelpMessage='Filter by the specified operating systems.')]
        [SupportsWildcards()]
        [string[]]
        $OperatingSystem,

        [Parameter(Mandatory=$false,
                   HelpMessage='Filter by the specified Service Principal Names.')]
        [SupportsWildcards()]
        [string[]]
        $SPN,
        
        [Parameter(Mandatory=$false,
                   HelpMessage='Name of host to match search on.')]
        [ValidateNotNullOrEmpty()]
        [SupportsWildcards()]
        [string]
        $Name,

        [Parameter(Mandatory=$false,
                   HelpMessage='List of only the properties to retrieve from AD.')]
        [string[]]
        $Property = $()
        
        
    )
    
    begin {
        # Build filter
        $CompFilter = '(objectCategory=Computer)'
        $TempFilter = ''
        # Filter for modification time
        if ($ModifiedAfter -and $ModifiedBefore) {
            $TempFilter = "$($TempFilter)(whenChanged>=$($ModifiedAfter.ToString('yyyyMMddhhmmss.sZ')))(whenChanged<=$($ModifiedBefore.ToString('yyyyMMddhhmmss.sZ')))"
        } elseif ($ModifiedAfter) {
            $TempFilter = "$($TempFilter)(whenChanged>=$($ModifiedAfter.ToString('yyyyMMddhhmmss.sZ')))"
        } elseif ($ModifiedBefore) {
            $TempFilter = "$($TempFilter)(whenChanged<=$($ModifiedBefore.ToString('yyyyMMddhhmmss.sZ')))"
        }

        # Fileter for creation time
        if ($CreatedAfter -and $CreatedBefore) {
            $TempFilter = "$($TempFilter)(whencreated>=$($CreatedAfter.ToString('yyyyMMddhhmmss.sZ')))(whencreated<=$($CreatedBefore.ToString('yyyyMMddhhmmss.sZ')))"
        } elseif ($CreatedAfter) {
            $TempFilter = "$($TempFilter)(whencreated>=$($CreatedAfter.ToString('yyyyMMddhhmmss.sZ')))"
        } elseif ($CreatedBefore) {
            $TempFilter = "$($TempFilter)(whencreated<=$($CreatedBefore.ToString('yyyyMMddhhmmss.sZ')))"
        }
        
        # Fileter for password last set
        if ($PwSetAfter -and $PwSetBefore) {
            $TempFilter = "$($TempFilter)(pwdlastset>=$($PwSetAfter.ToFileTimeUTC()))(pwdlastset<=$($PwSetBefore.ToFileTimeUTC()))"
        } elseif ($PwSetAfter) {
            $TempFilter = "$($TempFilter)(pwdlastset>=$($PwSetAfter.ToFileTimeUTC()))"
        } elseif ($PwSetBefore) {
            $TempFilter = "$($TempFilter)(pwdlastset<=$($PwSetBefore.ToFileTimeUTC()))"
        }

        # Fileter for loggon time
        if ($LogOnAfter -and $LogOnBefore) {
            $TempFilter = "$($TempFilter)(lastlogon>=$($LogOnAfter.ToFileTimeUTC()))(lastlogon<=$($LogOnBefore.ToFileTimeUTC()))"
        } elseif ($LogOnAfter) {
            $TempFilter = "$($TempFilter)(lastlogon>=$($LogOnAfter.ToFileTimeUTC()))"
        } elseif ($LogOnBefore) {
            $TempFilter = "$($TempFilter)(lastlogon<=$($LogOnBefore.ToFileTimeUTC()))"
        }

        if ($Name) {
            $TempFilter = "$($TempFilter)(name=$($Name))"
        }

        # Filter by Operating System
        if ($OperatingSystem) {
            $initialFilter = ''
            foreach ($os in $OperatingSystem) {
                $initialFilter += "(operatingSystem=$($os))"
            }
            $TempFilter += "(|$($initialFilter))"
        }

        # Filter by Service Principal Name
        if ($SPN) {
            $initialFilter = ''
            foreach ($sp in $SPN) {
                $initialFilter += "(servicePrincipalName=$($sp))"
            }
            $TempFilter += "(|$($initialFilter))"
        }

        # Filter for hosts trusted for delegation.
        if ($TrustedForDelegation) {
            $TempFilter = "$($TempFilter)(userAccountControl:1.2.840.113556.1.4.803:=524288)"
        }

        $CompFilter = "(&$($CompFilter)$($TempFilter))"

        $culture = Get-Culture
        
        $StndProps = @(
            
        )

        $EncryptionTypes = @{
            1 = 'DES-CBC-CRC'
            2 = 'DES-CBC-MD5'
            4 = 'RC4-HMAC'
            8 = 'AES128-CTS-HMAC-SHA1-96'
            10 = 'AES256-CTS-HMAC-SHA1-96'}

<# $enctype = 28
foreach ($enct in $EncryptionTypes.keys) {
    if ($enct -band $enctype)
    {
        $EncryptionTypes[$enct]
    }
}#>


    }
    
    process {
        write-verbose -message "Executing search with filter $CompFilter"
        switch ($PSCmdlet.ParameterSetName) {
            'Remote' { 
                if ($searchRoot) {
                    $objSearcher = Get-DSDirectorySearcher -ComputerName $ComputerName -SearchRoot $searchRoot -Credential $Credential -Filter $CompFilter

                } else {
                    $objSearcher = Get-DSDirectorySearcher -ComputerName $ComputerName -Credential $Credential -Filter $CompFilter
                }
                
             }
            'Alternate' {
                $objSearcher = Get-DSDirectorySearcher -Credential $Credential -Filter $CompFilter
            }
            'Current' {
                $objSearcher = Get-DSDirectorySearcher -Filter $CompFilter
            }
            Default {}
        }
        $objSearcher.SizeLimit = $Limit
        $objSearcher.PageSize = $PageSize
        $objSearcher.SearchScope = $SearchScope
        $objSearcher.Tombstone = $TombStone
        $objSearcher.SecurityMasks = [DirectoryServices.SecurityMasks]$SecurityMask

        # If properties specified add those to the searcher
        if ($Property.count -ne 0 -or $Property -contains '*') {
            foreach ($prop in $Property) {
                $objSearcher.PropertiesToLoad.Add($prop.ToLower()) | Out-Null
            }
        }

        $objSearcher.findall() | ForEach-Object -Process {
            #$userObj = [adsi]$_.path
            $objProps = [ordered]@{}
            foreach ($prop in ($_.Properties.PropertyNames | Sort-Object))
            {
                if ($prop -eq 'objectguid') {
                    $objProps['Guid'] = [guid]$_.properties."$($prop)"[0]
                } elseif($prop -eq 'objectsid') {
                    $objProps['Sid'] = "$(&{$sidobj = [byte[]]"$($_.Properties.objectsid)".split(' ');$sid = new-object System.Security.Principal.SecurityIdentifier $sidobj, 0; $sid.Value})"
                } elseif($prop -eq 'lastlogontimestamp') {
                    $timeStamp = "$($_.Properties.lastlogontimestamp)"
                    $timeStampDate = [datetime]::FromFileTimeUtc($timeStamp)
                    $objProps['LastLogonTimeStamp'] = $timeStampDate
                } elseif($prop -eq 'ntsecuritydescriptor') {
                    $secds = New-Object System.DirectoryServices.ActiveDirectorySecurity
                    $Desc = $_.Properties.ntsecuritydescriptor[0]
                    $secds.SetSecurityDescriptorBinaryForm($Desc)
                    $objProps['NTSecurityDescriptor'] = $secds
                } elseif($prop -eq 'usercertificate') {
                    $certs = foreach ($cert in $_.Properties.usercertificate) {[Security.Cryptography.X509Certificates.X509Certificate2]$cert}
                    $objProps['UserCertificate'] = $certs
                } elseif ($prop -eq 'accountexpires') {
                    Try
                    {
                        $exval = "$($_.properties.accountexpires[0])"
                        If (($exval -eq 0) -or ($exval -gt [DateTime]::MaxValue.Ticks))
                        {
                            $objProps['AccountExpires'] = '<Never>'
                        }
                        Else
                        {
                            $Date = [DateTime]$exval
                            $objProps['AccountExpires'] = $Date.AddYears(1600).ToLocalTime()
                        }
                    }
                    catch
                    {
                        $objProps['AcctExpires'] = '<Never>'
                    }
                }
                elseif ($prop -eq 'pwdlastset')
                {
                    $objProps.Add('PwdLastSet', [dateTime]::FromFileTime($_.properties.pwdlastset[0]))
                }
                elseif ($prop -eq 'lastlogon')
                {
                    $objProps.Add('LastLogon', [dateTime]::FromFileTime($_.properties.lastlogon[0]))
                }
                elseif ($prop -eq 'badpasswordtime')
                {
                    $objProps.Add('BadPasswordTime', [dateTime]::FromFileTime($_.properties.badpasswordtime[0]))
                }
                else {
                    $objProps[$culture.TextInfo.ToTitleCase($prop)] = $_.properties."$($prop)"[0]
                }
            }
            if ($objProps['Dnshostname']) {
                $IPs = Get-ADIPAddress -ComputerName $objProps['Dnshostname']
                if ($IPs.count -ne 0)
                {
                    $objProps.Add('IPAddress',$IPs)
                }
                else
                {
                    $objProps.Add('IPAddress','')
                }
            }
            
            $compObj = [PSCustomObject]$objProps
            $compObj
        }
    }
    
    end {
    }
}