在所有域计算机上列出本地管理员组成员身份

时间:2016-03-09 17:24:14

标签: powershell dns active-directory

在这里完成PowerShell和脚本编写器 - 我甚至不知道是不是很危险。我需要查询域中的所有PC以确定其本地Administrators组成员身份是什么,并将该输出发送到text / csv文件。

我尝试过很多事情:

Import-Module -Name ActiveDirectory
Get-ADComputer -filter * |
Foreach-Object {
 invoke-command {net localgroup administrators} -EA silentlyContinue |
} |
Out-File c:\users\ftcadmin\test.txt

这让我重复了相同的列表,但似乎正在击中每个域名PC。我猜它实际上并没有在远程PC上运行。还尝试过:

$computers = Get-Content -Path c:\users\ftcadmin\computers.txt
invoke-command {net localgroup administrators} -cn $computers -EA silentlyContinue
Get-Process | Out-File c:\users\ftcadmin\test.txt

受限于computers.txt文件中预定的PC列表。我试过的第三件事是:

$a = Get-Content "C:\users\ftcadmin\computers.txt"
Start-Transcript -path C:\users\ftcadmin\output.txt -append
foreach ($i in $a)
  { $i + "`n" + "===="; net localgroup "Administrators"}
Stop-Transcript
除了输出之外,

似乎具有最大的潜力

computername1
====
computername2
====

等没有任何小组成员列表。

来自社区的任何想法?

3 个答案:

答案 0 :(得分:2)

将此功能复制并粘贴到PowerShell控制台中。

function Get-LocalGroupMember
{
    [CmdletBinding()]
    param
    (
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$Name,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$ComputerName = 'localhost',

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [pscredential]$Credential
    )
    process
    {
        try
        {
            $params = @{
                'ComputerName' = $ComputerName
            }
            if ($PSBoundParameters.ContainsKey('Credential'))
            {
                $params.Credential = $Credential
            }

            $sb = {
                $group = [ADSI]"WinNT://./$using:Name"
                @($group.Invoke("Members")) | foreach {
                    $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
                }
            }
            Invoke-Command @params -ScriptBlock $sb
        }
        catch
        {
            Write-Error $_.Exception.Message
        }
    }
}

然后,尝试使用它:

Get-ADComputer -filter * | foreach {Get-LocalGroupMember -Name 'Administrators' -ComputerName $_.Name }

如果你想做一些格式化,你可以获得一份计算机列表,并在每一台计算机旁边都有所有成员。

Get-ADComputer -filter * | foreach {
    $members = Get-LocalGroupMember -Name 'Administrators' -ComputerName $_.Name
    [pscustomobject]@{
        'ComputerName' = $_.Name
        'Members' = $members    
    }   
}

这至少需要PowerShell v3。如果您没有,我强烈建议您升级到PowerShell v4。

答案 1 :(得分:1)

在PowerShell版本5.1(WMF 5.1或Windows 10版本1607附带的版本)中,现在(最终)cmdlet用于管理本地用户和组。 https://technet.microsoft.com/en-us/library/mt651681.aspx

例如,要获取本地Administrators组的成员,可以使用

Get-LocalGroupMember -Group "Administrators"

不幸的是,这些新的cmdlet没有用于远程运行命令的ComputerName参数。您需要使用Invoke-Command之类的东西远程运行命令,远程计算机也需要使用PowerShell版本5.1。

Invoke-Command cmdlet的ComputerName参数不接受管道输入,它只接受字符串,因此我们首先需要展开Get-ADComputer返回的name属性并将字符串存储在变量中。值得庆幸的是,该参数接受多个字符串,因此我们可以在单个invoke-command调用中使用$ names变量。示例如下:

$names = Get-ADComputer -Filter * | Select-Object -ExpandProperty name
Invoke-Command -ScriptBlock {Get-LocalGroupMember -Group "Administrators"} -ComputerName $names

答案 2 :(得分:0)

这实际上是我最近做过的事情。似乎有两种常规方法可以从本地Administrators组获取成员:WMI和ADSI。

在我看来,更好的方法是使用WMI查询来获取成员,因为这包括域,因此您知道列出的用户/组是服务器本地还是域帐户。

使用ADSI的简单方法不包括此信息,但不太可能获得拒绝访问类型的错误。

为此,我拼凑了一个脚本,用于检查过去30天内活动的机器的AD(如果它不在线,则无需浪费时间)。然后,对于每个人,它尝试执行WMI查询以获取管理员成员,如果失败则转向ADSI查询。数据存储为哈希表,因为在我看来,这是管理嵌套数组的一种简单方法。

$TMinus30 = [datetime]::Now.AddDays(-30).ToFileTime()
$Domains = 'ChinchillaFarm.COM','TacoTruck.Net'
$ServerHT = @{}
$Servers = ForEach($Domain in $Domains){Get-ADObject -LDAPFilter "(&(objectCategory=computer)(name=*))" -Server $Domain | ?{$_.lastLogonTimestamp -gt $TMinus30}}
$Servers.DNSHostName | %{$ServerHT.Add($_,$Null)}
ForEach($Server in ($Servers | ?{$(Test-Connection $_.DNSHostName -Count 1 -Quiet)})){
    Try{
        $GMembers = Get-WmiObject -ComputerName $Server -Query "SELECT * FROM win32_GroupUser WHERE GroupComponent = ""Win32_Group.Domain='$Server',Name='Administrators'"""
        $Members = $GMembers | ?{$_.PartComponent -match 'Domain="(.+?)",Name="(.+?)"'}|%{[PSCustomObject]@{'Domain'=$Matches[1];'Account'=$Matches[2]}}
    }
    Catch{
        $group = [ADSI]("WinNT://$Server/Administrators,group") 
        $GMembers = $group.psbase.invoke("Members")
        $Members = $GMembers | ForEach-Object {[PSCustomObject]@{'Domain'='';'Account'=$_.GetType().InvokeMember("Name",'GetProperty', $null, $_, $null)}}
    }

    $ServerHT.$Server = $Members
}

然后,如果需要,您只需要输出到文件。这就是我要做的,应该输出你想要的东西:

$ServerHT.keys|%{"`n"+("="*$_.length);$_;("="*$_.length)+"`n";$ServerHT.$_|%{"{0}{1}" -f $(If($_.Domain){$_.Domain+"\"}), $_.Account}}

如果前两个服务器响应WMI查询而第三个服务器没有响应,则会显示以下内容:

===========
ServerSQL01
===========

ServerSQL01\SQLAdmin
TacoTruck\TMTech
TacoTruck\Stan2112

======
XWeb03
======

ChinchillaFarm\Stan2112

============
BrokenOld486
============

TMTech
Guest

如果有人将Guest帐户放在本地管理员组中,那最后一个会在我的书中触发一些危险信号,但我想这可能是你首先这样做的原因之一。