Change user mail property with ADSI in PowerShell - powershell

I am trying to update the email address of a directory user with PowerShell.
I am unable to modify the mail property of a user entry with the following code:
$BadUser = [adsi] $Account.Path
$BadUser.mail.Clear()
$BadUser.mail.Add($User.Email) | Out-Null
$BadUser.SetInfo()
The mail.Clear() nor the mail.Add() seem to modify $BadUser when debugging with PowerGUI.
I have a working version that relies on the QAD plugin, and I would like to avoid using it if possible.
$suf = $AD.Parent.Substring(10)
Connect-QADService -Service "$($AD.dc[0]).$suf" -ErrorVariable AD_Conn_Error -ErrorAction Stop -WarningAction Stop | Out-Null
Set-QADObject $Account.Properties.distinguishedname[0] -ObjectAttributes #{mail=$User.Email} | Out-Null
Disconnect-QADService
Reasons I am avoiding QAD:
I am searching for users across 8 domain servers
ADSI allows me to save multiple connected entries in a list
QAD can connect to 1 domain at a time
ADSI seems relatively fast
QAD has memory leaks (1kB/s bad) that crash in large batches
QAD is unable to "identify" some users that ADSI found by cn

Here's some example code to do it:
$query= "(&(objectCategory=User)(cn=FirstName LastName))"
$OU = "LDAP://OU=Users,dc=subdomain,dc=company,dc=com"
$PageSize = 100
$objOU = New-Object System.DirectoryServices.DirectoryEntry($OU)
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objOU
$objSearcher.PageSize = $PageSize
$objSearcher.Filter = $query
$objSearcher.SearchScope = "Subtree"
$colResults = $objSearcher.FindAll()
foreach($objResult in $colResults) {
$dirObject = [ADSI]$objResult.GetDirectoryEntry()
$dirObject.mail = "newaddress#company.com"
$dirObject.CommitChanges()
}

Related

Some computers on a powershell GPO script not recognizing parameter

I am running into an issue where about 10% of computers on my network are throwing a very strange errors when processing. The error I get is "Where-Object : A Parameter cannot be found that matches paramter name 'Property'" the code I'm using is as follows.
#Create ADSI Search object to query Active Directory for usernames
#Start-Transcript -Path "$env:userprofile\Desktop\log.txt"
$strFilter = "objectCategory=user"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry("LDAP://OU=SD25;DC=DC;DC=DC")
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 100000
$objSearcher.Filter = $strFilter
$objSearcher.SearchScope = "Subtree"
#Populate ADSI with the extra fields of samaccountname which is the username, and memberof which gives you roughly which groups they are a memberof
$colProplist = "samaccountname", "memberof"
foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
#Run the Search
$colResults = $objSearcher.FindAll()
#$colResults
$resultsarray = #()
#The way ADSI returns results, it populates all an array of every username listed within the scope, I then use this foreach recursive loop to find the name I need
foreach ($objResult in $colResults)
{
#Here I am taking each of the users, and finding the one which has the samaccountname of the user that is currently logged in
$objItem = $objResult.Properties | Where-Object -Property memberof -like ALL
#$groups = $objItem.memberof
#This is for diagnostics, if you output a logfile it will tell you the name and groups it is a member of
$objitem
}
#This is the beginnings of searching for a computer container in active directory.
$compFilter = "objectCategory=computer"
$compDomain = New-Object System.DirectoryServices.DirectoryEntry("LDAP://OU=OU;DC=DC;DC=DC")
$compSearcher = New-Object System.DirectoryServices.DirectorySearcher
$compSearcher.SearchRoot = $objDomain
$compSearcher.PageSize = 100000
$compSearcher.Filter = $strFilter
$compSearcher.SearchScope = "Subtree"
$compProplist = "name"
foreach ($i in $compPropList){$compSearcher.PropertiesToLoad.Add($i)}
$compResults = $compSearcher.FindAll()
foreach ($compR in $compResults)
{
}
#Stop-Transcript
IIRC -Property was introduced to Where-Object with PowerShell 3.0. Could you script be running on PowerShell 2.0?
Responding to comment
You need to create a filter script in the form of a scriptblock (i.e. PowerShell code in a set of braces) instead of using the comparison operator parameters they added for 3.0.
Try using
Where-Object { $_.memberof -like "ALL" }
or something like that. $_ refers to the current object in the pipeline. I couldn't find the docs for version 2.0 but I found Using the Where-Object Cmdlet for version 1.0 which was relevant for 2.0 AFAIK and should help you.

Get Current User URI for Lync 2013 via PowerShell

I'm am trying to get the current user's URI that is signed into Lync on the machine the PS script is run on. I've Googled to no avail. One method I thought of trying was to get the Windows logged in name and then parse that into an e-mail address but there will be instances in which this won't give the correct URI. Is this achievable?
Assuming I understand your question...
1) Getting sip-address for current user using the ActiveDirectory-module.
(Get-ADUser $env:USERNAME -Properties msRTCSIP-PrimaryUserAddress).'msRTCSIP-PrimaryUserAddress'
2) Getting sip-address for current user using DirectorySearcher.
$filter = "(&(objectCategory=User)(SamAccountName=$env:USERNAME))"
$property = 'msRTCSIP-PrimaryUserAddress'
$domain = New-Object System.DirectoryServices.DirectoryEntry
$Searcher = New-Object System.DirectoryServices.DirectorySearcher
$Searcher.SearchRoot = $domain
$Searcher.PageSize = 1000
$Searcher.Filter = $Filter
$Searcher.SearchScope = "Subtree"
$Searcher.PropertiesToLoad.Add($property) | Out-Null
# Value
($Searcher.FindAll()).Properties[$property]

Powershell - Store all Computers in AD into Array

So at the moment I have some code which can lock down to a specific OU via ADSI in Powershell, loop through, and store them into an Array. In turn I loop through this and run a Test-Connection. I have my reasons...
Anyway, is it possible (using only inbuilt cmdlets, i.e. no Quest stuff) to recurse through the whole of AD and add all Computer Objects to the array?
$myArrayOfComputers = #()
$orgUnit = [ADSI]"LDAP://OU=foo,DC=foo,dc=co,dc=uk"
ForEach($child in $orgUnit.psbase.Children) {
if ($child.ObjectCategory -like '*computer*') { $myArrayOfComputers += $child.Name }
}
ForEach($i in $myArrayOfComputers) {
Test-Connection $i
}
In PowerShell V2.0 you can try :
Import-module ActiveDirectory
$computers = Get-ADComputer *
In PowerShell V1.0 You can try :
# dom.fr is the DNS root name of the domain
$dn = New-Object System.DirectoryServices.DirectoryEntry ("LDAP://dom.fr:389/dc=dom,dc=fr","administrator#dom.fr","admin")
# Look for computers
$Rech = new-object System.DirectoryServices.DirectorySearcher($dn)
$Rech.filter = "((objectClass=computer))"
$Rech.SearchScope = "subtree"
$Rech.PropertiesToLoad.Add("sAMAccountName");
$Rech.PropertiesToLoad.Add("lastLogon");
$Rech.PropertiesToLoad.Add("distinguishedname");
$computers = $Rech.findall()
On V2 using .net:
Add-Type -AssemblyName System.DirectoryServices.AccountManagement | out-null
$ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
$pc = new-object 'System.DirectoryServices.AccountManagement.PrincipalContext'($ct, "foo.co.uk", "OU=foo,DC=foo,dc=co,dc=uk");
$cpp = New-Object 'System.DirectoryServices.AccountManagement.Computerprincipal'($pc)
$ps = new-object 'System.DirectoryServices.AccountManagement.PrincipalSearcher'
$ps.QueryFilter = $cpp
$MyListArray = $ps.FindAll() | select -expa name

Powershell Bulk Find ActiveDirectory Objects

I'm trying to develop a powershell script to help with AD Group Membership management. We have a handful of large groups (30k-60k+ objects) that we want to update with data from another system.
The script loads the objects that should be in the group from a text file. Each object then has to located in AD using a System.DirectoryServices.DirectorySearcher. After that each object is added to the group membership.
The script spends some 80% of its time looking up each object, is there a bulk way to find objects in AD with powershell?
Thanks!
This is the fast way to query AD that I found in my experience, you need to change the query to find specific objects, in this code you'll find all user/person object in $objRecordSet.
$Ads_Scope_SubTree = 2
$objConnection = new-Object -com "ADODB.Connection"
$objCommand = new-Object -com "ADODB.Command"
$objConnection.Provider = "ADsDSOObject"
$objConnection.Open( "Active Directory Provider")
$objCommand.ActiveConnection = $objConnection
$objCommand.Properties.Item("Page Size").value = 1000
$objCommand.Properties.item("Searchscope").value = $Ads_Scope_SubTree
$objCommand.CommandText = "Select Name From 'LDAP://DC = int, DC= my, DC = local' Where objectCategory = 'Person'"
$objRecordSet = $objCommand.Execute()
$objRecordSet.RecordCount
More info here
You perhaps can try System.DirectoryServices.Protocols (S.DS.P) the native (non managed) version is quite efficient.
Here is a PowerShell starting script :
# ADDP-Connect.PS1
Clear-Host
# Add the needed assemblies
Add-Type -AssemblyName System.DirectoryServices.Protocols
# Connexion
$serverName = "WM2008R2ENT"
$ADDPConnect = New-Object System.DirectoryServices.Protocols.LdapConnection $serverName
$userName = "JPB"
$pwd = "PWD"
$domain = "Dom"
$ADDPConnect.Credential = New-Object system.Net.NetworkCredential -ArgumentList $userName,$pwd,$domain
# Create a searcher
$searchTargetOU = "dc=dom,dc=fr"
$searchFilter = "(samAccountName=user1)"
$searchScope = [System.DirectoryServices.Protocols.SearchScope]::Subtree
$searchAttrList = $null
foreach($user in "user1","user2","user3")
{
$searchFilter = "(samAccountName=$user)"
$searchRequest = New-Object System.DirectoryServices.Protocols.SearchRequest -ArgumentList $searchTargetOU,$searchFilter,$searchScope,$searchAttrList
$searchResponse = $ADDPConnect.SendRequest($searchRequest)
foreach($searchEntries in $searchResponse.Entries)
{
$searchEntries.DistinguishedName
}
}
If you start seeing timeout issues then set the timeout parameter appropriately like shown below
$ADDPConnect = New-Object System.DirectoryServices.Protocols.LdapConnection $serverName
$ADDPConnect.Timeout = "1000"
The below can help if you see timeout issues during execution
$ADDPConnect = New-Object System.DirectoryServices.Protocols.LdapConnection $serverName
$ADDPConnect.Timeout = "1000"

Powershell acting different for values vs. arrays?

I'm trying to grab out some information from Active Directory using Powershell, but I get some strange behavior. Here's my script:
$toFind = ( 'bobjones', 'samsmith' )
filter Get-AdUser {
$strFilter = "(&(objectCategory=User)(sAMAccountName=$_))"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$colProplist = ("name", "department")
foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
($objSearcher.FindAll() | %{$_.Properties})
}
"paul" | get-aduser # Works
$toFind | get-aduser # Doesn't work?!
The former prints out what I expect, a table of properties; the latter ends up just printing "0 1" repeatedly though I'm not sure why. Why would the single case work but not the array?
Figured it out, it has nothing to do with PowerShell. When you create the DirectoryEntry:
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
It will return results for your domain only (i.e. if you have an AD forest like "NorthAmerica" and "Europe", it'll only query the one you're in). It just happened that all of the names I was searching for were in another domain.
If you use the constructor to manually specify the Domain, it works pretty well (still haven't figured out how to query all domains yet though...)