Artifacts/windows-add-local-admin/artifact.ps1 (139 lines of code) (raw):
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[string] $DomainJoinUsername
)
##############################
# Function returns the localized group name for the local administrator group
function Get-LocalAdminGroupName ()
{
#well known SID for the Administrators group
return ([wmi]"Win32_SID.SID='S-1-5-32-544'").AccountName
}
#############################
# Function to find the members of a local machine group, usually administrators.
# Works around the cahnge in call pattern InvokeMember
function Get-LocalGroupMembersPs3to5 ()
{
param
(
[Parameter(Mandatory = $true)]
[string] $GroupName
)
if ($PSVersionTable.PSVersion.Major -gt 4)
{
throw "This method id not supported on powershell 5 and greater"
}
$group = [ADSI]("WinNT://$env:COMPUTERNAME/$GroupName, group");
$members = @($group.psbase.Invoke("Members"));
$Details = @();
$members | ForEach-Object {
$name = $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
$path = $_.GetType().InvokeMember("ADsPath", 'GetProperty', $null, $_, $null)
$schema = $_.GetType().InvokeMember("Schema", 'GetProperty', $null, $_, $null)
if ($schema -notlike "WinNT://$name/*")
{
$Type = "Domain"
if ($path -like "*/$env:COMPUTERNAME/*")
{
$Type = "Local"
}
$Details += New-Object PSObject -Property @{"Account" = $name; "Type" = $type; }
}
}
return $Details
}
##############################
# Function to find the members of a local machine group, usually administrators
function Get-LocalGroupMembers ()
{
param
(
[Parameter(Mandatory = $true)]
[string] $GroupName
)
if ($PSVersionTable.PSVersion.Major -lt 5)
{
return Get-LocalGroupMembersPs3to5 $GroupName
}
$group = [ADSI]("WinNT://$env:COMPUTERNAME/$GroupName, group");
$members = @($group.psbase.Invoke("Members"));
$Details = @();
$members | ForEach-Object {
$name = $_.GetType.Invoke().InvokeMember("Name", 'GetProperty', $null, $_, $null)
$path = $_.GetType.Invoke().InvokeMember("ADsPath", 'GetProperty', $null, $_, $null)
$schema = $_.GetType.Invoke().InvokeMember("Schema", 'GetProperty', $null, $_, $null)
if ($schema -notlike "WinNT://$name/*")
{
$Type = "Domain"
if ($path -like "*/$env:COMPUTERNAME/*")
{
$Type = "Local"
}
$Details += New-Object PSObject -Property @{"Group" = $GroupName; "Account" = $name; "Type" = $type; }
}
}
return $Details
}
##############################
# Function to get the AD User string in format "WinNT://<domain>/<username>"
function Get-AdUsernameString ()
{
param
(
[Parameter(Mandatory = $true)]
[string] $UserName
)
if ([string]::IsNullOrEmpty($Username))
{
throw "Username not provided"
}
if ($Username -notmatch '\\')
{
$ADResolved = ($Username -split '@')[0]
$DomainResolved = ($Username -split '@')[1]
}
else
{
$ADResolved = ($Username -split '\\')[1]
$DomainResolved = ($Username -split '\\')[0]
}
$Username = "WinNT://$DomainResolved/$ADResolved"
return $Username
}
##############################
# Function to add an AD user to a local group
function Add-UserToLocalGroup ()
{
param
(
[Parameter(Mandatory = $true)]
[string] $Username,
[Parameter(Mandatory = $true)]
[string] $GroupName
)
Write-Output "Attempting to add $DomainJoinUsername to the administrators group..."
$adUser = Get-AdUsernameString $Username
$group = [ADSI]("WinNT://$env:COMPUTERNAME/$GroupName, group")
if ($group.IsMember($adUser))
{
Write-Output "Result: $Username already belongs to the $GroupName"
return
}
$group.Add($adUser)
if ($group.IsMember($adUser))
{
Write-Output "Result: $Username successfully added to $GroupName"
}
else
{
Write-Error "Result: failed to add $username to $GroupName"
}
}
##############################
# Main function
$adminGroupName = Get-LocalAdminGroupName
Add-UserToLocalGroup -Username $DomainJoinUsername -GroupName $adminGroupName
Write-Output "Members of $adminGroupName are:"
Get-LocalGroupMembers $adminGroupName