In my organization, we spend a large amount of time changing user home folder paths, based on users changing roles, etc. I have written a very simple powershell script that sets the homedir path from a csv.:
Import-Csv C:\Dir\homedir.csv | ForEach-Object {
Set-ADUser $_.SamAccountName –HomeDirectory $_.HomeDirectory
}
What I would like for this to also do, is to check the users for the presence of a -profilepath (roaming profile) and change that (if present) to "$_.HomeDirectory"\Profile (all roaming profiles follow this construct). If not present, it would simply skip down to the next user and perform the work as required.
I've played around with if statements, and really done more harm than good. Anyone got a lifeline they can throw me?
Hard to tell where you're getting stuck, but I assume it's in the 'properties' bit. ProfilePath is not pulled by default when you issue the command Get-ADUser. Something like this should do the trick:
Import-Csv C:\Dir\homedir.csv | ForEach-Object {
$user = Get-ADUser $_.SamAccountName -Properties 'ProfilePath'
if($user.ProfilePath -ne $null)
{
$profilepath = $_.HomeDirectory + "\Profile"
Set-ADUser $user –ProfilePath $profilepath
}
Set-ADUser $_.SamAccountName –HomeDirectory $_.HomeDirectory
}
You need to specify -Properties ProfilePath if you want the Get-ADUser command to return the profile path.
$user = Get-ADUser $_.SamAccountName -Properties ProfilePath
If ($user.ProfilePath -ne $null) {
Set-ADUser $_.SamAccountName -ProfilePath "$($_.HomeDirectory)\Profile"
}
Related
Giving myself a fun little project today I thought, but now it's grown into an issue and the solution eludes me. I have a massive .Csv file with all our employees sAMAccountName and telephoneNumber attributes. I would like to update all of the telephone numbers in our active directory. I was poking around some of my old scripts, taking parts and pieces that would work for this my first iteration got me too here.
$Users = Import-Csv -Path C:\Results\EmployeeExtsTest.csv
ForEach ($User in $Users) {
$User = $User.sAMAccountName
$telephoneNumber = $User.telephoneNumber
Get-ADUser -Identity $User | Set-ADUser -telephoneNumber $telephoneNumber
}
That's when I discovered that PowerShell doesn't have a -telephoneNumber attribute. So I did some digging and then arrived here.
$Users = Import-Csv -Path C:\Results\EmployeeExtsTest.csv
ForEach ($User in $Users) {
$User = $User.sAMAccountName
$telephoneNumber = $User.telephoneNumber
Get-ADUser -Identity $User | Set-ADUser -Add #{telephoneNumber=$telephoneNumber}
}
I tested it out with my user at first and I keep getting the following.
Set-ADUser : Cannot validate argument on parameter 'Add'. The argument is null or an element of the argument collection contains a null value.
At line:6 char:50
+ ... -Identity $User | Set-ADUser -Add #{telephoneNumber=$telephoneNumber}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Set-ADUser], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.ActiveDirectory.Management.Commands.SetADUser
I know that it's reading my .Csv correctly because I can call it just fine. It outputs the following.
sAMAccountName telephoneNumber
-------------- ---------------
zgroven 1121
I know this solution "should" be easy but it's completely escaping me!
To expand on #PaulWain answer. Active Directory Users and Computers displays Telephone Number, the AD Attribute is telephoneNumber, but Set-ADUser oddly uses the parameter OfficePhone for setting it. Another quirk due to OfficePhone being a "special" field, when clearing with Set-ADUser you actually have to use telephoneNumber as the field. e.g.:
$Users = Import-Csv -Path C:\Results\EmployeeExtsTest.csv
ForEach ($UserEntry in $Users) {
$User = Get-ADUser -Filter "samAccountName -like '$($UserEntry.sAMAccountName)'" -Properties *
#Check to see if the user exists
if($User)
{
#Check to see if the Office Phone number has been cleared in CSV
if ([string]::IsNullOrEmpty($UserEntry.telephoneNumber))
{
#Clear the user's OfficePhone (telephoneNumber) in Active Directory
Set-ADUser -Identity $User -Clear telephoneNumber
}
else
{
#Update the user in Active Directory
Set-ADUser -Identity $User -OfficePhone $UserEntry.telephoneNumber
}
}
else
{
Write-Host "User $($UserEntry.sAMAccountName) does not exist in Active Directory"
}
}
One thing I add to my script is to use the -Filter parameter on my Get-ADUser that way I can verify the user exists without Get-ADUser throwing an error. See my answer for more information "Determine If Users Are In Active Directory With PowerShell":
The other method is to modify all of the properties all at once, and then use the Set-ADUser -Instance parameter to set them all at once (note: OfficePhone/telephoneNumber are special and have to be cleared manually like the above code, other fields can be manually cleared/set blank):
$Users = Import-Csv -Path C:\Results\EmployeeExtsTest.csv
ForEach ($UserEntry in $Users) {
$User = Get-ADUser -Filter "samAccountName -like '$($UserEntry.sAMAccountName)'" -Properties *
#Check to see if the user exists
if($User)
{
#Check to see if the Office Phone number has been cleared in CSV
if ([string]::IsNullOrEmpty($UserEntry.telephoneNumber))
{
#Clear the user's OfficePhone (telephoneNumber) in Active Directory
Set-ADUser -Identity $User -Clear telephoneNumber
}
else
{
#Modify Local instance of the user's properties
$User.OfficePhone = $UserEntry.telephoneNumber
}
#Modify Local instance of other user's properties
$User.GivenName = $UserEntry.GivenName
$User.Surname = $UserEntry.Surname
#..... etc.....
#Update the user in Active Directory
Set-ADUser -Instance $User
}
else
{
Write-Host "User $($UserEntry.sAMAccountName) does not exist in Active Directory"
}
}
I believe that you are being misled by what is displayed and what the actual name of the property is, due to behind-the-scenes aliasing.
Try using this instead:
set-aduser $user -OfficePhone $telephoneNumber
The final script that got me through this is here
$Users = Import-Csv -Path C:\Results\EmployeeExts.csv
ForEach ($U in $Users) {
$User = $U.sAMAccountName
$telephoneNumber = $U.telephoneNumber
Set-ADUser $User -OfficePhone $telephoneNumber
}
Because I work for a school district I will be adding on more to this in the future to look for employees that are missing. As it stands now this script just updated nearly 1000 AD accounts perfectly (aside from the missing employees that have left). I want to thank all of you for helping in giving me pieces of this answer. You've made me better at my job.
Special thanks to #PaulWain and #HAL9256
I have a list of users exported to a csv. Some of them have fax numbers, some of them do not. To add the number I need in there, I have this written:
$users = Import-Csv C:\ (My CSV path)
ForEach($user in $users) {
if(Get-ADUser $user.samaccountname -Properties fax -eq $null) {
Set-ADUser $user.samaccountname -add #{fax=$($user.fax)}
}
else {
Set-ADUser $user.samaccountname -Replace #{fax=$($user.fax)}
}
}
The error I get for this is:
-Properties : The term '-Properties' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again
Any help would be appreciated.
if(Get-ADUser $user.samaccountname -Properties fax -eq $null) - This is wierd.
I think you should do
$user = Get-ADUser $user.samaccountname -Properties fax
if (($null -ne $user) -or ($null -eq $user.fax)) {
There is no fax attribute in AD by default, but otherfacsimiletelephonenumber exists. It's preferred to use while setting, because you never know how exactly Cmdlets will interpret it.
Why you use if to check if fax -eq $null ? If there is no fax, you add it, and if there is, you replace it. Why not to replace always ?
Use pipelines
Among all, you should not check if user exists or fax exists, because you overwrite it, this results in one-liner:
Import-Csv C:\Csv.csv |
ForEach-Object {Set-ADUser -Identity $_.samaccountname -Replace #{'otherFacsimileTelephoneNumber'=$_.fax}}
I am trying to get only AD Objects of type user and then iterate over all them and change AD user object name. So I have done below:
$Users = Get-ADObject -Filter {(ObjectClass -eq "user")} # OR Get-ADObject -Filter 'ObjectClass -eq "user"'
$Users | foreach
{
# Here code to create name based on conditions ($newUserObjectName)
Rename-ADObject -Identity $_ -NewName $newUserObjectName
}
The problem is that Get-ADObject is returning not only users but also computer objects.... I only want user object classes. Also I am not sure If below line of code is correct by setting identity to $_ in order to update the current user in the iteration:
Rename-ADObject -Identity $_ -NewName $newUserObjectName
Why not use Get-ADUser instead of Get-ADObject and just return the DistinguishedName? Obviously, DON'T just run this code :)
$users = (Get-ADUser -Filter *).DistinguishedName #This gets all the users in AD
Foreach($user in $users){
Rename-ADObject -Identity $user -NewName $newUserObjectName
}
The Computer objectClass is derived from the User objectClass. Hence, queries for user class will return both Computers and Users. If you want to filter for Users only, you have to specify ObjectCategory as Person
$Users = Get-ADObject -Filter {(Objectclass -eq "user") -and (objectCategory -eq "Person")}
Use that or you can use the goodole Get-ADuser
Use Get-ADUser and Set-ADUser:
$Users = Get-ADUser -Filter *
$Users | foreach {
# Naming code
Set-ADUser -Identity $_.SamAccountName -SamAccountName $newName
}
This replaces all user's identities to $newName.
Note you can replace -SamAccountName with any other property of an ADUser. for example if you want to replace the display name instead, you would use -Name $newName
I'm trying to extract some readable variables from AD, the following works.
$user = get-aduser "username" -Properties memberof, emailAddress, extensionattribute2, manager, physicalDeliveryOfficeName, url
$groups = ForEach ($group in $user.memberof){(Get-ADGroup $group).Name}
$groupStr = $groups -join "; " #Change "; " to "`r`n" for line break seperator
$user | Select-Object `
#{N="firstName";E={$_.GivenName}}, `
#{N="lastName";E={$_.Surname}}, `
#{N="email";E={$_.EmailAddress}}, `
#{N="businessArea";E={$_.extensionattribute2}}, `
#{N="accountName";E={$_.SamAccountName}}, `
#{N="manager";E={$_.Manager -replace '^CN=|,.*$'}}, `
#{N="office";E={$_.physicalDeliveryOfficeName}}, `
#{N="standardProfile";E={$_.url}}, `
#{n='Groups'; e={$groupStr}} | Export-CSV -NoTypeInformation "c:\out.csv"
However when I swap Get-aduser "username" to: Get-aduser -Filter {Enabled -eq $true} -SearchBase “ou=redacted,ou=UserAccounts,dc=redacted,dc=com”
It runs for a fairly long time and fills up the last 40gb on the disk and errors out as it's run out of space.
I know in the past I've wildcarded -Properties and run into similar issues (obvious now I understand) but I'm not sure what's causing the issue this time round.
{Enabled -eq $true} & -SearchBaselimit it to about 4 thousand users which I wouldn't think would take this long to run, and I've no idea what's using up the disk space.
Thanks in advance!
A slight augment in your code can achieve the results you want:
$users = get-aduser -filter "Enabled -eq '$true'" -Properties memberof, emailAddress, extensionattribute2, manager, physicalDeliveryOfficeName, url
$users | Foreach-Object {
$groups = ForEach ($group in $_.memberof) {
(Get-ADGroup $group).Name
}
$groupStr = $groups -join "; " #Change "; " to "`r`n" for line break separator
$_ | Select-Object #{N="firstName";E={$_.GivenName}},
#{N="lastName";E={$_.Surname}},
#{N="email";E={$_.EmailAddress}},
#{N="businessArea";E={$_.extensionattribute2}},
#{N="accountName";E={$_.SamAccountName}},
#{N="manager";E={$_.Manager -replace '^CN=|,.*$'}},
#{N="office";E={$_.physicalDeliveryOfficeName}},
#{N="standardProfile";E={$_.url}},
#{n='Groups'; e={$groupStr}}
} | Export-CSV -NoTypeInformation "c:\out.csv"
In your original code, $groups contains all of the groups for all enabled AD Users if you don't pick a specific user object for get-aduser. This is because $user.memberof will return all groups for every user in the $user array. Imagine 10 groups per user at 5000 users. You would have 50000 groups per user in your CSV.
-Properties adds attributes to return from the objects you are querying. It does not impact the number of objects you return only the size of the returned result. -Properties * vs. -Properties Attribute1,Attribute2 will likely use more memory but won't impact your CSV since you are selecting (Select-Object) the attributes you want to output. If you run Get-ADUser username, it will return a default list of attributes, which does not include mail for example. If you want to see the mail value along with the default attributes, then you must run Get-ADUser username -Properties Mail.
Can someone assist me in how can I search all of AD for a users, who I would not know if exist or not.
Root domain (NA1.local)
Resource Domain (domain1.local, domain2.local, domain3.local)
MSmith (not sure where in the domain he\she is located or if the userid has been deleted from AD)
$user = PSmith
foreach ($domain in $domains)
{
Get-ADUser -Identity $username -Server $domain -ErrorAction SilentlyContinue
if ($? -eq 'True') {
$forest = Get-ADUser $username -Server $domain
Add-ADGroupMember -Identity $GPName -Member $forest -Server $VbrickSrv }
}
Specify the username with the -Filter or -LDAPFilter vs. the -Identity parameter. The filters are usually faster because they do the filtering on the DC instead of locally on the machine running the script. Also, the cmdlet won't generate an exception if nothing is returned when using the filter (over the identity) parameters.
$user = Get-ADUser -Filter { SamAccountName -eq 'psmith' }
...
I normally tell you to set the search base to whatever makes sense for your search. The more restrictive the better, but I see you want to search the entire domain. Just keep that in the back of your mind.
Check the following article out for a deeper discussion.
https://social.technet.microsoft.com/wiki/contents/articles/28485.filters-with-powershell-active-directory-module-cmdlets.aspx
As well as what #Adam said about using a filter rather than a where clause (which is the proper answer) , you can simplify your code a bit when you find the user
foreach ($domain in $domains) {
If ($u = Get-ADUser -Filter 'SamAccountName -eq "psmith"' -server $domain) {
Add-ADGroupMember -Identity $GPName -Members $u -Server $domain
Break #this should exit from the foreach loop
}
}