列出除域管理员和本地管理员之外的所有本地管理员帐户
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)) }
您还需要从 Catch
和 Else
脚本块中删除 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
}
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)) }
您还需要从 Catch
和 Else
脚本块中删除 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
}