Currently I have the script below, which will compare email addresses in the CSV to the main mail address in ActiveDirectory, but it does not take proxy addresses into account. For instance, if Mary Smith had an email address Mary.Smith#abc.com, then Mary got married and her last name changed to Jones. Her standard email address is still Mary.smith#abc.com but she now has a proxy called mary.jones#abc.com.
How do I use this script to also validate against the proxyaddresses? Preferably without a huge hit to Active Directory .
$path = "H:\users.csv"
$csv = Import-Csv $path
Import-Module ActiveDirectory
foreach ($line in $csv)
{
$User = Get-ADUser -LDAPFilter "(&(objectclass=user)(mail=$($line.Email)))"
if ($User -eq $Null) {"User does not exist in AD " + $line.Email }
else {"User found in AD - " + $line.Email}
}
AD has a proxyAddresses attribute for mail-enabled users, which includes the primary SMTP address as well as any aliases. Change your -LDAPFilter argument to this:
"(&(objectclass=user)(proxyAddresses=*$($line.Email)*))"
BTW, it's possible for the mail attribute to differ from the primary SMTP address in proxyAddresses, because the latter is enforced by Exchange but the former can be changed at will outside Exchange. It's not likely if you have a single Exchange organization integrated with the domain, but if you're concerned about that possibility you can use this filter:
"(&(objectclass=user)(|(mail=$($line.Email))(proxyAddresses=*$($line.Email)*)))"
Assuming you're running Exchange, you'd be much better off using the Exchange Get-Recipient cmdlet for this. Exchange maintains a database indexed by SMTP address, so those lookups are immediate. AD does not, so it must search all the ProxyAddreses of every user looking for a match.
$ExSession = new-pssession -configurationname Microsoft.Exchange -ConnectionURI http://<ExchangeServerName>/powershell/ -authentication kerberos
foreach($line in $csv)
{
if (Invoke-Command {Get-Recipient $args[0]} -ArgumentList $line.Email -Session $ExSession -ErrorAction SilentlyContinue)
{"User exists in AD"}
else {"User not found in AD"}
}
Substitue the name of one of your Exchange servers for in the new-pssession command.
Related
I have the script below to give me the distinguished name for groups in a spreadsheet I have. The issue is, the groups are located in another domain. How do I point my script to that domain? Issue is I know I have to be logged in to that domain to run it but I cant.
$Groups = Get-Content -Path C:\Scripts\DistinguishedName.csv
ForEach ($Group in $Groups) {
Get-ADGroup -Identity $Group | Select-Object distinguishedName
}
The cmdlets in the Active Directory module support passing in the value of the domain controller you are wanting to query. By default when you call Get-ADGroup (or any of the other) it will validate what domain it should query by checking the domain of your current machine.
The other option is to provide the -Server (doc) with the value of the Active Directory Domain Services you want to execute your query against.
You can also provide the -Credential parameter with a PSCredential object that contains your login for that other domain. This is required if the current login of your PowerShell session is not authorized to authenticate against that other domain.
So your example script would look something like this:
$AdDomain = "whatever.company.local"
$adCred = Get-Credential
$Groups = Get-Content -Path C:\Scripts\DistinguishedName.csv
ForEach ($Group in $Groups) {
Get-ADGroup -Identity $Group -Server $AdDomain -Credential $adCred | Select-Object distinguishedName
}
New-PSSession wants a -ConnectionURI of an explict Exchange server. I don't want to hardcode a name in the script (we have 32 servers), and furthermore I want it to select an exchange that is in the same datacenter.
I want a solution similar to Get-ADDomainController -Discover -GetClosestSite But it seems I'm hoping for too much.
I suppose I can pull the members of cn=Exchange Install Domain Servers and do some site dependent ranking on them.
Looking for best practices.
Update Edit: 9/26 I have achieved a solution. It may be site specific, but I'll share below in an answer to show the final code. The answer provided by postanote provided pointers that helped me move forward.
There is no official documented best practices for PowerShell in general (there are too many variables in the mix, but some have put their thoughts in the topic , for example, this one - https://github.com/PoshCode/PowerShellPracticeAndStyle ) or for what you are asking for from Microsoft.
As for you point here:
I suppose I can pull the members of cn=Exchange Install Domain Servers
and do some site dependent ranking on them.
This is not something new, or tricky, so you can do this.
I have code in my personal library that I use that does this as well as for other doing resources, so I never have to hardcode server names for Exchange, SQL, DC, etc.
There are several blogs (that have been out there for a while now) on the topic with sample code to use as is or tweak as needed, which is why I asked what you've searched for.
One of those blog examples of how to do this is here:
https://use-powershell.blogspot.com/2012/12/find-exchange-servers-in-domain.html
The examples provided:
an active directory user with mailbox will have 2 attributes (msExchHomeServerName and homemdb) that will contain the name of the
mailbox server that has his mailbox - once conected to one server you
can use exchange console to find the rest of them;
Get-ADUser samaccountname -Properties msExchHomeServerName, homemdb |Select-Object msExchHomeServerName, homemdb |Format-List
active directory computer type objects contain "exchange" word in servicePrincipalName attribute; you can use only your
organizational unit that contain your servers if you have one to
narrow your search:
Get-ADComputer -Filter * -SearchBase 'OU= SERVERS, DC=domain_name,DC=net' -Properties * | Where-Object {$_.serviceprincipalname -like '*exchange*'} |select-object name
active directory configuration partition contain information about exchange servers in domain; you can search for objects of class
msExchExchangeServer:
Get-ADObject -LDAPFilter "(objectClass=msExchExchangeServer)" –SearchBase "CN=Configuration,DC=domainname,DC=net" | Select-Object name
or you can list all objects from "CN=Servers,CN=First Administrative Group,CN=Administrative Groups,CN=INTERNAL,CN=Microsoft
Exchange,CN=Services,CN=Configuration,DC=domainname,DC=net" using
powershell or ADSI Edit console;
Get-ADObject -Filter * -SearchBase "CN=Servers,CN=First Administrative Group,CN=Administrative Groups,CN=INTERNAL,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=domainname,DC=net" -SearchScope onelevel
Or this post:
https://social.technet.microsoft.com/Forums/ie/en-US/94d89161-9dfb-48fc-b307-2f0e1320c9dc/how-to-find-file-servers-and-exchange-servers-in-ad-
Example:
dsquery * "cn=Configuration,dc=MyDomain,dc=com" -Filter "(objectCategory=msExchExchangeServer)"
Or if you are really trying to get an Exchange server in given site, then this to already exists. See this GitHub source:
https://github.com/mikepfeiffer/PowerShell/blob/master/Get-ExchangeServerInSite.ps1
The sample provided is:
function Get-ExchangeServerInSite {
$ADSite = [System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]
$siteDN = $ADSite::GetComputerSite().GetDirectoryEntry().distinguishedName
$configNC=([ADSI]"LDAP://RootDse").configurationNamingContext
$search = new-object DirectoryServices.DirectorySearcher([ADSI]"LDAP://$configNC")
$objectClass = "objectClass=msExchExchangeServer"
$version = "versionNumber>=1937801568"
$site = "msExchServerSite=$siteDN"
$search.Filter = "(&($objectClass)($version)($site))"
$search.PageSize=1000
[void] $search.PropertiesToLoad.Add("name")
[void] $search.PropertiesToLoad.Add("msexchcurrentserverroles")
[void] $search.PropertiesToLoad.Add("networkaddress")
$search.FindAll() | %{
New-Object PSObject -Property #{
Name = $_.Properties.name[0]
FQDN = $_.Properties.networkaddress |
%{if ($_ -match "ncacn_ip_tcp") {$_.split(":")[1]}}
Roles = $_.Properties.msexchcurrentserverroles[0]
}
}
}
I'm accepting postanote's answer as being most helpful.
In the end, I created a solution that may be site and Exchange install specific, but it does illustrate another technique.
My constraints that were different than most other solutions I found and include; that the given user did not currently have a mailbox on the system. Hence the code beyond this snippet will gather some data, then select a specific database.
I discovered that the Exchange server version we have installed, creates some records in "CN=Exchange Install Domain Servers,CN=Microsoft Exchange System Objects," In particular, the Members attribute has a list of servers.
I extracted that list, sorted it by Site (local to front), and then resolved the FQDN to form a URI to connect.
Function Connect-Exchange {
# Find servers list, then sort by name given what site we are running in: SITE1 = Ascending , SITE2 = Descending
$ADSite = (Get-ADDomainController).Site
if ($ADSite -like "SITE1*") { $descOrder = $true } else { $descOrder = $false }
$exchSession = $null
$ExchServersDN = "CN=Exchange Install Domain Servers,CN=Microsoft Exchange System Objects,DC=example,DC=com”
$ExchServers = (Get-ADObject -Identity $($ExchServersDN) -Properties Member).Member | Sort-Object -Descending:$descOrder
# Iterate through Exchange server list until connection succeeds
$i = 0;
while ((-Not $exchSession) -and ($i -lt $ExchServers.Count)) {
$ExchServerURI = "http://" + (Get-ADObject -Identity $ExchServers[$i] -Properties dNSHostName).dnsHostName + "/Powershell"
$exchSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionURI $ExchServerURI -ErrorAction SilentlyContinue
If (-Not $exchSession) { $i++ }
else {
Import-PSSession $exchSession -DisableNameChecking | Out-Null
}
}
return $exchSession
}
My first question on this forum so hopefully I am doing this right. I have written a script based off of a bit of code I found on this site but it is not producing what I need and I am not sure why. The original code is as follows:
$Mailbox=get-Mailbox xxxx#company.com
$DN=$mailbox.DistinguishedName
$Filter = "Members -like ""$DN"""
Get-DistributionGroup -ResultSize Unlimited -Filter $Filter
This produced the output of a list of distribution lists the user was a member of with 4 columns, Name, DisplayName, GroupType, PrimarySmtpAddress. This works great. I added to this to build a tool where you enter in the users email address but now the output looks like all the properties of the Distribution Lists the user is a member of. Here is my complete code:
Import-Module MSOnline
$LiveCred = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/PowerShell -Credential $LiveCred -Authentication Basic -AllowRedirection
Import-PSSession -allowclobber $Session
Connect-MsolService -Credential $LiveCred
cd c:\scripts
Write-Host "This tool displays the Distrbution lists a user is a member of"
$User = Read-Host -Prompt 'email address you would like to find the distribution lists of'
$Mailbox=get-Mailbox "$User"
$DN=$mailbox.DistinguishedName
$Filter = "Members -like ""$DN"""
Get-DistributionGroup -ResultSize Unlimited -Filter $Filter
I assume you want only those four properties. Change the last line in your code to something like below:
Get-DistributionGroup -ResultSize Unlimited -Filter $Filter | Select-Object Name,DisplayName,GroupType,PrimarySmtpAddress
I'm stuck in a stupid problem that I can't figure out how to solve.
I need to get all domain controllers of a trusted domain.
With this piece of code I get all DC in the current domain Get-ADDomainController -Filter *
With this I get one DC from target domain Get-ADDomainController -domain MyTrustedDomain -Discover
But how can I get all DC in target domain?
Can't test this due to lack of AD, but you could try the -Server option with the FQDN of the trusted domain:
Get-ADDomainController -Filter * -Server trusted.example.com
One way without using AD module:
$a = new-object 'System.DirectoryServices.ActiveDirectory.DirectoryContext'("domain", "other.domain.local" )
[System.DirectoryServices.ActiveDirectory.DomainController]::FindAll($a)
You need to be an 'authenticated user' in the remote domain or add username and password parameter to the DirectoryContext object
This command will list all domain controllers in the forest for each domain
(get-adforest).domains |%{get-addomaincontrollers -filter * -server $_}
I've come across the same problem as I work regularly with multiple domains. I was hoping for a more elegant solution, but so far the best I've come up with is to take your work one step further.
if Get-ADDomainController -domain MyTrustedDomain -Discover gives you one server in the target domain, you can feed that to the -server parameter to query that one DC. You do need to provide credentials to query a DC from a different domain than your login session if a trust DOES NOT exist (in a trust, the trusting domain considers you to be 'authenticated').
$targetdcname = (Get-ADDomainController -DomainName <MyTrustedDomain> -Discover).hostname
Get-ADDomainController -Filter * `
-Server $targetdcname `
-Credential (Get-Credential MyTrustedDomain\username) | ft HostName
or
Get-ADDomainController -Filter * `
-Server $((Get-ADDomainController -DomainName <MyTrustedDomain> -Discover).hostname) `
-Credential (Get-Credential MyTrustedDomain\username) | ft HostName
If you do this sort of thing alot, you can always store your credentials in a variable for reuse, $cred = Get-Credential MyTrustedDomain\username) and save the repeated prompts. The password is stored as a System.Security.SecureString and will be secure as long as you keep it within your session.
Until the Get-ADDomainController cmdlet is updated to allow both the -filter parameter AND the Domainname parameter, we're stuck with a workaround.
from: help get-addomaincontroller -examples
This should list all DCs in your domain
-------------------------- EXAMPLE 12 --------------------------
C:\PS>Get-ADDomainController -Filter { isGlobalCatalog -eq $true -and Site -eq "Default-First-Site-Name" }
Get all global catalogs in a given site.
Get-ADDomain -Identity <DOMAIN NAME> | select -ExpandProperty ReplicaDirectoryServers
Here is what I used
cls
$domains = (Get-ADForest).Domains;
foreach ($domain in $domains)
{
Write-Host $domain
(Get-ADDomain -Identity $domain | select -ExpandProperty ReplicaDirectoryServers).Count;
Write-Host "";
$totalCount = $totalCount + (Get-ADDomain -Identity $domain | select -ExpandProperty ReplicaDirectoryServers).Count;
}
Write-Host "Total domain controller count is: "$totalCount
Thanks for the start, here's what I came up with. Then I feed it to a SharePoint list.
get-adtrust -Filter * | Select-object Name, Domain,ipv4Address, OperatingSystem, Site, HostName, OperatingSystemVersion | ForEach-Object{Get-ADDomainController -Filter * -Server $_.Name}
Sometimes Powershell adds complexity, just open a cmd prompt and enter
C:\Windows\System32\nltest.exe /dclist:[trusted domain]
Of course, replace [trusted domain] with the name of the domain whose DC's you want.
I have the following code pulling from my exchange server 2003.
connect-qadservice -service 'localhost'
foreach ($server in $exchangeservers)
{
$AllUsers += get-wmiobject -class Exchange_Mailbox -namespace Root\MicrosoftExchangeV2 -computername $server| select servername,storagegroupname, storename,mailboxdisplayname,totalitems,size, DeletedMessageSizeExtended, legacyDN, datediscoveredabsentInDS
}
$exchngver = "2003"
foreach ($user in $AllUsers)
{
$obj = new-object psObject
$office = get-qaduser -Identity $user.legacyDN | select office, description
}
disconnect-qadservice
and it doesn't grab all the mailbox stores on the server. Any idea why or what might be causing this?
thanks in advance
NOTE: IT seems to grab all the mailbox stores except for 1 in the 2nd storage group. I have no idea why this is... The funny thing is my vbscript grabs all the mailbox stores using the same namespace and class just fine.
So to start simple, does it come back correct before you unroll & start using the quest stuff?
Do you get the right number from:
(get-wmiobject -class Exchange_Mailbox -namespace Root\MicrosoftExchangeV2 -computername srv02).count
Have you checked permissions on the Stores/SGs?
Couple of things (not sure they are the cause (#1)):
you are looping over $exchangeservers but don't use $server in -computerName (there's a fixed "srv02" server name).
I would move the connect-qadservice -service 'localhost' out of the foreach servers loop (You call it for each server in exchangeservers).
You are calling get-qaduser twice ($tmp and $office) to get the user office and description, you can do it in one call ($tmo is redundant):