Ok so I'm trying to automate the creation of security groups under a specific OU. The keystone is group membership, so basically If member of group A -> create group B.
So I'm filling a variable with the name attribute of an "All Managers" group. Then I want to loop through those $names and check for the existence of another group using {Name -like 'Reports to $name'}
The looping part is throwing me off, here's what I've got:
import-module activedirectory
$ou = "ou=Stuff, ou=Resources, ou=Groups, ou=Org, dc=domain, dc=net"
$creds = "domain.net\user"
$server = "<domain controller>"
$managers = get-adGroupMember -server $server -Credential $creds -identity "All Managers" | select name
$name = $managers.name
$ReportsTo = Get-adgroup -server $server -credential $creds -searchbase $ou -filter "Name -like 'Reports to *'" | where {$_.name -replace 'Reports to ' -in $name} | select name
$Reports = $reportsto.name
$reports
ForEach ($manager in $managers){
If ($ReportsTo -NotContains $name)
#{$name}
{New-ADGroup -name "Reports to "$name -groupscope Global -path $ou}
}
it's ugly I know, but like i said I'm not sure how to process the loop, they are still new to me.
You may do the following:
$ou = 'ou=Stuff,ou=Resources,ou=Groups,ou=Org,dc=domain,dc=net'
$creds = "domain.net\user"
$server = "<domain controller>"
# Get Manager names only
$managers = Get-ADGroupMember -Server $server -Credential $creds -Identity 'All Managers' |
Select-Object -ExpandProperty Name
# Get Group names that are in the format Reports to Manager Name
$ReportsTo = Get-ADGroup -Server $server -Credential $creds -SearchBase $ou -Filter "Name -like 'Reports to *'" |
where {$_.Name -replace 'Reports to ' -in $managers} |
Select-Object -ExpandProperty Name
# Find manager names that don't have a Reports to group
Compare-Object $managers ($ReportsTo -replace 'Reports to ') -PassThru | Foreach-Object {
# Pipe found manager names into New-ADGroup command's -Name parameter
New-ADGroup -Name "Reports to $_" -GroupScope Global -Path $ou -Server $server -Credential $creds
}
Compare-Object by default only lists differences.
Related
I found a script that give you OU permissions for the domain the script is run on.
I want to use the same script from a single domain but scan other domains I specify.
The problem I think is with $schemaIDGUID = #{}
When run It's always for the domain the script is running on which is different from the domain I want to run the script on.
Here's the script I modified it to pickup specific domain.
$schemaIDGUID = #{}
$domain = "My specific domain name"
$report = #()
$schemaIDGUID = #{}
$ErrorActionPreference = 'SilentlyContinue'
Get-ADObject -Server $domain -SearchBase (Get-ADRootDSE -Server $domain).schemaNamingContext -LDAPFilter '(schemaIDGUID=*)' -Properties name, schemaIDGUID |
ForEach-Object {$schemaIDGUID.add([System.GUID]$_.schemaIDGUID,$_.name)}
Get-ADObject -SearchBase "CN=Extended-Rights,$((Get-ADRootDSE -Server $domain).configurationNamingContext)" -LDAPFilter '(objectClass=controlAccessRight)' -Properties name, rightsGUID |
ForEach-Object {$schemaIDGUID.add([System.GUID]$_.rightsGUID,$_.name)}
$ErrorActionPreference = 'Continue'
$OUs = #(Get-ADDomain -Server $domain | Select-Object -ExpandProperty DistinguishedName)
$OUs += Get-ADOrganizationalUnit -Server $domain -Filter * | Select-Object -ExpandProperty DistinguishedName
$OUs += Get-ADObject -Server $domain -SearchBase (Get-ADDomain -Server $domain).DistinguishedName -SearchScope OneLevel -LDAPFilter '(objectClass=container)' | Select-Object -ExpandProperty DistinguishedName
ForEach ($OU in $OUs) {
$report += Get-Acl -Path "AD:\$OU" |
Select-Object -ExpandProperty Access |
Select-Object #{name='organizationalUnit';expression={$OU}}, `
#{name='objectTypeName';expression={if ($_.objectType.ToString() -eq '00000000-0000-0000-0000-000000000000') {'All'} Else {$schemaIDGUID.Item($_.objectType)}}}, `
#{name='inheritedObjectTypeName';expression={$schemaIDGUID.Item($_.inheritedObjectType)}}, `
*
}
$report | Export-Csv -Path ".\$domain.OU_Permissions.csv" -NoTypeInformation
#Start-Process ".\$domain.OU_Permissions.csv"
break
$report |
Where-Object {-not $_.IsInherited} |
Select-Object IdentityReference, OrganizationalUnit -Unique |
Sort-Object IdentityReference
$filter = Read-Host "Enter the user or group name to search in OU permissions"
$report |
Where-Object {$_.IdentityReference -like "*$filter*"} |
Select-Object IdentityReference, OrganizationalUnit, IsInherited -Unique |
Sort-Object IdentityReference
Your problem has nothing to do with the $schemaIDGUID variable.
The problem is this line:
$report += Get-Acl -Path "AD:\$OU"
The AD: drive is mapped to ADWS on a DC in your home domain, on module import, so you'll need to explicitly create another drive that maps to the target domain instead:
$domain = "other.domain.tld"
# discover naming context + find a DC to query
$defaultNC = (Get-ADRootDSE -Server $domain).defaultNamingContext
$DC = Get-ADDomainController -Server $domain
# map new ADTemp:\ drive
New-PSDrive -Name ADTemp -PSProvider ActiveDirectory -Root $defaultNC -Server $DC
For the rest of the script, the only thing you need to change is the previously mentioned line, to:
$report += Get-Acl -Path "ADTemp:\$OU"
Part of a script that I'm working on grabs users from AD passes to the variable $TargetUsers
This variable is then passed on to the following to change the UPN suffix for each user:
$OldSuffix = "#olddomain.com"
$NewSuffix = "#newdomain.com"
Foreach ($User3 in $TargetUsers) {
$Upn3 = $User3.UserPrincipalName
$NewUpn = $User3.UserPrincipalName.Replace($OldSuffix,$NewSuffix)
Get-ADUser -Filter "UserPrincipalName -eq '$Upn3'" | Set-ADuser `
-Remove #{proxyAddresses=#("SMTP:$($User3.givenName).$($User3.sn)$OldSuffix","sip:$($User3.givenName).$($User3.sn)$OldSuffix")} `
-Add #{proxyAddresses=#("SMTP:$($User3.givenName.ToLower()).$($User3.sn.ToLower())$NewSuffix","smtp:$($User3.givenName.ToLower()).$($User3.sn.ToLower())$OldSuffix","sip:$($User3.givenName.ToLower()).$($User3.sn.ToLower())$NewSuffix")} `
-Replace #{ co = "United Kingdom" } `
-Email "$($User3.givenName.ToLower()).$($User3.sn.ToLower())$NewSuffix" `
-UserPrincipalName $NewUpn
$NewUpn2 = Get-ADuser -Filter "UserPrincipalName -eq '$NewUpn'" | Select UserPrincipalName
"$(Get-Date -f HH:mm:ss): $($Upn3): AD Attributes updated & UPN Suffix changed to $NewUpn2" | Tee-Object $UserMigrationLog -Append
}
This outputs to host and log file "...UPN Suffix changed to #{UserPrincipalName=Firstname.surname#newdomain.com}"
How can I get this to exclude the "#{UserPrincipalName=" & trailing "}" at the end?
Ah sorted it.
$NewUpn2 = Get-ADuser -Filter "UserPrincipalName -eq '$NewUpn'" | % {$_.UserPrincipalName}
Did the trick.
I am putting together a script that will check all of my web servers certificates so that I can monitor when they are set to expire. When the script goes to execute the Invoke-Command I am getting this error:
Here is my code:
Import-Module WebAdministration
$results = #()
$ou = 'OU=test,OU=test,OU=Servers,DC=contoso,DC=com'
$subtree = Get-ADOrganizationalUnit -SearchBase $ou -SearchScope Subtree -filter * | Select-Object -ExpandProperty DistinguishedName
ForEach($dn in $subtree){
$servers = Get-ADComputer -Filter * -SearchBase $dn | select Name
$results += $servers
}#ForEach($dn in $subtree)
$scriptBlock = [scriptblock]::Create({
Import-Module WebAdministration; Get-ChildItem -Path IIS:SSLBindings | ForEach-Object -Process `
{
If($_.Sites){
$certificate = Get-ChildItem -Path CERT:LocalMachine/My |
Where-Object -Property Thumbprint -EQ -Value $_.Thumbprint
[PSCustomObject]#{
Sites = $_.Sites.Value
CertificateDNSNameList = $certificate.DnsNameList
CertificateNotAfter = $certificate.NotAfter
}#[PSCustomObject]
}#If($_.Sites)
}#Import-Module
})#ScriptBlock
ForEach($server in $results){
Invoke-Command -ComputerName $server -ScriptBlock $scriptBlock | Select Sites,CertificateDNSNameList,CertificateNotAfter,PSComputerName #ScriptBlock
}#ForEach($server in $results)
Now, If I take the following line out of the loop and replace $server with an actual server name, I get the results I am looking for:
Invoke-Command -ComputerName ServerName -ScriptBlock $scriptBlock | Select Sites,CertificateDNSNameList,CertificateNotAfter,PSComputerName
Any ideas what I am doing wrong?
Your Results-Array is not an array of string, it is an array of object. Each object have the attribute name. Change your last ForEach-Loop into this and your script will work:
ForEach($server in $results){
Invoke-Command -ComputerName $server.name -ScriptBlock $scriptBlock | Select Sites,CertificateDNSNameList,CertificateNotAfter,PSComputerName #ScriptBlock
}#ForEach($server in $results)
It looks to me like "select Name" is returning an object rather than a string. Try changing the line that fetches the servers to this:
$servers = Get-ADComputer -Filter * -SearchBase $dn | select -ExpandProperty Name
I have a task to get userPrincipalName attribute from users who are in several groups in our multiple-domain AD forest.
The problem is that I can't use Select-Object to get a user's UPN from Get-ADGroupMember because this cmdlet only returns a limited number of properties (samaccountname, name, SID and DN), and UPN isn't one of them.
I wrote this code (get "name" and than search UPN by "name"):
$ScriptPath = Split-Path $MyInvocation.MyCommand.Path
$LocalSite = (Get-ADDomainController -Discover).Site
$NewTargetGC = Get-ADDomainController -Discover -Service 6 -SiteName
$LocalSite
IF (!$NewTargetGC)
{ $NewTargetGC = Get-ADDomainController -Discover -Service 6 -NextClosestSite }
$NewTargetGCHostName = $NewTargetGC.HostName
$LocalGC = “$NewTargetGCHostName” + “:3268”
$domains = (Get-ADForest).domains
$MembersOfSFDC_Groups = foreach ($domain in $domains) {
$Group = Get-ADGroup -Filter { Name -like "*groupname*" } -Server $Domain
$Group | Get-ADGroupMember -Server $domain | Select #{
Name="Domain";Expression={$Domain}},#{
Name="Group";Expression={$Group.Name}}, name}
$DisplayNames = $MembersOfSFDC_Groups.name
$DisplayNames |Out-file (Join-Path $ScriptPath 'DisplayNames.txt')
Get-content (Join-Path $ScriptPath 'DisplayNames.txt') |
$displaynames | ForEach-Object {
Get-ADUser -Server $LocalGC -Filter {Name -eq $_} |
Select-Object -Property userPrincipalName} |
Out-File (Join-Path $ScriptPath 'upnOfSDFC_AD_GroupsMembers.txt')
But next problem is that this code is running about 30 min (Measure-Command cmdlet). We have a huge number of users across multiple domains.
My question is how to improve my code to get user's UPN more faster?
I know about System.DirectoryServices.DirectorySearcher, but don't know how to implementing this method with my txt-file (list of "names").
Any help will be much appreciated.
You can actually get it from one line of code. Simples... :)
Get-ADGroupMember -Identity "group name" |%{get-aduser $_.SamAccountName | select userPrincipalName } > c:\scripts\upnofADgroup.txt
Fastest approach is probably avoiding Get-ADGroupMember altogether, and just search for the group, and then search for objects that are members of that group:
$Group = Get-ADGroup -Filter { Name -like "*groupname*" } -Server $Domain
$Members = Get-ADObject -LDAPFilter "(memberOf=$($Group.DistinguishedName))" -Properties UserPrincipalName
$Members |Select-Object UserPrincipalName |Out-File (Join-Path $ScriptPath 'upnOfSDFC_AD_GroupsMembers.txt')
Now you're down to 2 queries, rather than 2 + N (where N is the number of members)
Ok, guys, I'v got it:
function Get-DomainFromDN ($param)
{
$dn1 = $param -split "," | ? {$_ -like "DC=*"}
$dn2 = $dn1 -join "." -replace ("DC=", "")
$script:test = $dn2
return $dn2
}
foreach ($Group in $Groups) {
$Members = Get-ADObject -LDAPFilter "(&(objectCategory=user)(memberOf=$($Group.DistinguishedName)))" -Properties UserPrincipalName -Server (Get-DomainFromDN ($group.DistinguishedName))
$UPN_Of_SFDC_Groups += $Members |Select-Object UserPrincipalName }
$UPN_Of_SFDC_Groups | Out-file (Join-Path $ScriptPath 'upnOfSDFC_AD_GroupsMembers.txt')
This script works without error now, but the problem is that when several groups in the searchbase are found, the script will add all users from all groups to the cross forest target groups.
So for example:
ForestAGroup1 = contains 2 users
ForestAGroup2 = contains 2 users
::runs script::
now...
ForestBGroup1 = contains 4 users
ForestBGroup2 = contains 4 users
The ForestBGroup1/2 needs to contain the same identical users as ForestAGroup1/2.
Here is the script for reference:
$creds = Get-Credential
$Groups = Get-ADGroup -Properties * -Filter * -SearchBase "OU=TEST,OU=Shop Print Groups,OU=User,OU=domain Groups,DC=domainA,DC=com" | export-csv c:\temp\test.csv
$Groups = Get-ADGroup -Properties * -Filter * -SearchBase "OU=TEST,OU=Shop Print Groups,OU=User,OU=domain Groups,DC=domainA,DC=com"
Foreach($G In $Groups)
{
#Display group members and group name
Write-Host $G.Name
Write-Host "-------------"
$G.Members
#Add members to domainB group
$domainGMembers = import-csv C:\temp\test.csv | ForEach-Object -Process {Get-ADGroupMember -Identity $_.CN} | Select-Object samaccountname | export-csv c:\temp\gmembers.csv
$domainDNUser = import-csv C:\temp\gmembers.csv | ForEach-Object -Process {Get-ADUser $_.samaccountname -Server "domainA.com" -properties:Distinguishedname}
import-csv C:\temp\gmembers.csv | ForEach-Object -Process {Add-ADGroupMember -Server "domainB.com" -Identity $G.Name -Members $domainDNUser -Credential $creds -Verbose}
}
What are you doing?
You export to csv, but still try to save it to a variable
You search twice
You add all members from ALL groups in TEST-OU to every group in domainB
You waste time on saving and reading data that you already have in memory
You search for the user-object to get SamAccountName when you already have something ten times better, the DN. Then you use that SamAccountName to find the DN.
Try this (untested):
$creds = Get-Credential
$Groups = Get-ADGroup -Properties Members -Filter * -SearchBase "OU=TEST,OU=Shop Print Groups,OU=User,OU=domain Groups,DC=domain,DC=com"
Foreach($G In $Groups)
{
#Display group members and group name
Write-Host $G.Name
Write-Host "-------------"
$G.Members
#Add members to domainB group
$G.Members |
Get-ADUser -Server fairfieldmfg.com |
ForEach-Object { Add-ADGroupMember -Server "domainB.com" -Identity $G.Name -Members $_ -Credential $creds -Verbose }
}
I used a foreach-loop to run the Add-ADGroupMember because it usually fails in the middle of a group of members if it finds on the already is a member, but if we add them one at a time you get around that (or you could do a search and exclude those already in the group).
You may want to add -ErrorAction SilentlyContinue to Add-ADGroupMember to ignore those errors when you know the script works as it should.