AD Object name doesn't presented well

Hello All,

I have a script which help me to find all OU computers local admin.
when i run it, instead of computer name i get “System.DirectoryServices.PropertyValueCollection”

code:

Import-Module ActiveDirectory
$Searcher = New-Object DirectoryServices.DirectorySearcher([ADSI]"")
$Searcher.SearchRoot = 'LDAP://OU=Laptops,DC=contoso,DC=com'
$Searcher.Filter = "(objectClass=computer)"
$Computers = ($Searcher.Findall())

$Results = @()
md C:\temp

Foreach ($Computer in $Computers){
	$Path=$Computer.Path
	$Name=([ADSI]"$Path").Name
	write-host $Name
	$members =[ADSI]"WinNT://$Name/Administrators"
	$members = @($members.psbase.Invoke("Members"))
	$members | foreach {
		$LocalAdmins = $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)    # Create a new object for the purpose of exporting as a CSV
		$pubObject = new-object PSObject
		$pubObject | add-member -membertype NoteProperty -name "Server" -Value $Name
		$pubObject | add-member -membertype NoteProperty -name "Administrators" -Value $LocalAdmins

		# Append this iteration of our for loop to our results array.
		$Results += $pubObject
	}
}

$Results | Export-Csv -Path "C:\temp\ServerLocalAdmins.csv" -NoTypeInformation
$Results = $Null

Wow … how do you manage to find such a crappy code? :smirk:

You may start with something like this and extend or tweak it to your particular needs.

$SearchBase = 'OU=Laptops,DC=contoso,DC=com'
$CSVPath = 'C:\temp\ServerLocalAdmins.csv'

$ComputerList = Get-ADComputer -Filter * -SearchBase $SearchBase

$Result =
foreach ($ComputerName in $ComputerList.Name) {
    if (Test-Connection -ComputerName $ComputerName) {
        Invoke-Command -ComputerName $ComputerName -ScriptBlock {
            Get-LocalGroupMember -Group Administrators 
        } | Select-Object -Property Name, PSComputerName
    }
}

$Result |
    Export-Csv -Path $CSVPath -NoTypeInformation -Delimiter ',' -Encoding utf8

Ok, thanks.
with this method, i will have to Enable-PSRemoting on each endpoint?
of course it could be done by GP

Yes. I tend to assume that this is the case for any nearly up to date server infrastructure anyway. :wink:

I didn’t get that. What is “GP”?

sorry, Group Policy,

thank you so much.

Although I agree the code could use some fine tuning, if the OP wants to avoid enabling PSRemoting for some security reason, and or has hosts at a powershell level the does not support Get-LocalGroupMember, I see nothing wrong with using ADSI.

I personally manage systems that meet this criteria.

My $.02

This code has a lot of legacy bad habits. That aside, you could try surrounding name with a subexpression

$($name)

I’ve had to do that frequently with adsi objects that normal powershell objects rarely require

It’s still not worth the hassle in my opinion. :smirk:

In my experiences most of the time, those “security reasons” are unsubstantiated vague concerns limitting the managebility without actually increasing security.

Those systems need to be updated as soon as possible.

There is nothing wrong with using ADSI but when you borrow code from others you should do it right. :wink: :stuck_out_tongue_winking_eye: :grin:

$SearchBase = 'OU=Laptops,DC=contoso,DC=com'
$CSVPath = 'C:\temp\ServerLocalAdmins.csv'

$ComputerList = Get-ADComputer -Filter * -SearchBase $SearchBase
$NetBIOSDomainName = (([adsi]'').distinguishedname -split ',|=')[1]
$LocalGroupName = 'Administrators'

$Result =
foreach ($ComputerName in $ComputerList.Name) {
    if (Test-Connection -ComputerName $ComputerName -Count 1 -Quiet ) {
        Write-Verbose $ComputerName
        $Group = [ADSI]"WinNT://$NetBIOSDomainName/$ComputerName/$LocalGroupName"         try {
            $Group.psbase.Invoke("members") | 
            ForEach-Object {
                [PSCustomObject]@{
                    ComputerName = $ComputerName
                    Group        = 'Administrators'
                    GroupMember  = $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
                }
            }
        }
        catch {
        }
    }
}

$Result
$Result |
    Export-Csv -Path $CSVPath -NoTypeInformation -Delimiter ',' -Encoding utf8

Even if I don’t fully understand it myself and it’s ugly … it works in my test environment.

Just my $.02 :smirk: :man_shrugging:t4:

Understood and I totally agree. However, I do have to maintain a script in an air gapped XP environment where we are contractually bound to leave the systems as is. I had to resort to ADSI … so there are situations where it cant be avoided.

You need to change/update Active Directory group memberships in an air gapped computer running with XP by script? Really? :thinking: :smirk: :smirk: Poor you! :wink: :wink:

No, sorry for not being clear. I just query group membership using ADSI as part of the system audit. There is no domain/AD.

Don’t worry. I’m just making fun. :wink: :stuck_out_tongue_winking_eye:

I probably would have used

net localgroup administrators

in this case. I like to work according to the KISS principle. :wink:

Understood. However, I have to audit ALL local groups, so I use ADSI. If there is a better way, I am all ears :slight_smile:

I am also not allowed to use/install external modules.

Thanks Olaf.