I was creating what I thought was a super-simple PowerShell script to update the location field with "Mobile: " + Mobile Phone number. Using the limited fields on GAL to show mobile number for all users.
Somehow, I only get the "Mobile: " without the number. I have tried many variations of this same script but ultimately $User.mobile is incorrect.
Import-Module ActiveDirectory
$Userlist = Get-ADUser -Server XXXXX -filter * -SearchBase "OU=Users,OU=Corporate,OU=XXXXXXXX,DC=XXXXXX,DC=com"
foreach ($User in $Userlist) {
$newlocation = "Mobile: "
$newlocation = $newlocation + $User.mobile
Set-ADUser -Instance $User
}
# Update properties.
Two things you need to change here:
Include the mobile and location attributes in the original Get-ADUser query, it won't retrieve these by default:
$Userlist = Get-ADUser -Server XXXXX -filter * -Properties mobile,physicalDeliveryOfficeName -SearchBase "OU=Users,OU=Corporate,OU=XXXXXXXX,DC=XXXXXX,DC=com"
and then make sure you actually modify the $User object before calling Set-ADUser:
foreach ($User in $Userlist) {
$newlocation = "Mobile: " + $User.mobile
$User.physicalDeliveryOfficeName = $newlocation
Set-ADUser -Instance $User
}
The Get-AdUser adding -properties was the answer. It worked like a charm.
$Userlist = Get-ADUser -Server XXXXX -filter * -Properties mobile,physicalDeliveryOfficeName -SearchBase "OU=Users,OU=Corporate,OU=XXXXXXXX,DC=XXXXXX,DC=com"
foreach($User in $userlist)
{
$newlocation = "Mobile: " + $User.mobile
$User.physicalDeliveryOfficeName = $newlocation
Set-ADUser -Instance $User
}
Related
I've cobbled together (from various online sources) a script that can return data about AD users from a CSV file. It can clearly mark when a user has NOT been found, but perhaps just as important to me is a way of outputting a blank line to the CSV file when the input CSV file also has a blank. That would save a lot mucking around in Excel to make sure that all the blank lines correspond to each other (and subsequently where user data has been found). A 1-to-1 comparsion is the goal.
Here is what I have...
$ImportCSV = "C:\Users\x\Desktop\testCSV_in.csv"
$Names = Import-Csv -Path $ImportCSV
$Results = foreach ($Name in $Names) {
$filter = $Name.samAccountName
$User = Get-ADUser -Filter "SamAccountName -like '$filter'" -Properties Samaccountname, Givenname, Surname, EmailAddress, Name
#blank lines input CSV
if ( $User.SamAccountName -eq "" ) {
# please help
}
# found user
if ( $User ) {
$User |
Select-Object -Property Samaccountname, Givenname, Surname, EmailAddress, Name
}
# not found user
else {
[pscustomobject]#{
SamAccountName = 'MISSING ACCOUNT'
}
}
}
$Results | Export-Csv -Path "C:\Users\x\Desktop\testCSV_out.csv" -NoTypeInformation -Encoding UTF8
All the possible combinations that I can think of for $User.SamAccountName -eq "" just return back a CSV file that doesn't reflect the gaps that I purposely introduced (to mimic real use-cases).
I am sure, it's a just a line or two code that's needed. Thanks.
If you want a normalized export you need a normalized Object, meaning, all columns for your CSV must exist for all lines, even if they're $null. Try this code, see if it works:
$out = {
param($samAccountName)
[pscustomobject]#{
Samaccountname = $samAccountName
Givenname = $User.GivenName
Surname = $User.SurName
EmailAddress = $User.EmailAddress
Name = $User.Name
}
}
Import-Csv -Path 'C:\Users\x\Desktop\testCSV_in.csv' | ForEach-Object {
if([string]::IsNullOrWhiteSpace($_.samAccountName)) {
return & $out -samAccountName 'User Not Found on CSV'
}
$params = #{
Properties = 'Samaccountname', 'Givenname', 'Surname', 'EmailAddress', 'Name'
LDAPFilter = "(SamAccountName={0})" -f $_.samAccountName
}
$user = Get-ADUser #params
if(-not $user) {
return & $out -samAccountName 'User Not Found on AD'
}
& $out -samAccountName $user.samAccountName
} | Export-Csv -Path "C:\Users\x\Desktop\testCSV_out.csv" -NoTypeInformation -Encoding UTF8
Edit: Import-Csv, same as ConvertFrom-Csv will skip empty lines. At least one column has to be populated.
I found a way to get this same functionality and also add manager email and calculated fields as well:
Import-CSV C:\test\CSV_in.csv |
ForEach-Object {
Try{
$u = Get-ADUser $_.samaccountname -Properties * -ErrorAction Stop | Select GivenName, Surname, samaccountname, Title, Department, #{N='Manager';E={(Get-ADUser $_.Manager).Name}},#{N="ManagerEmail";E={(Get-ADUser -Property emailaddress $_.Manager).emailaddress}}
[PSCustomObject]#{User = $_.name; samaccountname = $u.samaccountname; Manager = $u.Manager; ManagerEmail = $u.ManagerEmail}
}
Catch{
[PSCustomObject]#{User = $_.name; samaccountname = 'Not Found'; Manager = 'N/A'; ManagerEmail = 'N/A'}
}
} | Export-CSV c:\test\CSV_out.csv -NoTypeInformation
Can't seem to figure out what is causing the error with script below with the "New-ADUser" syntax. Not sure if anybody can spot the error?
"New-ADUser : The object name has bad syntax
At D:\ScriptPath\importadusersAndMoveOU.ps1:33 char:3"
The script works if I remove the "$NewOU" variable and have the users imported into the default "users" OU.
# Import active directory module for running AD cmdlets
Import-Module activedirectory
#Store the data from ADUsers.csv in the $ADUsers variable
$ADUsers = Import-csv 'D:\CSVPATH\adusers.csv'
$NewOU = New-ADOrganizationalUnit -Name "ADMINS"
#Loop through each row containing user details in the CSV file
foreach ($User in $ADUsers)
{
#Read user data from each field in each row and assign the data to a
variable as below
$DomainName = Get-ADDomain -current LocalComputer
$Username = $User.username
$Password = "TestPassword12345"
$Firstname = $User.firstname
$Lastname = $User.lastname
$OU = $NewOU+","+$DomainName.DistinguishedName
$upn = $Username+"#"+$DomainName.DNSRoot
#Check to see if the user already exists in AD
if (Get-ADUser -F {SamAccountName -eq $Username})
{
#If user does exist, give a warning
Write-Warning "A user account with username $Username already exist in Active Directory."
}
else
{
#User does not exist then proceed to create the new user account
#Account will be created in the OU provided by the $OU variable read from the CSV file
New-ADUser `
-SamAccountName $Username `
-UserPrincipalName $upn `
-Name "$Firstname $Lastname" `
-GivenName $Firstname `
-Surname $Lastname `
-Enabled $True `
-DisplayName "$Lastname, $Firstname" `
-Path $OU `
-AccountPassword (convertto-securestring $Password -AsPlainText -Force) -ChangePasswordAtLogon $True
Add-ADGroupMember "domain admins" $username
Add-ADGroupMember "enterprise admins" $Username
}
}
The New-ADOrganizationalUnit -Name "ADMINS" command creates a new OU under the default NC head for the domain.
If you want that elsewhere, you should use the -Path <DistinghuisedName of Parent OU> parameter.
However, as Drew Lean already commented, this code does not check if the OU exists before trying to create it, so a quick test might be in order here:
[adsi]::Exists("LDAP://OU=ADMINS,DC=domain,DC=com")
or
Get-ADOrganizationalUnit -Filter "distinguishedName -eq 'OU=ADMINS,DC=domain,DC=com'"
# don't filter on 'Name' because it is more than likely you have several OUs with the same name
Next, the part where you construct the distinguishedName for variable $OU results in a badly formatted string.
$OU = $NewOU+","+$DomainName.DistinguishedName will result in "ADMINS,DC=domain,DC=com" which is not a valid DistinghuishedName, hence the error The object name has bad syntax
Try getting the DN of the existing OU first and if that does not exist, capture it after the creation and store the DistinghuishedName in variable $OU
something like this:
$OU = "OU=ADMINS,DC=domain,DC=com"
if (-not (Get-ADOrganizationalUnit -Filter "distinguishedName -eq '$OU'")) {
$NewOU = New-ADOrganizationalUnit -Name "ADMINS" -PassThru
$OU = $NewOU.DistinghuishedName
}
ps. The Identity parameter for Get-ADOrganizationalUnit must be one of:
A distinguished name
A GUID (objectGUID)
A security identifier (objectSid)
A Security Account Manager account name (sAMAccountName)
I'm doing a virtual machine test, I have the following dilemma.
I want to modify a field to users who have HomeDirectory configured, for a new DFS path.
I have this script I does not work:
$user = Get-ADUser -Filter {HomeDirectory -like '*'} -Properties HomeDirectory | Select-Object samaccountname
Set-ADUser -Identity $user -Replace #{homeDirectory="\\\mboulaayoun.com\comu\personals\$user"}
Hi guys finnaly i get the correct way o do this, i hope can help someone with the same o similar problem.
$user = Get-ADUser -Filter {HomeDirectory -like '*'} -Properties HomeDirectory, HomeDrive
foreach($e in $user)
{
$name= $e.SamAccountName
$drive = $e.HomeDrive
Set-ADUser -Identity $name -HomeDirectory \\mboulaayoun.com\comu\personals\$nom -HomeDrive $drive
}
I am running a PowerShell script that gets some information from a csv file, stores it in an object array and then does some action depending on what's on the file. It actually only does one thing:
If one column has a AD group it copies the row for every member of that group.
The thing is I am really new at scripting and at the beginning the files were small, so everything went ok. Now I have huge files and the script is taking hours to execute.
$file = "c:\Report.csv"
$fileContent = Import-csv $file | select *, UserName
foreach($item in $fileContent)
{
$LoginName = $item.LoginName
$LoginNameClean = $LoginName.split("\")
$LoginNameClean = $LoginNameClean[1].trimstart("_")
$ObjectClass = (Get-ADObject -filter {SamAccountName -eq $LoginNameClean}).ObjectClass
$UserName = $null
if($ObjectClass -eq "user")
{
$UserName = Get-ADUser -identity $LoginNameClean -properties DisplayName
if($UserName)
{
$item.UserName = $UserName.DisplayName
}
}
elseif($ObjectClass -eq "group")
{
$GroupUsers = Get-ADGroupMember -identity $LoginNameClean -Recursive
foreach($user in $GroupUsers)
{
$UserInsideGroup = Get-ADUser -identity $user -properties DisplayName
$UserInsideGroupName = $UserInsideGroup.DisplayName
$newRow = New-Object PsObject -Property #{"URL" = $item.URL; "SiteListFolderItem" = $item.SiteListFolderItem; "TitleName" = $item.TitleName; "PermissionType" = $item.PermissionType; "LoginName" = $item.LoginName; "Permissions" = $Item.Permissions; "UserName" = $UserInsideGroup.DisplayName;}
$fileContent += $newRow
}
}
}
$fileContent | Export-Csv -NoTypeInformation -Path "c:\ReportUpgraded.csv"
Any tips on how to improve the performance of this is much appreciated
Thanks in advance.
edit: I am using PS 2.0
As commentaries suggested, I am trying to replace the fileContent += newRow.
I am trying to use add member but it's giving me this error:
Add-Member : Cannot add a member with the name "URL" because a member
with that name already exists. If you wan t to overwrite the member
anyway, use the Force parameter to overwrite it. At line:1 char:26
+ $fileContent | Add-Member <<<< -MemberType NoteProperty -Name "URL"-Value "teste"
+ CategoryInfo : InvalidOperation: (#{SiteListFolde...me=; URL=teste}:PSObject) [Add-Member], Inv
alidOperationException
+ FullyQualifiedErrorId : MemberAlreadyExists,Microsoft.PowerShell.Commands.AddMemberCommand
How I can I use this properly? Add-member is not adding but replacing members
I manage to reduce 30 times the execution time with a couple of things.
First, I switched array to a array list so that I could use theArray.Add() method. Then, in order to stop making requests to the AD all the time, I am saving the information in excel sheets with the name of the group, so that it will only request AD once per group.
Here is the script:
$file = "ReportBefore.csv"
$fileContent = Import-csv $file | select *, UserName
[System.Collections.ArrayList]$ArrayList = $fileContent
foreach($item in $fileContent)
{
$LoginName = $item.LoginName
$LoginNameClean = $LoginName.split("\")
$LoginNameClean = $LoginNameClean[1].trimstart("_")
$ObjectClass = (Get-ADObject -filter {SamAccountName -eq $LoginNameClean}).ObjectClass
$UserName = $null
if($ObjectClass -eq "user")
{
$UserName = Get-ADUser -identity $LoginNameClean -properties DisplayName
if($UserName)
{
$item.UserName = $UserName.DisplayName
}
}
elseif($ObjectClass -eq "group")
{
$exportString = "\\folder\username$\Desktop\ADGroups\" + $LoginNameClean + ".csv"
if([System.IO.File]::Exists($exportString))
{
$GroupUsers = Import-csv $exportString | select *
}
else
{
$GroupUsers = Get-ADGroupMember -identity $LoginNameClean -Recursive | Select samAccountName,Name, #{Name="DisplayName";Expression={(Get-ADUser $_.distinguishedName -Properties Displayname).Displayname}}
$GroupUsers | Export-Csv -NoTypeInformation -Path $exportString
}
foreach($user in $GroupUsers)
{
$UserInsideGroupName = $user.DisplayName
$newRow = New-Object PsObject -Property #{"URL" = $item.URL; "SiteListFolderItem" = $item.SiteListFolderItem; "TitleName" = $item.TitleName; "PermissionType" = $item.PermissionType; "LoginName" = $item.LoginName; "Permissions" = $Item.Permissions; "UserName" = $UserInsideGroupName;}
#$filecontent += $newRow
$ArrayList.Add($newRow)
}
}
}
$ArrayList | Export-Csv -NoTypeInformation -Path "\ReportAfter.csv"
I want to know if a user whom username is delivered is member of a group whom groupname is delivered.
$u = Get-WmiObject -Class Win32_UserAccount -Filter "Name='$username'"
$g = Get-WmiObject -Class Win32_Group -Filter "Name='$groupname'"
So I get two object with the property SID.
How can I check that user $u is member of group $g?
You can do this with an Associators query (example). Which are notoriously slow but do work.
$u = Get-WmiObject -Class Win32_UserAccount -Filter "Name='user'"
$group = Get-WmiObject -Class Win32_Group -Filter "Name='group'" | Select-Object -ExpandProperty Caption
$u | foreach {
$query = “Associators Of {Win32_UserAccount.Domain='” `
+ $_.Domain + “',Name='” + $_.Name `
+ “'} WHERE AssocClass=Win32_GroupUser”
$memberOf = Get-WmiObject -Query $query |
select -ExpandProperty Caption
If($memberOf -contains $group){
Write-Host "$($_.Name) is a member of $group"
} Else {
Write-Host "$($_.Name) is not a member of $group"
}
}
Get the use you are looking for and group your are checking to see if the user is a member of. While u$ should be only one user it is still a collection with one member. Pipe it into a ForEach-Object and build the Associators query. Execute the query and return all the group captions ( domain\groupname). Since $memberof is an array we can use -contains to see if the group you are looking for is there.
Alternatively
You could use the AD cmdlets if you have access to them and run the following
(Get-ADUser $user -Properties memberof | Select-Object -ExpandProperty memberof) -contains (Get-ADGroup -Identity $group)
The above will return True or False. You can install Ad cmdlets by using import-module activedirectory
Continued Testing
OpenLDAP should support this from what I gather and it's much faster then the previous WMI.
$search = [adsisearcher]"(&(objectcategory=user)(Name=userFullName))"
$userLDAP = $search.FindOne().Path
$userMembers = ([ADSI]$userLDAP).memberof
$search = [adsisearcher]"(&(objectcategory=group)(Name=groupname))"
$group = ($search.FindOne().Path) -replace "LDAP://"
$userMembers -contains $group
Sorry as I do not have access to OpenLDAP for testing. Do a search for a user and get the MemberOf as $userMembers. Then get the group into $group. Needed to remove the LDAP prefix from the string. Then just do another -Contains again.