列出除域管理员和本地管理员之外的所有本地管理员帐户

List all local administrator accounts excluding domain admin and local admin

function get-localgroupmember {
  [CmdletBinding()]
  param(
    [parameter(ValueFromPipeline=$true,
      ValueFromPipelineByPropertyName=$true)]
    [string[]]$computername = $env:COMPUTERNAME
  )

  BEGIN {
    Add-Type -AssemblyName System.DirectoryServices.AccountManagement
    $ctype = [System.DirectoryServices.AccountManagement.ContextType]::Machine
  }

  PROCESS{
    foreach ($computer in $computername) {
      $context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $ctype, $computer
      $idtype = [System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName
      $group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($context, $idtype, 'Administrators')
      $group.Members |
        select @{N='Server'; E={$computer}}, @{N='Domain'; E={$_.Context.Name}}, samaccountName
    } # end foreach
  } # end PROCESS
}

"Win12R2", "W12SUS" | get-localgroupmember

我想要的是如下所示的输出,我想标记管理员组中不属于我们标准设置的用户。真的,我想忽略作为域帐户的 SAM 帐户,但现在标记它们是可行的。发生的事情是通过 SAM 帐户循环来创建此输出。但是,当机器离线时,我也需要注意这一点。

我也不想使用 ValueFromPipeline 而是从此命令 $allComputers = Get-ADComputer -Filter 'PasswordLastSet -ge $date' -properties PasswordLastSet | select Name 获取 PC 名称列表,然后使用该变量作为循环的源。

这是我修改后的代码,但当 $group.Members |select @{N='Server'; E={$computer}}, @{N='Domain'; E={$_.Context.Name}}, samaccountName

中似乎存在循环时,我在创建要添加到数组的自定义对象时遇到问题
function get-localgroupmember {
  [CmdletBinding()]
  param(
    [Parameter(Mandatory=$True,HelpMessage="Enter PC")]
    [ValidateNotNullorEmpty()]
    [object]$computername = $null   
  )

  BEGIN {
    $newArray = @();
    Add-Type -AssemblyName System.DirectoryServices.AccountManagement
    $ctype = [System.DirectoryServices.AccountManagement.ContextType]::Machine
  }

  PROCESS{
    foreach ($computer in $computername) {
      If (Test-Connection -ComputerName $computer.name -Quiet -Count 1) {
        try {
          $context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $ctype, $computer.name
          $idtype = [System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName
          $group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($context, $idtype, 'Administrators')

          $group.Members | select @{N='Server'; E={$computer.name}}, @{N='Domain'; E={$_.Context.Name}}, samaccountName

          $objComputer = [pscustomobject] @{
            Server = $computer.name
            Domain = $group.Members | select @{N='Domain'; E={$_.Context.Name}}
            Account = $Computer.samaccountName
          }
        } catch {
          $objComputer = [pscustomobject] @{
            Server = $computer.name
            Domain = "Error"
            Account = "Error"
          }
        }
      } else {
          $objComputer = [pscustomobject] @{
            Server = $computer.name
            Domain = "Off-Line"
            Account = "Off-Line"
          }
      } $arrayNew += $objComputer
    } # end foreach
  } # end PROCESS

  return $arrayNew
}

$date = [DateTime]::Today.AddDays(-1)

$allComputers = Get-ADComputer -Filter  'PasswordLastSet -ge $date' -properties PasswordLastSet | select Name

get-localgroupmember -computername $allComputers | Out-GridView

老实说,我不会像您那样尝试输出数组对象。真的没有必要。只需根据需要创建每个对象,并让它直接输出(你真的不需要使用 return 因为函数将把任何输出传递到管道,除非你特别告诉它,比如 Write-Host,或 Out-File)。此外,看起来您的输入需要一个对象(这很模糊),但是您随后试图遍历该对象,并将每条记录用作 PC 的名称,因此您真正想要输入的是一个字符串数组.在这种情况下,将您的类型从 [object] 更改为 [string[]]。最后,如果您在创建 $AllComputers 变量时仅扩展 Name 属性,则可以简化很多代码。哦,我撒谎了,这是最后一件事......你的 return 声明不在你的函数的有效部分。它需要类似于 END{ Return $arrayNew }

然后您只需添加一个不标记的例外帐户列表,或者添加一些逻辑等等。老实说,你的代码应该做几乎所有你想让它做的事,只需一点语法修复。这是基于您的脚本,它输出该组的所有成员并标记任何不是名称为 'Administrator' 的本地帐户并且不是列为 OK 的域帐户(在 BEGIN 部分,目前 "Domain Admins" 或 "Workstation Admin").

function get-localgroupmember {
  [CmdletBinding()]
  param(
    [Parameter(Mandatory=$True,HelpMessage="Enter PC")]
    [string[]]$computername
  )

  BEGIN {
    Add-Type -AssemblyName System.DirectoryServices.AccountManagement
    $ctype = [System.DirectoryServices.AccountManagement.ContextType]::Machine
    $OKAccounts = ("Workstation Admin","Domain Admins" | ForEach{[regex]::Escape($_)}) -join "|"
  }

  PROCESS{
    foreach ($computer in $computername) {
      If (Test-Connection -ComputerName $computer -Quiet -Count 1) {
        try {
          $context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $ctype, $computer
          $idtype = [System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName
          $group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($context, $idtype, 'Administrators')

          $group.Members | select @{N='Server'; E={$computer}}, @{N='Domain'; E={$_.Context.Name}}, samaccountName, @{N='Flag';E={If(!(($_.Context.Name -eq $Computer -and $_.samaccountname -match "Administrator") -or ($_.context.name -ne $Computer -and $_.samaccountname -match $OKAccounts))){"X"}}}

        } catch {
          [pscustomobject] @{
            Server = $computer
            Domain = "Error"
            SamAccountName = "Error"
            Flag = ''
          }
        }
      } else {
          [pscustomobject] @{
            Server = $computer
            Domain = "Off-Line"
            SamAccountName = "Off-Line"
            Flag = ''
          }
      } 

    } # end foreach
  } # end PROCESS

}

$date = [DateTime]::Today.AddDays(-1)

$allComputers = Get-ADComputer -Filter  'PasswordLastSet -ge $date' -properties PasswordLastSet | select -Expand Name
#$allComputers = $env:COMPUTERNAME
get-localgroupmember -computername $allComputers | Out-GridView

那应该给你这样的输出:

Server         Domain                     SamAccountName             Flag
------         ------                     --------------             ----
TMTsLab        TMTsLab                    Administrator                  
TMTsLab        TMTsTacoTruck.com          Domain Admins                  
TMTsLab        TMTsTacoTruck.com          SomeAcct1                  X   
TMTsLab        TMTsTacoTruck.com          SomeAcct2                  X   
TMTsLab        TMTsTacoTruck.com          TMTech                     X 

可能更好的方法是过滤掉您不需要的帐户,而不是不标记它们。因此,将 @{N='Flag';E={If(!(($_.Context.Name -eq $Computer -and $_.samaccountname -match "Administrator") -or ($_.context.name -ne $Computer -and $_.samaccountname -match $OKAccounts))){"X"}}} 位更改为 Where 语句,因此该行将是:

          $group.Members | select @{N='Server'; E={$computer}}, @{N='Domain'; E={$_.Context.Name}}, samaccountName | Where { !(($_.Server -eq $_.Domain -and $_.samaccountname -match "Administrator") -or ($_.Server -ne $_.Domain -and $_.samaccountname -match $OKAccounts)) }

您还需要从 CatchElse 脚本块中删除 Flag = '' 行。然后代码只有 returns 类似:

Server         Domain                     SamAccountName            
------         ------                     --------------            
TMTsLab        TMTsTacoTruck.com          SomeAcct1                   
TMTsLab        TMTsTacoTruck.com          SomeAcct2
TMTsLab        TMTsTacoTruck.com          TMTech  

当时的完整功能代码:

function get-localgroupmember {
  [CmdletBinding()]
  param(
    [Parameter(Mandatory=$True,HelpMessage="Enter PC")]
    [string[]]$computername
  )

  BEGIN {
    Add-Type -AssemblyName System.DirectoryServices.AccountManagement
    $ctype = [System.DirectoryServices.AccountManagement.ContextType]::Machine
    $OKAccounts = ("Workstation Admin","Domain Admins" | ForEach{[regex]::Escape($_)}) -join "|"
  }

  PROCESS{
    foreach ($computer in $computername) {
      If (Test-Connection -ComputerName $computer -Quiet -Count 1) {
        try {
          $context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $ctype, $computer
          $idtype = [System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName
          $group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($context, $idtype, 'Administrators')

          $group.Members | select @{N='Server'; E={$computer}}, @{N='Domain'; E={$_.Context.Name}}, samaccountName | Where{ !(($_.Server -ieq $_.Domain -and $_.samaccountname -match "Administrator") -or ($_.Server -ne $_.Domain -and $_.samaccountname -match $OKAccounts)) }

        } catch {
          [pscustomobject] @{
            Server = $computer
            Domain = "Error"
            Account = "Error"
          }
        }
      } else {
          [pscustomobject] @{
            Server = $computer
            Domain = "Off-Line"
            Account = "Off-Line"
          }
      } 

    } # end foreach
  } # end PROCESS

}