resolve ForeignSecurityPrincipals to distinguishedName in PowerShell - powershell

I have a ForeignSecurityPrincipals and need to resolve it to the distinguishedName but am not sure how.
I have this code to get the NTAccount:
$m = "CN=S-1-1-11-1111111111-1111111111-1111111111-1111111,CN=ForeignSecurityPrincipals,DC=one,DC=two,DC=company,DC=com"
$member = [ADSI]("LDAP://" + $m)
$sid = New-Object System.Security.Principal.SecurityIdentifier ($member.objectSid[0], 0)
$sid.Translate([System.Security.Principal.NTAccount]).value

You can bind to an object using the SID (and then get the distinguishedName), but you have to know at least the DNS name of the domain:
$user = [ADSI]"LDAP://$domaindns/<SID=$($sid.Value)>"
To get the DNS name of the domain, you need to examine all the trusts your domain has and store the DNS name and the SID of the domain in a list. Then you can match the domain portion of the user's SID with your list and get the DNS name (a user's SID will start with the domain's SID).
This page has some info on pulling all of the trusts, but the method he ends up using is WMI, which may not work, depending on your permissions. It didn't for me. You can do the same with ADSI, but I haven't done it. It's a starting point at least.
Update:
You can try this:
$DomainSIDList = #{}
$Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
#Get trusts from each domain in the forest -- this will include forest trusts
ForEach($Domain in $Forest.Domains) {
$adsisearcher = New-Object system.directoryservices.directorysearcher
$adsisearcher.SearchRoot = [ADSI]"LDAP://CN=System,$($Domain.GetDirectoryEntry().distinguishedName)"
$adsisearcher.Filter = "(objectclass=trustedDomain)"
ForEach($ExtDomain in $adsisearcher.FindAll()) {
$name = $ExtDomain.Properties["name"][0]
"Found $($name)"
$sid = New-Object System.Security.Principal.SecurityIdentifier ($ExtDomain.Properties["securityidentifier"][0], 0)
if (-not $DomainSIDList.Contains($sid.Value)) {
"Adding $($sid.Value), $($name)"
$DomainSIDList.Add($sid.Value, $name)
}
}
}
Once that runs, $DomainSIDList will contain a list of trusted domains. It'll contain all the domains in the forest, which you don't really need, but that's not a big deal.

Related

Grabbing assigned VM names by entering username in Vmware Horizon (PowerCLI)

I've been working on a PowerShell code to grab VM names from all desktop pools.
I'm using PowerCLI with PowerShell 7 installed.
I have managed to get an output of all the users and their assigned machines. But, I'm having difficulties in optimizing the code in a way that I can input a single user name and it will only show me that user's assigned VM.
Here is the code I've got so far
#Import-Module VMware.VimAutomation.Core
#Import-Module Activedirectory
Connect-VIServer -server servername123 -Force
Connect-HVServer -server server.name.123
$uname = Read-Host -Prompt 'Input the user name you wish to find:' #User-Input
$Global:DefaultHVServers
$query = New-Object "Vmware.Hv.QueryDefinition"
$query.queryEntityType = 'SessionLocalSummaryView'
$qSrv = New-Object "Vmware.Hv.QueryServiceService"
$PCs = ($qSRv.QueryService_Query($global:DefaultHVServers[0].ExtensionData,$query) |
Select -ExpandProperty Results |
Select -ExpandProperty NamesData |
Select-Object -Property UserName,MachineOrRDSServerName)
$PCs | % {"$($_.UserName.Split("\")[1]) `t`t $($_.MachineOrRDSServerName) "}
In the last line of the code, I am formatting the table to remove unnecessary content.
$PCs | % {"$($_.UserName.Split("\")[1]) `t`t $($_.MachineOrRDSServerName) "}
Can someone help me in grabbing username from console and only displaying the VMs that they are assigned to?
I have tried googling for a solution but couldn't find anything relevant.
Thanks!!
Note: I have declared a variable uname but haven't used it yet. I'm unsure how can I use it in this usecase.
After digging around more in the deepest subreddits, I found a post that solved my question.
https://www.reddit.com/r/vmware/comments/d547nt/horizon_view_powercli_help/
Below is the code which utilizes QueryFilterEquals
from VMware.Hv.Equals class to grab usernames and their properties.
I'm skipping the connections portion of the code, it is the same mentioned in the question.
#Get User Input for UserName
$UserName = Read-Host -Prompt 'Input the user name you wish to find:'
#Create Horizon Services object
$HorizonServerServices = $global:DefaultHVServers[0].ExtensionData
#Create Query Definition object with EntityType SessionLocalSummaryView
$HorizonQuery = New-Object VMware.Hv.QueryDefinition
$HorizonQuery.QueryEntityType = 'SessionLocalSummaryView'
#Create Query Filter Object
$QueryFilterEquals = New-Object VMware.Hv.QueryFilterEquals
$QueryFilterEquals.MemberName = 'namesData.userName'
$QueryFilterEquals.value = "domain.loc\$UserName"
$HorizonQuery.Filter = $QueryFilterEquals
$HorizonQueryService = New-Object VMware.Hv.QueryServiceService
$SearchResult = $HorizonQueryService.QueryService_Query($HorizonServerServices, $HorizonQuery)
if ($SearchResult.Results)
{
$SearchResult.Results.Namesdata
}
We do not have to delete the query at the end as it doesn't consume any server-side resources. It is a virtual query. Refer to the link given below for detailed info on how QueryService works.
Refer to: https://vdc-download.vmware.com/vmwb-repository/dcr-public/e2e25628-4ed2-43fc-8bad-54fb86f3bb0f/8e4d2491-c740-4778-ac43-ba8fc0ec8175/doc/queries-landing.html

Display domain information using Powershell

How can I display the domain, name and site (and nothing else) of all domain controllers using a single PowerShell command?
I've tried Get-ADDomainController cmdlet, but I only seem to get the local domaincontroller and not the information of my second server.
$getdomain = [System.Directoryservices.Activedirectory.Domain]::GetCurrentDomain()
$getdomain | ForEach-Object {$_.DomainControllers} |
ForEach-Object {
$hEntry= [System.Net.Dns]::GetHostByName($_.Name)
New-Object -TypeName PSObject -Property #{
Forest = $_.Forest
Name = $_.Name
IPAddress = $hEntry.AddressList[0].IPAddressToString
}
}
Source: https://gallery.technet.microsoft.com/scriptcenter/Get-List-of-Domain-4c993070

Check for user in a group in a different domain

I am stuck with a piece of code.
We have 2 AD domains with users and groups in them.
I am trying to run a script that will check if the user is a member of a group to disable EV access and if they are not a member of that group add them to the EV enable group.
I have this working for 1 domain but I can't get it to work across the 2 domains we have.
I want the script to check domain1 and add it to the group in domain1 but if it doesn't find the user check domain2 and add it to the group in domain2.
Below is an extract of the code I have but I am struggling to get it to recognise the domain controller so that it looks in the right domain for the user.
foreach ($u in $Users){
Foreach($domain in $Domainlist)
{
$dom =get-addomain $domain.name
$dm = $dom.distinguishedname
$dname = $dom.name
$DomName = $dom.DNSRoot
$ADdc = Get-addomaincontroller -discover -domain $domName
$dc = $ADdc.hostname
$User = Get-ADUser $u.name -server $dc
$Enablegroup = "cn=evenable,ou=users and computers," + $dom
$disablegroup = "cn=evdisable,ou=users and computers," + $dom
if ((Get-ADUser $u.name -server $dc -Properties memberof).memberof -eq $disablegroup)
{
$name = $u.name
$dm = $domain.name
Write-host "$name is a member of the $dm EV disable group" -f Yellow
}
This is not hard at all!
Basically we just replace one line with the following, and we use PowerShell's try/catch syntax. Try this first chunk of code, if you have an error, then do the second part instead.
From
$User = Get-ADUser $u.name -server $dc
To
try{ $User = Get-ADUser $u.name -server $dc -ErrorAction STOP}
catch {$User = Get-ADUser $u.name -server OtherDC -ErrorAction STOP
$dom =get-addomain OtherDomain}
The whole goal of a structure like this is to handle the branching logic of try this/if it fails, do this instead, and ensure that the script will keep running after that point. So, because you're using $dom in the later part of the script to resolve the full path of the Security Group, you also need to change the $dom value in the Catch block, as I've done above.
Just tweak these values as appropriate for your domain and it should just work. I used an approach very similar to this for a task of my own, and Try/Catch/Finally was exactly the tool to get the job done.

Adding members to local groups by SID in multiple languages

I'm new to powershell/scripting/life in general, but finally I got a problem that is worthy of asking for help:
I've various Windows localizations in environment - English, Finnish and Russian in current environment, but with possibilities to have other Scandinavian/European localizations. I need to add Authenticated users to Administrators group. I can script it in English:
NET LOCALGROUP Administrators "Authenticated Users" /add,
but I won't know all localized names. For example, in Russian it would be "Administratori" and "Proshedshie Proverku." In cyrilic, that I'm not that strong with anyway.
Of course, I know SIDs - S-1-5-32-544 for Administrators and S-1-5-11 for Authenticated users. However, running
NET LOCALGROUP S-1-5-32-544 S-1-5-11 /add returns error that group doesn't exist. Ok, so I found a script to check it -
$objUser = New-Object System.Security.Principal.NTAccount("kenmyer")
$strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
$strSID.Value
This returns expected value, so far so good. Then I tried to double check it -by running line to get name from SID -
$Admin = (Get-WMIObject -Class Win32_Group -Filter "LocalAccount=True and SID='S-1-5-32-544'").Name
$Auth = (Get-WMIObject -Class Win32_Group -Filter "LocalAccount=True and SID='S-1-5-11'").Name
And $Admin = Administratori (as it should be), while $Auth = nothing. There is no name. And that's where I stopped. I tried this in English environment as well - still got "no such group" message. Running first command I wrote, with both names in English - Works perfectly Ok.
Any ideas?
Upd:
Perhaps I can't explain properly what I'm trying to do, so let the script do the talking:
#Task: to add "Authenticated users" to "Administrators" group in any languange OS.
$objSID = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")
$objgroup = $objSID.Translate( [System.Security.Principal.NTAccount])
$objgroupnameAdm = ($objgroup.Value).Split("\")[1]
$objSID = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-11")
$objgroup = $objSID.Translate( [System.Security.Principal.NTAccount])
$objgroupnameAuth = ($objgroup.Value).Split("\")[1]
#Administratörer
#Autentiserade användare
net localgroup $objgroupnameAdm $objgroupnameAuth /add
I try this on Swedish Win7 right now. So result is:
net.exe : Syntaxen för kommandot är:
At line:13 char:4
+ net <<<< localgroup $objgroupnameAdm $objgroupnameAuth /add
+ CategoryInfo : NotSpecified: (Syntaxen för kommandot är::String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
I've tried also putting $objgroupnameAuth in quotes, as it contains two words, but that gives same result. Definig variables as string - no changes, and replacing $objGroupNameAdm with actual value - no changes.
If I couldn't do it in English Windows, I would assume that it's just functionally impossible.
I use this method to translate from SID to localized name:
.SYNOPSIS
Adds the "NT AUTHORITY\Interactive security principal to the local computer Administrators group"
.DESCRIPTION
THis script uses a SID translation to receive the localized name for the Interactive principal and the Administrators group, then adds the principal to the group using the localized names.
# Translate the S-1-5-32-544 (.\Administrators) SID to a group name, the name varies depending on the language version of Windows.
$sid2 = 'S-1-5-32-544'
$objSID2 = New-Object System.Security.Principal.SecurityIdentifier($sid2)
$localadminsgroup = (( $objSID2.Translate([System.Security.Principal.NTAccount]) ).Value).Split("\")[1]
# Translate the S-1-5-4 (NT AUTHORITY\Interactive) SID to an account name, the name varies depending on the language version of Windows.
$sid1 = 'S-1-5-4'
$objSID1 = New-Object System.Security.Principal.SecurityIdentifier($sid1)
$interactive = (( $objSID1.Translate([System.Security.Principal.NTAccount]) ).Value).Split("\")[1]
# Add the security principal name to the local administrators group. (used old style of adding group members due to compatibility reasons)
try {
Write-Host "Adding security principal: $interactive to the $localadminsgroup group..."
$group = [ADSI]"WinNT://$env:computername/$localadminsgroup,group"
$ismember = "False"
#($group.Invoke("Members")) | ForEach-Object {
If ($interactive -match $_.GetType.Invoke().InvokeMember("Name", 'GetProperty', $null, $_, $null)) {
$ismember = "True"
}
}
If ($ismember -eq "True") {
write-host "user $interactive is already a member of $localadminsgroup"
}
Else {
$result = $group.Add("WinNT://NT AUTHORITY/$interactive,user")
write-host "user $interactive is added to $localadminsgroup"
}
}
Catch {
write-host $_.Exception.Message
}
It's not entirely tailored towards what you need but I'm sure you can make it work.
Regards,
Koen.
The SID S-1-5-11 is used for Authenticated Users (Well known SIDs). That is a BUILTIN group that cannot be modified. Other groups like this are Everyone, or Anonymous, etc.
This type of group doesn't exist in the "physical" sense or the word, i.e. there is no object created either in the local SAM nor in the Active Directory.
They are entirely generated and managed by Windows.
You receive the SID in your session depending on how you connected and/or logged on.
Therefore making a WMI Win32_Group request, or using Get-ADGroup won't return anything.
You can invoke Get-ADAccountAuthorizationGroup, to see if a particular identity is member of such groups.
You can use the SID to retrieve create a create a System.Security.Principal.NTAccount object pointing to Authenticated Users:
$auth = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-11")
$name = $auth.Translate([System.Security.Principal.NTAccount])
UPDATE:
I could not add the localized name of $auth to that group. Looks like only the English version works.
Question is simple, once asked correctly, and answer is to be found here: Microsoft Supprt: NET /ADD command .
If NET limit is 20 characters, and "Autentiserade användare" is 24 characters, it's not supposed to work. Workaround is to be found in the same link.

Listing users in ad group recursively with powershell script without CmdLets

I'm trying to list everyone in a security group in an active directory without using CmdLets in PowerShell. The weird thing with my script is that it works if I list the entire directory but if I try and specify with an ldap query what I want to be listed it does not work. I know my ldap query is correct because I have used it in another similar vbs and it works. The commented lines are where i have tried to put in the query.
$strFilter = "(&(objectCategory=person)(objectClass=user))"
#$strFilter = "(&(objectCategory=person)(objectClass=user)(memberOf=CN=Common Name,OU=User Groups,...,DC=ad,DC=domain,DC=com))" #... is just left out part of query
#$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$objDomain = New-Object System.DirectoryServices.DirectoryEntry("LDAP://CN=Common Name,OU=User Groups,...,DC=ad,DC=domain,DC=com") #... is just left out part of query
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$objSearcher.SearchScope = "Subtree"
$colProplist = "name"
foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
$colResults = $objSearcher.FindAll()
foreach ($objResult in $colResults)
{$objItem = $objResult.Properties; $objItem.name}
Here is something working in an Active-Directory 2003 SP2 and 2008 R2. I use ADSI and Microsoft LDAP_MATCHING_RULE_IN_CHAIN. It Search recursively (but in one query) all the users from a group (be careful it return users from security and distributions group)
Clear-Host
$dn = New-Object System.DirectoryServices.DirectoryEntry ("LDAP://WM2008R2ENT:389/dc=dom,dc=fr","jpb#dom.fr","PWD")
# To find all the users member of groups "MonGrpPlusSec" :
# Set the base to the groups container DN; for example root DN (dc=societe,dc=fr)
# Set the scope to subtree
# Use the following filter :
# (member:1.2.840.113556.1.4.1941:=CN=MonGrpPlusSec,OU=ForUser1,DC=dom,DC=fr)
$dsLookFor = new-object System.DirectoryServices.DirectorySearcher($dn)
$dsLookFor.Filter = "(&(memberof:1.2.840.113556.1.4.1941:=CN=MonGrpPlusSec,OU=ForUser1,DC=dom,DC=fr)(objectCategory=user))";
$dsLookFor.SearchScope = "subtree";
$n = $dsLookFor.PropertiesToLoad.Add("cn");
$n = $dsLookFor.PropertiesToLoad.Add("distinguishedName");
$n = $dsLookFor.PropertiesToLoad.Add("sAMAccountName");
$lstUsr = $dsLookFor.findall()
foreach ($usrTmp in $lstUsr)
{
Write-Host $usrTmp.Properties["samaccountname"]
}
This will get all members of the domain Administrators group, including nested members (requires .NET 3.5).
$Recurse = $true
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
$group=[System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($ct,'Administrators')
$group.GetMembers($Recurse)
So long as you know the group name, you can run the following (ugly) quasi-one-liner:
## List Members in a Group
$groupname = 'GroupNameHere'
(New-Object System.DirectoryServices.DirectoryEntry((New-Object System.DirectoryServices.DirectorySearcher("(&(objectCategory=Group)(name=$($groupname)))")).FindOne().GetDirectoryEntry().Path)).member | % { (New-Object System.DirectoryServices.DirectoryEntry("LDAP://"+$_)) } | Sort-Object sAMAccountName | SELECT #{name="User Name";expression={$_.Name}},#{name="User sAMAccountName";expression={$_.sAMAccountName}}
Also since you rarely do one without the other, I'm also going to include the way to list all groups for a user using the same basic approach:
## List Groups for a Username
$username = 'UsernameHere'
(New-Object System.DirectoryServices.DirectorySearcher("(&(objectCategory=User)(samAccountName=$($username)))")).FindOne().GetDirectoryEntry().memberOf | % { (New-Object System.DirectoryServices.DirectoryEntry("LDAP://"+$_)) } | Sort-Object sAMAccountName | SELECT #{name="Group Name";expression={$_.Name}},#{name="Group sAMAccountName";expression={$_.sAMAccountName}}
Both of these query your current domain and do not require any domain qualification, nor do they require any modules or additional libraries be installed. I also find myself working in a pretty vanilla environment from time-to-time with minimal permissions where I need to search through AD, and I find these two commands help me with that quite a bit.