134 lines
5.3 KiB
PowerShell
134 lines
5.3 KiB
PowerShell
#Requires -Version 5.1
|
|
[CmdletBinding(SupportsShouldProcess)]
|
|
param()
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$userName = 'alumno'
|
|
$plainTextPassword = 'ingenieria'
|
|
$description = 'Cuenta local estandar SGU para recuperacion'
|
|
$passwordNeverExpiresFlag = 0x10000
|
|
|
|
function Get-LocalUserFlags {
|
|
param([Parameter(Mandatory)][string]$Name)
|
|
|
|
$directoryEntry = [ADSI]("WinNT://$env:COMPUTERNAME/$Name,user")
|
|
return [int]$directoryEntry.InvokeGet('UserFlags')
|
|
}
|
|
|
|
function Get-LocalGroupMemberSid {
|
|
param([Parameter(Mandatory)][string]$Name)
|
|
|
|
$group = [ADSI]("WinNT://$env:COMPUTERNAME/$Name,group")
|
|
foreach ($member in @($group.psbase.Invoke('Members'))) {
|
|
try {
|
|
$sidBytes = $member.GetType().InvokeMember(
|
|
'objectSid',
|
|
[Reflection.BindingFlags]::GetProperty,
|
|
$null,
|
|
$member,
|
|
$null)
|
|
if ($sidBytes) {
|
|
([Security.Principal.SecurityIdentifier]::new([byte[]]$sidBytes, 0)).Value
|
|
}
|
|
}
|
|
catch {
|
|
# An orphaned domain SID can no longer resolve after a forest is
|
|
# rebuilt. Other members must remain inspectable and unchanged.
|
|
}
|
|
}
|
|
}
|
|
|
|
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
|
$principal = [Security.Principal.WindowsPrincipal]::new($identity)
|
|
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
|
throw 'Run this script from an elevated Windows PowerShell session.'
|
|
}
|
|
|
|
if (-not $PSCmdlet.ShouldProcess($env:COMPUTERNAME, "Create or update standard local user $userName")) {
|
|
return
|
|
}
|
|
|
|
$securePassword = ConvertTo-SecureString $plainTextPassword -AsPlainText -Force
|
|
try {
|
|
$user = Get-LocalUser -Name $userName -ErrorAction SilentlyContinue
|
|
if ($user -and $user.SID.Value.EndsWith('-500', [StringComparison]::Ordinal)) {
|
|
throw "The local account '$userName' is the built-in Administrator account and cannot be converted to a standard user."
|
|
}
|
|
|
|
if ($user) {
|
|
# Preserve existing credentials on enrollment/repair. Resetting the same
|
|
# password after domain join can violate password history/complexity.
|
|
Set-LocalUser -Name $userName `
|
|
-PasswordNeverExpires $true `
|
|
-Description $description
|
|
if (-not $user.Enabled) {
|
|
Enable-LocalUser -Name $userName
|
|
}
|
|
}
|
|
else {
|
|
New-LocalUser -Name $userName `
|
|
-Password $securePassword `
|
|
-PasswordNeverExpires `
|
|
-Description $description | Out-Null
|
|
}
|
|
|
|
# Windows 10's Get-LocalUser object has PasswordExpires but does not expose
|
|
# PasswordNeverExpires. Enforce and verify the underlying UF_DONT_EXPIRE_PASSWD
|
|
# flag so the result is consistent across Windows 10 and Windows 11.
|
|
$directoryEntry = [ADSI]("WinNT://$env:COMPUTERNAME/$userName,user")
|
|
$userFlags = [int]$directoryEntry.InvokeGet('UserFlags')
|
|
if (($userFlags -band $passwordNeverExpiresFlag) -eq 0) {
|
|
$directoryEntry.InvokeSet('UserFlags', ($userFlags -bor $passwordNeverExpiresFlag))
|
|
$directoryEntry.CommitChanges()
|
|
}
|
|
|
|
$user = Get-LocalUser -Name $userName -ErrorAction Stop
|
|
$administratorsSid = [Security.Principal.SecurityIdentifier]::new('S-1-5-32-544')
|
|
$usersSid = [Security.Principal.SecurityIdentifier]::new('S-1-5-32-545')
|
|
$administratorsGroup = Get-LocalGroup -SID $administratorsSid -ErrorAction Stop
|
|
$usersGroup = Get-LocalGroup -SID $usersSid -ErrorAction Stop
|
|
$administratorMembers = @(Get-LocalGroupMemberSid -Name $administratorsGroup.Name)
|
|
if ($administratorMembers -contains $user.SID.Value) {
|
|
([ADSI]("WinNT://$env:COMPUTERNAME/$($administratorsGroup.Name),group")).Remove(
|
|
"WinNT://$env:COMPUTERNAME/$userName,user")
|
|
}
|
|
|
|
$standardMembers = @(Get-LocalGroupMemberSid -Name $usersGroup.Name)
|
|
if ($standardMembers -notcontains $user.SID.Value) {
|
|
([ADSI]("WinNT://$env:COMPUTERNAME/$($usersGroup.Name),group")).Add(
|
|
"WinNT://$env:COMPUTERNAME/$userName,user")
|
|
}
|
|
}
|
|
finally {
|
|
$securePassword = $null
|
|
}
|
|
|
|
$verifiedUser = Get-LocalUser -Name $userName -ErrorAction Stop
|
|
$verifiedAdministratorsGroup = Get-LocalGroup `
|
|
-SID ([Security.Principal.SecurityIdentifier]::new('S-1-5-32-544')) `
|
|
-ErrorAction Stop
|
|
$verifiedUsersGroup = Get-LocalGroup `
|
|
-SID ([Security.Principal.SecurityIdentifier]::new('S-1-5-32-545')) `
|
|
-ErrorAction Stop
|
|
$verifiedAdministrators = @(Get-LocalGroupMemberSid -Name $verifiedAdministratorsGroup.Name)
|
|
$verifiedUsers = @(Get-LocalGroupMemberSid -Name $verifiedUsersGroup.Name)
|
|
if ($verifiedAdministrators -contains $verifiedUser.SID.Value) {
|
|
throw "The local account '$userName' still belongs to the local Administrators group."
|
|
}
|
|
if ($verifiedUsers -notcontains $verifiedUser.SID.Value) {
|
|
throw "The local account '$userName' does not belong to the local Users group."
|
|
}
|
|
$verifiedPasswordNeverExpires =
|
|
((Get-LocalUserFlags -Name $userName) -band $passwordNeverExpiresFlag) -ne 0
|
|
if (-not $verifiedPasswordNeverExpires) {
|
|
throw "The local account '$userName' password is not configured to never expire."
|
|
}
|
|
|
|
[pscustomobject]@{
|
|
UserName = $verifiedUser.Name
|
|
Enabled = $verifiedUser.Enabled
|
|
IsAdministrator = $false
|
|
IsStandardUser = $true
|
|
PasswordNeverExpires = $verifiedPasswordNeverExpires
|
|
}
|