#region Function Add-ToLocalGroup
Function Add-ToLocalGroup {
<#
.SYNOPSIS
Adds users or Groups to Local Computer groups
.DESCRIPTION
Adds users or Groups to Local Computer groups (tested for Local Computer groups. Might also work for AD groups)
Can also specify a SID for the Local Computer group
Will NOT create group
.PARAMETER DomainAndAccountToAdd
The Windows NT Account name you want to add specified in <domain>/<username> format.
Use fully qualified account names (e.g., <domain>/<username>) instead of isolated names (e.g, <username>) because they are unambiguous and provide better performance.
CAVEAT: If you use -DomainAndAccountToAdd and -DomainAndGroupToAdd at the same time, Only -DomainAndGroupToAdd will be used
.PARAMETER DomainAndGroupToAdd
The Windows NT GROUP name you want to add specified in <domain>/<username> format.
Use fully qualified account names (e.g., <domain>/<username>) instead of isolated names (e.g, <username>) because they are unambiguous and provide better performance.
.PARAMETER TargetDomainAndGroup
The Windows NT GROUP name specified in <domain>/<username> format that will get new members
Use fully qualified account names (e.g., <domain>/<username>) instead of isolated names (e.g, <username>) because they are unambiguous and provide better performance.
CAVEAT: If you use -TargetDomainAndGroup and -TargetSID at the same time, Only -TargetSID will be used
.PARAMETER TargetSID
The Windows SID of the Windows NT GROUP name that will get new members
Specifying SIDs is best when dealing with multilingual environments
"Remote Desktop Users" = S-1-5-32-555 = "Utilisateurs du Bureau à distance"
.EXAMPLE
Add-ToLocalGroup -DomainAndGroupToAdd 'SIGNET/Domain Users' -TargetDomainAndGroup "$($env:COMPUTERNAME)/Remote Desktop Users"
.EXAMPLE
Add-ToLocalGroup -DomainAndGroupToAdd 'SIGNET/Domain Users' -TargetDomainAndGroup "./Remote Desktop Users"
.EXAMPLE
Add-ToLocalGroup -DomainAndAccountToAdd 'SIGNET/stpierdj' -TargetDomainAndGroup "./Remote Desktop Users"
.EXAMPLE
Add-ToLocalGroup -DomainAndAccountToAdd 'SIGNET/stpierdj' -TargetDomainAndGroup "./Remote Desktop Users"
.EXAMPLE
Add-ToLocalGroup -DomainAndGroupToAdd 'SIGNET/Domain Users' -TargetSID 'S-1-5-32-555' #"Remote Desktop Users"
.NOTES
Author: Denis St-Pierre (Ottawa, Canada)
TODO: redo Error handling
.LINK
List of Well Known SIDs: http://msdn.microsoft.com/en-us/library/system.security.principal.wellknownsidtype(v=vs.110).aspx
#>
[CmdletBinding()]
Param (
[Parameter(Mandatory=$false,HelpMessage="<Domain>/<UserName>")]
[ValidateNotNullorEmpty()]
[String]$DomainAndAccountToAdd, #Need to test for Forward Slash, if no slash at all, add current domain
[Parameter(Mandatory=$false,HelpMessage="<Domain>/<GroupName>")]
[ValidateNotNullorEmpty()]
[String]$DomainAndGroupToAdd, #Need to test for Forward Slash, if no slash at all, add current domain
[Parameter(Mandatory=$false,HelpMessage="./<LocalGroupName> or <Domain>/<GroupName>")]
[ValidateNotNullorEmpty()]
[String]$TargetDomainAndGroup,
[Parameter(Mandatory=$false,HelpMessage="Windows SID of the Windows NT GROUP name that will get new members")]
[ValidateNotNullorEmpty()]
[String]$TargetSID, #S-1-5-32-555
[Parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[boolean]$ContinueOnError = $true
)
Begin {
## Get the name of this function and write header
[string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name
Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -CmdletBoundParameters $PSBoundParameters -Header
}
Process {
If ($TargetSID) {
Write-Log "Translating SID [$TargetSID] to OS language specific Account or Group Name" -Source ${CmdletName}
$objSID = New-Object System.Security.Principal.SecurityIdentifier($TargetSID)
$objName = $objSID.Translate( [System.Security.Principal.NTAccount])
[String]$TargetDomainAndGroup = $objName.Value #e.g. BUILTIN\Remote Desktop Users
$TargetDomainAndGroup = $TargetDomainAndGroup.Replace('\','/') # flip \ to Forward slash (/) for WinNT://
$TargetDomainAndGroup = $TargetDomainAndGroup.Replace('BUILTIN/',"$($env:COMPUTERNAME)/") # flip BUILTIN to %COMPUTERNAME% for WinNT://
}
#NOTE: [ADSI] hates adding already existing members, so we check first.
$TargetGroupObj = [ADSI]("WinNT://$TargetDomainAndGroup,group")
Write-Log "Getting members of the [$TargetDomainAndGroup] Group" -Source ${CmdletName}
$MembersOfTargetGroupObj = @($TargetGroupObj.psbase.Invoke("Members")) #Create Array of members SLOW?!
#$MembersOfTargetGroupObj.GetType() | Get-Member # Show all member properties
Write-Log "Getting Group Member NAMES..." -Source ${CmdletName}
Try {
$MemberNames = @($MembersOfTargetGroupObj | foreach {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)})
} catch {
[string]$ErrorMessage = "$($_.Exception.Message) $($_.ScriptStackTrace) $($_.Exception.InnerException)"
Write-Log $ErrorMessage -Severity 3 -Source ${CmdletName}
Write-Log " ERROR while getting names of each group member. `r`n[$ErrorMessage]" -Severity 3 -Source ${CmdletName}
If ($ContinueOnError) {
Return $null
} else {
[string]$ErrorMessage = "$($_.Exception.Message) $($_.ScriptStackTrace) $($_.Exception.InnerException)"
Write-Log $ErrorMessage -Severity 3 -Source ${CmdletName}
Throw "ERROR while getting names of each group member. `r`n[$ErrorMessage]"
}
}
If ($DomainAndAccountToAdd) { #Adding a user account to the Group
$AccountToAdd = $DomainAndAccountToAdd.Substring($DomainAndAccountToAdd.IndexOf('/')+1) #Right() +1
If ($MemberNames -contains $AccountToAdd) {
Write-Log " [$AccountToAdd] is already a member of [$TargetDomainAndGroup] group" -Severity 2 -Source ${CmdletName}
} Else {
Write-Log " Adding Account [$AccountToAdd] to [$TargetDomainAndGroup] group" -Source ${CmdletName}
Try {
$TargetGroupObj.add("WinNT://$DomainAndAccountToAdd,user").path #CAVEAT: Forward slash (/) (Opposite of GUI and VBS)
Write-Log " Success." -Source ${CmdletName}
} Catch {
[string]$ErrorMessage = "$($_.Exception.Message) $($_.ScriptStackTrace) $($_.Exception.InnerException)"
Write-Log $ErrorMessage -Severity 3 -Source ${CmdletName}
Write-Log " ERROR: adding account [$AccountToAdd] failed. `r`n[$ErrorMessage]" -Severity 3 -Source ${CmdletName}
If ($ContinueOnError) {
Return $null
} else {
Throw "ERROR: adding account [$AccountToAdd] failed. `r`n[$ErrorMessage]"
}
}
}
} Else { #Adding a Group to the Group
$GroupToAdd = $DomainAndGroupToAdd.Substring($DomainAndGroupToAdd.IndexOf('/')+1) #Right() +1
If ($MemberNames -contains $GroupToAdd) {
Write-Log " [$GroupToAdd] is already a member of [$TargetDomainAndGroup] group" -Severity 2 -Source ${CmdletName}
} Else {
Write-Log " Adding Group [$GroupToAdd] to [$TargetDomainAndGroup] group" -Source ${CmdletName}
Try {
# $TargetGroupObj.add("WinNT://$DomainAndGroupToAdd,group").path #WORKS! Forward slash in PowerShell (Opposite of GUI and VBS)
$adgroup = [ADSI]"WinNT://$DomainAndGroupToAdd" #"corp.domain.com/$admingroup"
$TargetGroupObj = [ADSI]"WinNT://$TargetDomainAndGroup" #"$server/Administrators"
$TargetGroupObj.PSBase.Invoke("Add",$adgroup.PSBase.Path) #Need to be Elevated to do this!
Write-Log " Success." -Source ${CmdletName}
} Catch {
[string]$ErrorMessage = "$($_.Exception.Message) $($_.ScriptStackTrace) $($_.Exception.InnerException)"
Write-Log $ErrorMessage -Severity 3 -Source ${CmdletName}
Write-Log " ERROR: adding Group [$GroupToAdd] failed. `r`n[$ErrorMessage]" -Severity 3 -Source ${CmdletName}
If ($ContinueOnError) {
Return $null
} Else {
Throw "ERROR: adding Group [$GroupToAdd] failed. `r`n[$ErrorMessage]"
}
}
}
}
}
End {
Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -Footer
}
}
#endregion Function Add-ToLocalGroup