Usaré WMI para consultar en los servidores las membresías del grupo de administradores. Mi pregunta es: también quiero obtener el estado de la cuenta mediante una consulta WMI. Por cierto, no se requiere un estado para el grupo, como administradores de dominio, etc.
Mi resultado deseado:
"UserName","Fullname","Machinename","DomainName","Account Status"
"localuser","MACHINE\localuser","MACHINE","MACHINE","OK"
"Domain Admins","CONTOSO\Domain Admins","MACHINE","CONTOSO"
"domain_user_01","CONTOSO\domain_user_01","MACHINE","CONTOSO","Degraded"
Guión:
function get-localadministrators {
param ([string]$computername=$env:computername)
$computername = $computername.toupper()
$ADMINS = get-wmiobject -computername $computername -query "select * from win32_groupuser where GroupComponent=""Win32_Group.Domain='$computername',Name='administrators'""" | % {$_.partcomponent}
foreach ($ADMIN in $ADMINS) {
$admin = $admin.replace("\$computername\root\cimv2:Win32_UserAccount.Domain=","") # trims the results for a user
$admin = $admin.replace("\$computername\root\cimv2:Win32_Group.Domain=","") # trims the results for a group
$admin = $admin.replace('",Name="',"\")
$admin = $admin.REPLACE("""","")#strips the last "
$objOutput = New-Object PSObject -Property @{
Machinename = $computername
Fullname = ($admin)
DomainName =$admin.split("\")[0]
UserName = $admin.split("\")[1]
}#end object
$objreport+=@($objoutput)
}#end for
return $objreport
}#end function
¿Por qué utilizar WMI? ¿Qué versión del sistema operativo estás ejecutando? ¿Qué versión de PowerShell estás ejecutando? PSv5 y tiene cmdlets para administración local de usuarios y grupos. Hay un módulo en MS powershellgallery.com, que tiene un módulo que puede descargar para versiones anteriores de PowerShell.ns.
- postanota28 de marzo de 2021 a las 7:46
Tengo máquinas de 2003 y 2008.
Arbelac28 de marzo de 2021 a las 7:50
1
Vea mi respuesta para usted. Sin embargo, aunque puede hacer lo que está haciendo, esto realmente complica demasiado el caso de uso. puedes hacer estoEstá en una sola línea según mi respuesta proporcionada a continuación, que, por supuesto, puede convertirlo en una función si ese es su plan. Alguien más hizo exactamente esta pregunta en otro sitio de preguntas y respuestas, al que doy la misma respuesta. Entonces, ¿están ustedes dos en la misma empresa tratando de resolver el mismo caso de uso o en la misma clase/taller, y esto es tarea, ya que ambos tenían el mismo estilo de codificación y los mismos errores/problemas, o era usted el del otro sitio? ¿también?.... *** ;-}***
- postanota28 de marzo de 2021 a las 8:33
Continuación de mi comentario.
Puedes usar WMI o ADSI para hacer esto, pero PowerShell v5 y superiores ya tienen cmdlets para este caso de uso.
Todo lo siguiente utiliza los nombres de propiedad sin formato de las clases. Por supuesto, si desea un nombre diferente, puede usar una tabla hash, PSCustomObject o una propiedad calculada para hacerlo.
Get-Command -Module '*local*' |
Format-Table -AutoSize
# Results
<#
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Add-LocalGroupMember 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Disable-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Enable-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Get-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Get-LocalGroupMember 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Get-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet New-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet New-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Remove-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Remove-LocalGroupMember 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Remove-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Rename-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Rename-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Set-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Set-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
#>
Si tienes una versión de PS que no tiene esto de forma predeterminada, puedes obtener uno aquí:
Find-Module -Name '*local*' |
Format-Table -AutoSize
# Results
<#
Version Name Repository Description
------- ---- ---------- -----------
...
1.6 localaccount PSGallery A Simple module to allow the management of local users and groups on a computer
1.0.0.0 Microsoft.PowerShell.LocalAccounts PSGallery Provides cmdlets to work with local users and local groups
3.0 LocalUserManagement PSGallery a module that performs various local user management functions
1.3 LocalMachine PSGallery Simple management functions for accounts and settings on a local machine.
0.1.1 LocalAccountManagement PSGallery Manage local and remote user accounts and profiles
...
1.0.1 cLocalGroup PSGallery The cLocalGroup module contains the cLocalGroup DSC resource that provides a mecha...
2.1.0 ECS.LocalGPO PSGallery This Windows PowerShell module contains functions used for working with Windows lo...
...
#>
Si estás atascado con WMI, entonces...
Descubre con qué tienes que trabajar y las relaciones de clases asociadas
# Group Detail
Clear-Host
((Get-WmiObject -Class Win32_Group) -match 'Administrators')[0] |
Select-Object -Property '*'
<#
PSComputerName : 570A5E12-BA93-4
Status : OK
Name : Administrators
__GENUS : 2
__CLASS : Win32_Group
__SUPERCLASS : Win32_Account
__DYNASTY : CIM_ManagedSystemElement
__RELPATH : Win32_Group.Domain="570A5E12-BA93-4",Name="Administrators"
__PROPERTY_COUNT : 9
__DERIVATION : {Win32_Account, CIM_LogicalElement, CIM_ManagedSystemElement}
__SERVER : 570A5E12-BA93-4
__NAMESPACE : root\cimv2
__PATH : \570A5E12-BA93-4\root\cimv2:Win32_Group.Domain="570A5E12-BA93-4",Name="Administrators"
Caption : 570A5E12-BA93-4\Administrators
Description : Administrators have complete and unrestricted access to the computer/domain
Domain : 570A5E12-BA93-4
InstallDate :
LocalAccount : True
SID : S-1-5-32-544
SIDType : 4
...
#>
Get-WmiObject -Class Win32_Group |
Select-Object -Property Name, SIDType
# Results
<#
Name SIDType
---- -------
...
Administrators 4
...
Guests 4
...
Users 4
#>
# User Detail
Clear-Host
(Get-WmiObject -Class Win32_Account)[0] |
Select-Object -Property '*'
<#
PSComputerName : 570A5E12-BA93-4
Status : Degraded
Caption : 570A5E12-BA93-4\Administrator
PasswordExpires : False
__GENUS : 2
__CLASS : Win32_UserAccount
__SUPERCLASS : Win32_Account
__DYNASTY : CIM_ManagedSystemElement
__RELPATH : Win32_UserAccount.Domain="570A5E12-BA93-4",Name="Administrator"
__PROPERTY_COUNT : 16
__DERIVATION : {Win32_Account, CIM_LogicalElement, CIM_ManagedSystemElement}
__SERVER : 570A5E12-BA93-4
__NAMESPACE : root\cimv2
__PATH : \570A5E12-BA93-4\root\cimv2:Win32_UserAccount.Domain="570A5E12-BA93-4",Name="Administrator"
AccountType : 512
Description : Built-in account for administering the computer/domain
Disabled : True
Domain : 570A5E12-BA93-4
FullName :
InstallDate :
LocalAccount : True
Lockout : False
Name : Administrator
PasswordChangeable : True
PasswordRequired : True
SID : S-1-5-21-2047949552-857980807-821054962-500
SIDType : 1
...
#>
Get-WmiObject -Class Win32_Account |
Select-Object -Property Name, SIDType
# Results
<#
Name SIDType
---- -------
Administrator 1
DefaultAccount 1
Guest 1
WDAGUtilityAccount 1
Everyone 5
...
BUILTIN 3
...
Administrators 4
...
Guests 4
...
Users 4
#>
Lo siguiente le mostrará todos los usuarios y los grupos a los que pertenecen seleccionando primero al usuario, que es lo que muestra en su publicación, pero en realidad es una lógica de cortocircuito ya que solo está buscando usos en su consulta en Administradores. Entonces, esto...
Seleccione solo lo que necesita. Tenga en cuenta el enfoque con respecto al código SIDType comofiltro
Clear-Host
Get-WmiObject -Class Win32_Account |
Where-Object -Property SIDType -eq 1 |
Select-Object -Property PSComputerName, Name, Status,
@{
Name = 'Groups'
Expression = {($PSItem).GetRelated('Win32_Group').Name}
} |
Format-Table -AutoSize
# Results
<#
PSComputerName Name Status Groups
-------------- ---- ------ ------
570A5E12-BA93-4 Administrator Degraded Administrators
570A5E12-BA93-4 DefaultAccount Degraded System Managed Accounts Group
570A5E12-BA93-4 Guest Degraded Guests
570A5E12-BA93-4 WDAGUtilityAccount OK {Administrators, Remote Desktop Users}
#>
Por supuesto, puedes usar RegEx para deshacerte de los frenillos si eso es lo que te gusta. Por último, elimine la línea Where-Object, el filtro SIDType y lo obtendrá todo.
Clear-Host
Get-WmiObject -Class Win32_Account |
Select-Object -Property PSComputerName, Name, Status,
@{
Name = 'Groups'
Expression = {($PSItem).GetRelated('Win32_Group').Name}
} |
Format-Table -AutoSize
# Results
<#
PSComputerName Name Status Groups
-------------- ---- ------ ------
570A5E12-BA93-4 Administrator Degraded Administrators
570A5E12-BA93-4 DefaultAccount Degraded System Managed Accounts Group
570A5E12-BA93-4 Guest Degraded Guests
570A5E12-BA93-4 WDAGUtilityAccount OK {Administrators, Remote Desktop Users}
570A5E12-BA93-4 Everyone OK
...
570A5E12-BA93-4 NETWORK OK
570A5E12-BA93-4 BATCH OK
570A5E12-BA93-4 INTERACTIVE OK Users
...
570A5E12-BA93-4 SELF OK
570A5E12-BA93-4 Authenticated Users OK Users
570A5E12-BA93-4 RESTRICTED OK
...
570A5E12-BA93-4 IUSR OK IIS_IUSRS
...
#>
Revertir la solicitud --- Seleccione solo lo que necesita, SIDType no es necesario.
Clear-Host
Get-WmiObject -Class Win32_Group |
Select-Object -Property PSComputerName, Name, Status,
@{
Name = 'GroupMembers'
Expression = {
(
Get-WmiObject -Class win32_group |
Where Name -eq $PSItem.Name).GetRelated('Win32_UserAccount'
).Name
}
} |
Format-Table -AutoSize
# Results
<#
PSComputerName Name Status GroupMembers
-------------- ---- ------ ------------
570A5E12-BA93-4 Access Control Assistance Operators OK
570A5E12-BA93-4 Administrators OK {Administrator, WDAGUtilityAccount}
570A5E12-BA93-4 Backup Operators OK
570A5E12-BA93-4 Cryptographic Operators OK
570A5E12-BA93-4 Device Owners OK
570A5E12-BA93-4 Distributed COM Users OK
570A5E12-BA93-4 Event Log Readers OK
570A5E12-BA93-4 Guests OK Guest
570A5E12-BA93-4 Hyper-V Administrators OK
570A5E12-BA93-4 IIS_IUSRS OK
570A5E12-BA93-4 Network Configuration Operators OK
570A5E12-BA93-4 Performance Log Users OK
570A5E12-BA93-4 Performance Monitor Users OK
570A5E12-BA93-4 Power Users OK
570A5E12-BA93-4 Remote Desktop Users OK WDAGUtilityAccount
570A5E12-BA93-4 Remote Management Users OK
570A5E12-BA93-4 Replicator OK
570A5E12-BA93-4 System Managed Accounts Group OK DefaultAccount
570A5E12-BA93-4 Users OK
#>
Si PSRemoting (ya sea en modo dominio o grupo de trabajo) está configurado correctamente, acceder a sistemas remotos es sencillo.
# Target a remote computer
Clear-Host
Import-Csv -Path 'D:\Temp\ComputerList.csv' |
ForEach-Object {
Get-WmiObject -Class Win32_Account -ComputerName $PSitem.Name -Credential (Get-Credential -Credential WDAGUtilityAccount) |
Where-Object -Property SIDType -eq 1 |
Select-Object -Property PSComputerName, Name, Status,
@{
Name = 'Groups'
Expression = {($PSItem).GetRelated('Win32_Group').Name}
}
} |
Format-Table -AutoSize
# Results
<#
PSComputerName Name Status Groups
-------------- ---- ------ ------
570A5E12-BA93-4 Administrator Degraded Administrators
570A5E12-BA93-4 DefaultAccount Degraded System Managed Accounts Group
570A5E12-BA93-4 Guest Degraded Guests
570A5E12-BA93-4 TestUser OK Users
570A5E12-BA93-4 WDAGUtilityAccount OK {Administrators, Remote Desktop Users}
#>
En cuanto a tus detalles
<#
"UserName","Fullname","Machinename","DomainName","Account Status"
"localuser","MACHINE\localuser","MACHINE","MACHINE","OK"
"Domain Admins","CONTOSO\Domain Admins","MACHINE","CONTOSO"
"domain_user_01","CONTOSO\domain_user_01","MACHINE","CONTOSO","Degraded"
#>
# Only the administrators group
Clear-Host
Get-WmiObject -Class Win32_Account |
Where-Object -Property SIDType -eq 1 |
Select-Object -Property Name, Caption, PSComputerName, Domain, Status,
@{
Name = 'Groups'
Expression = {($PSItem).GetRelated('Win32_Group').Name}
} |
Where-Object -Property Groups -EQ 'Administrators'|
Format-Table -AutoSize
# Results
<#
Name Caption PSComputerName Domain Status Groups
---- ------- -------------- ------ ------ ------
Administrator 570A5E12-BA93-4\Administrator 570A5E12-BA93-4 570A5E12-BA93-4 Degraded Administrators
WDAGUtilityAccount 570A5E12-BA93-4\WDAGUtilityAccount 570A5E12-BA93-4 570A5E12-BA93-4 OK {Administrators, Remote Desktop Users}
#>
Clear-Host
Get-WmiObject -Class Win32_Group |
Select-Object -Property Name, Caption, PSComputerName, Domain, Status,
@{
Name = 'GroupMembers'
Expression = {
(
Get-WmiObject -Class win32_group |
Where Name -eq $PSItem.Name).GetRelated('Win32_UserAccount'
).Name
}
} |
Format-Table -AutoSize
# Results
<#
Name Caption PSComputerName Domain Status GroupMembers
---- ------- -------------- ------ ------ ------------
Access Control Assistance Operators 570A5E12-BA93-4\Access Control Assistance Operators 570A5E12-BA93-4 570A5E12-BA93-4 OK
Administrators 570A5E12-BA93-4\Administrators 570A5E12-BA93-4 570A5E12-BA93-4 OK {Administrator, WDAGUtilityAccount}
...
#>
# Only the administrators group
Clear-Host
Get-WmiObject -Class Win32_Group |
Where-Object -Property Name -eq 'Administrators' |
Select-Object -Property Name, Caption, PSComputerName, Domain, Status,
@{
Name = 'GroupMembers'
Expression = {
(
Get-WmiObject -Class win32_group |
Where Name -eq $PSItem.Name).GetRelated('Win32_UserAccount'
).Name
}
} |
Format-Table -AutoSize
# Results
<#
Name Caption PSComputerName Domain Status GroupMembers
---- ------- -------------- ------ ------ ------------
Administrators 570A5E12-BA93-4\Administrators 570A5E12-BA93-4 570A5E12-BA93-4 OK {Administrator, WDAGUtilityAccount}
#>
Actualiza según tu comentario.
En cuanto a esto...
¿Puedo escribir a través de la clase .NET de servicios de directorio en lugar de WMI?
Claro que puedes, como se detalla aquí...
https://devblogs.microsoft.com/scripting/the-admins-first-steps-local-group-membership
... pero usar esto no le devuelve el resultado que enumera.
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$ctype = [System.DirectoryServices.AccountManagement.ContextType]::Machine
$context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $ctype, $env:COMPUTERNAME
$idtype = [System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName
$group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($context, $idtype, ‘Administrators’)
$group.Members |
Select-Object -Property '*' -First 1
# Results
<#
GivenName :
MiddleName :
Surname :
EmailAddress :
VoiceTelephoneNumber :
EmployeeId :
AdvancedSearchFilter : System.DirectoryServices.AccountManagement.AdvancedFilters
Enabled : False
AccountLockoutTime :
LastLogon :
PermittedWorkstations : {}
PermittedLogonTimes : {255, 255, 255, 255...}
AccountExpirationDate :
SmartcardLogonRequired : False
DelegationPermitted : True
BadLogonCount : 0
HomeDirectory :
HomeDrive :
ScriptPath :
LastPasswordSet : 3/28/2021 10:20:29 AM
LastBadPasswordAttempt :
PasswordNotRequired : False
PasswordNeverExpires : True
UserCannotChangePassword : False
AllowReversiblePasswordEncryption : False
Certificates : {}
Context : System.DirectoryServices.AccountManagement.PrincipalContext
ContextType : Machine
Description : Built-in account for administering the computer/domain
DisplayName :
SamAccountName : Administrator
UserPrincipalName :
Sid : S-1-5-21-2047949552-857980807-821054962-500
Guid :
DistinguishedName :
StructuralObjectClass :
Name : Administrator
#>
7
gracias, Get-WmiObject -Class Win32_Group -ComputerName MÁQUINA | Donde-Objeto -Nombre de propiedad -eq 'Administradores' | Seleccionar-Objeto -Nombre de propiedad, Título, PSComputerName, Dominio, Estado, @{ Nombre = 'GroupMembers' Expresión = { ( Get-WmiObject -Class win32_group | Donde Nombre -eq $PSItem.Name).GetRelated('Win32_UserAccount' ).Name } } | Formato-Tabla -AutoSize
Arbelac28 de marzo de 2021 a las 8:33
No te preocupes. Ya actualicé mi respuesta para abordar las necesidades y el diseño de su propiedad en particular. Cuídate y mantente a salvo.
- postanota28 de marzo de 2021 a las 8:35
He probado un script de muestra en una máquina específica. pero tarda mucho en completarse. . ¿Es normal?
Arbelac28 de marzo de 2021 a las 8:36
Puede, ya que tiene que mirar no sólo cada clase sino cada objeto de la clase, luego filtrar cuál debe ser el resultado final y luego los formateadores lo toman antes de enviarlo a la pantalla o al archivo. Otras cosas afectan la velocidad, eso es todo ambiental. CPU, velocidad del disco, RAM, otros procesos en ejecución, etc. Por ejemplo, en mi sistema WIn10, esto solo toma unos segundos. Sin embargo, tengo 8 núcleos, 64 GB de RAM, todo SSD y estoy totalmente optimizado. Si terminas haciendo esto en máquinas remotas, tomará aún más tiempo, porque tiene que atravesar la red y el entorno del host remoto.configuración del entorno.
- postanota28 de marzo de 2021 a las 8:40
Entonces, ¿cómo puedo optimizar este script? Porque hay alrededor de 200 máquinas en nuestro entorno. Puede que tarde un siglo :) Por cierto, ¿tengo que usar GetRelated?
Arbelac28 de marzo de 2021 a las 9:07
Dijiste
¿Cómo puedooptimice este script, hay 200 máquinas, tomará un siglo...
... Entonces, ¿cómo puedo escribir a través de la clase .NET de servicios de directorio en lugar de WMI? ¿Es posible? Tienes alguna información sobre esto? – Arbelac hace 6 horas
Si realmente necesita ejecutar un comando en una gran cantidad de máquinas y tiene derechos de acceso remoto, puede consultar ForEach-Parallel o Invoke-Parallel, dos opciones diferentes para ejecutar un comando en varias máquinas.
Sin embargo, tendrás que lidiar con el estado remoto, como preocuparte por qué hacer si una máquina remota está fuera de línea, o qué pasa si no se puede acceder a una máquina cuando intentas comunicarte con ella.
Una alternativa más fácilYa tienes un entorno, bueno, pensemos en otras formas de lograr el mismo objetivo.
En su lugar, podrías utilizarPolítica de grupo para ejecutar este comando localmente en cada máquina como un script de inicio de sesión. Luego, las máquinas pueden escribir su salida en un archivo Json o Csv en algún recurso compartido central, tal vez ADFS si lo tiene.
También puede utilizar cualquier agente remoto que haya instalado en las máquinas, como System Center Configuration Manager, Shalvik o cualquiera de las otras aplicaciones que pueda tener.
Para resumir mi respuesta, puedes hacer esto con PowerShell Remoting, pero empieza a parecer que eso te causará problemas y quizás quieras pensar en distribuir el trabajo usando algún otro sistema.
Fuente: fue administrador de sistemas e ingeniero de automatización durante años. Probablemente no usaría la comunicación remota de PowerShell de esta manera.