Automation of local server admin group membership

Hi Guys,

I recently got my feet wet with PowerShell and before I know it, I have been handed an “interesting” task. You know how we have the local server admin groups on our servers and as all of us reading this post we would like to keep this group membership of this admin group on the server streamlined and a desired standard, however that doesn’t work out too well does it. Over time we see individual accounts added, different domain groups added and service accounts added and that just goes out of hand!

Now enough of this backstory. What I am looking to do is query all my servers and look for the group membership of the local server admins group and report it back to me. After I have that I want to somehow just somehow automate the process of updating this membership if its non complaint.
So I googled and found a lot of information on how to get he local admin groups membership and some of the scripts were quite lengthy and a little complex at this stage for me to understand (But I eventually made some sense of it!)

So i wrote up a 6 line piece of code which would query all the servers in a text file and report the group membership back to me.
I mean its really some basic line of code and here it is

$server = Get-Content C:\powershell\Scripts\GetLocalAdmin\IN\servers.txt
foreach($item in $server){
write-host "`n"
Write-Host "Checking $($item.toupper())" -ForegroundColor Green 
write-host "`n" 
invoke-command {net localgroup Administrators} -comp $item
}

Now the way this script runs just fine in the console, BUT for now I cant figure out how to export this to a csv file, maybe I need to look at using hash tables, which again I need to read up!

So my million dollar question is –> Can the maintenance of a local server admin group be automated? Like look at the membership and if its not the correct model, delete the extra group or account.
Having said that, I have some exceptions in my environment that I need to account for. Like a citrix server needs a locally added service account or else the citrix app breaks!
So as you can tell, this is an “interesting” task and I am looking for the laziest way to get this done! j/k

-A

After looking around all day and trying different possibilities, I now have a script block using which I can remove an account from the local admin group of a server. However now I need something a little more smarter. What I need to do is query all the servers that I pass and remove any accounts that start with “adm”.

I have the below lines of code but what I am trying to do is clearly wrong and that is why it doesn’t work!
Any clues

Also the way I am using invoke-command in my earlier post, I dont think its the right way to export to csv as I cant seem to nail that…

$serverList = Get-Content -Path 'C:\powershell\Scripts\GetLocalAdmin\New folder\servers.txt'
foreach ($server in $serverList) {
   $computer = [ADSI]("WinNT://" + $server + ",computer")  
   $group = $computer.psbase.children.find("Administrators") 
   $group.Remove("WinNT://mydomainname/" + 'adm*')
}
  1. get rid of write-host. use write-output or [pscustomobject] and export-csv
    2a. group policy :slight_smile:
    2b. or a script that read group membership, compare it with reference model and save it back if needed.
    where can I get my million ? :wink:

Hi Max,

Thanks for the response. I ended up writing a new piece of code which might make it easier to get that to export, however I am still working on that bit!

$computers = 'server1','server2'
$groupname = 'Administrators'

foreach($comp in $computers){
  $group = [ADSI]("WinNT://$comp/$groupname,group")
  $group.PSBase.Invoke('Members') | % {
    $_.GetType().InvokeMember('Name', 'GetProperty', $null, $_, $null)
   
  }
} 

This is a part of my long-time-ago written module

Hope it helps with your task

Thanks Max! I will probably take my entire lifetime to get my head around your script! haha but I really appreciate that.
Also I have found a way to remove my unwanted members from the local admin group of the servers, I just need to build in some more logic but I think. Also I need to export the results to a csv file… Let see how far I get!

$serverList = "server1","server2"
foreach ($server in $serverList) {
$objGroup = [ADSI]("WinNT://$server/Administrators")
 $objGroupMembers = $objGroup.Invoke("Members") | foreach {$_."GetType".Invoke().InvokeMember("Name", 'GetProperty',$null, $_, $null)}
 
        ForEach($Member in $objGroupMembers)
        {
            If($Member -like "adm*")
            {
            
             $objRemoveGroup = [ADSI]("WinNT://contoso/$($Member)")
             $objGroup.Invoke("Remove",$objRemoveGroup.PSBase.Path)
             Write-host "Removed $Member from Administrators on $server"
             
             }


            if($Member -like "tem*"){

            $objRemoveGroup = [ADSI]("WinNT://contoso/$($Member)")
             $objGroup.Invoke("Remove",$objRemoveGroup.PSBase.Path)
            Write-host "Removed $Member from Administrators on $server"
            
            }
          
        } 
        
        }

I think I have achieved what I wanted to for now atleast. I have come with a script which queries my OU structure and pulls out all the Windows 2008 and Windows 2012 machines and puts them in a csv file. After that the script reads that csv file and processes all the machines in that and removes any accounts starting with adm and tem and prints the removed accounts and the server name in the console! phew!

Hope this helps someone out here and if you improve it please let me know! I am no expert by anyway… I just figured this is the simplest way to achieve it.

$result = @()
$ous ='OU=UAT,OU=Servers Non-Production,OU=TESTING,OU=US,OU=machines,DC=contoso,DC=com'
ForEach ($ou in $ous){
$count = Get-ADComputer -Filter * -SearchBase $ou -Properties Name,OperatingSystemVersion,LastLogonDate,OperatingSystem,Description | where{$_.operatingsystem -match 'Windows Server 2008*' -or $_.operatingsystem -match 'Windows Server 2012*'} | select-object Name | Sort-Object  Name -Descending
$result+= $count
}

$result | Export-Csv -Path C:\powershell\Scripts\GetLocalAdmin\ME\MEServers.csv -Encoding UTF8 -NoTypeInformation


$serverList = (Get-Content C:\powershell\Scripts\GetLocalAdmin\ME\MEServers.csv) -notmatch 'Name'

foreach ($server in $serverList) {
$objGroup = [ADSI]("WinNT://$server/Administrators")
 $objGroupMembers = $objGroup.Invoke("Members") | foreach {$_."GetType".Invoke().InvokeMember("Name", 'GetProperty',$null, $_, $null)}
 

        ForEach($Member in $objGroupMembers)
        {
            If($Member -like "adm*")
            {
             
                  
             $objRemoveGroup = [ADSI]("WinNT://contoso/$($Member)")
             $objGroup.Invoke("Remove",$objRemoveGroup.PSBase.Path)
             Write-host "Removed $Member from Administrators on $server"
             
             }


            if($Member -like "tem*"){

            $objRemoveGroup = [ADSI]("WinNT://contoso/$($Member)")
             $objGroup.Invoke("Remove",$objRemoveGroup.PSBase.Path)
             Write-host "Removed $Member from Administrators on $server"
            
            
            }
          
        } 
        
        }