wrigley06
wrigley06

Reputation: 359

Trouble executing powershell script on multiple remote machines

I need to generate a list of all users on our network who are members of their workstation's local administrators group. I found a script here https://gallery.technet.microsoft.com/scriptcenter/List-local-group-members-762b48c5#content which was written to list local group members by executing a WMI query through Powershell. I've tested this script and it works well, but I've been trying to modify it to take in a list of computers to check and that's where I've run into trouble. Here's what I've done:

function LocalAdmins
{
  param([string]$GroupName = "Administrators")

    begin
    {
        # Get all workstations listed in this text file
        $WorkStations = Get-Content -Path C:\useful_lists\testLocal.txt

        # Initialize an array to hold the results of the query
        $arr = @()

    # hash table for storing computer name, member pairings
    $hash = @();
    }

    process
    {
        foreach ($machine in $WorkStations)
        {
            $wmi = Get-WmiObject -ComputerName $machine -Query `
                "SELECT * FROM Win32_GroupUser WHERE GroupComponent=`"Win32_Group.Domain='$machine',Name='$GroupName'`""

            # Parse out the username from each result and append it to the array
            if ($wmi -ne $null)
            {
                foreach($item in $wmi)
                {
                    $arr += ($item.PartComponent.Substring($item.PartComponent.IndexOf(',') + 1).Replace('Name=', '').Replace("`"", ''))
                }
            }

            # Return a hash table comprised of two columns: Computer Name & Members
            $hash += @{ComputerName=$machine;Members=$arr}
        }
    }

    end
    {
        return $hash
    }
}

When I ran the unmodified script here's what I got as output:

PS > (Get-LocalGroupMembers -ComputerName "<COMPUTER NAME>" -GroupName "Administrators").Members

ACCOUNTNAME
ACCOUNTNAME
ACCOUNTNAME

PS >

However, when I run the version of this script that I modified I get this:

PS > (LocalAdmins -GroupName "Administrators").Members
PS >

I'm fairly certain that the issue lies either in how I've setup the first foreach loop to run the wmi query or how the results of that query are being stored in the hash table. I'm not sure what I could do differently to fix the issue.

Thanks in advance to anyone who can help!

UPDATE

Per mortenya's suggestion, I edited my test text file to only include one computer in it. Doing so, along with taking out the foreach ($machine in $computers) loop worked as expected producing the following result:

>> LocalAdmins -GroupName "Administrators"

Name               Value
----               ----
ComputerName       {computerName.domain}
Members            {account, account, account, account}

>>

However, going back and trying to get this to work when incorporating multiple machines using the code above (I've updated it since my initial post), I get the following:

>> LocalAdmins -GroupName "Administrators"

Name               Value
----               -----
ComputerName       computerName1.domain
Members            {}
ComputerName       computerName2.domain
Members            {}

>>

Why is it that with one machine in the list I can get the members of the Administrator group, but adding a second computer to the list makes it so I can not retrieve members from that group on either machine?

Upvotes: 1

Views: 444

Answers (1)

mortenya
mortenya

Reputation: 209

So, if you're going to use Begin{}, Process{}, and End{}, use them for what they're meant for, in the Begin{} block, initialize all your arrays and constant varaibles.

Begin {
    # Get all workstations listed in this text file
    $WorkStations = Get-Content -Path C:\useful_lists\testLocal.txt

    # Store the contents of that list in an array
    $computers = @()

    $hash = @()
}

Outside of that, I did this same thing a few months ago, it's a little messy, but it spit out a list of computers and who was in the Local Administrators group. It was partially to practice some different methods.

$output = 'c:\psresults\ListOfLocalAdministratorsGroup.txt'
$results = New-Object System.Collections.ArrayList

$objSID = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")
$objgroup = $objSID.Translate( [System.Security.Principal.NTAccount])
$objgroupname = ($objgroup.Value).Split("\")[1]

foreach($server in (Get-ADComputer -Filter *).name)
{
    $admins = New-Object System.Collections.ArrayList
    $group =[ADSI]"WinNT://$server/$objgroupname" 
    $members = @($group.psbase.Invoke("Members"))
    $members | foreach {
        $obj = new-object psobject -Property @{
            Server = $Server
            Admin = $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
    }    
    #$obj
        $admins.Add($obj)
    } 
    $results.Add($admins)
}
$results | Out-File $Output

I found the meat of that somewhere and then modified it a bit.

EDIT: I just put this into ISE and it seems to work fine

$machine = "testsrv"
$groupname = "Administrators"

$wmi = Get-WmiObject -ComputerName $machine -Query `
"SELECT * FROM Win32_GroupUser WHERE GroupComponent=`"Win32_Group.Domain='$machine',Name='$GroupName'`""

if ($wmi -ne $null) 
{ 
    foreach ($item in $wmi) 
    { 
        $arr += ($item.PartComponent.Substring($item.PartComponent.IndexOf(',') + 1).Replace('Name=', '').Replace("`"", '')) 
    } 
} 

$hash = @{ComputerName=$machine;Members=$arr} 
return $hash

Get it working on one machine, then start trying to add the loops back in.

EDIT 2.0:

  1. I made a .txt file with only computer names in it, not the FQDN, that works fine for me. I can run it and get results using your script with minor modification.

  2. Despite what I'd said about the Begin{} block, the $arr variable will need to be initialized inside the foreach ($machine in $WorkStations) loop. The reason for this is that when the loop runs, it will create the $arr array, add the data we want, insert that data into a global variable, and then clean up the $arr variable. If we make this global, it won't be cleaned up until the function is done, and we will just keep adding to it, which isn't what we actually want in this case.

  3. The problem you're having with getting multiple machines to work is likely how you're building your results table.

Upvotes: 1

Related Questions