Fax number update script, how to reverse? - powershell

I have created a script that would allow for the addition of the values "1-" to the beginning of our current AD fax numbers. I am running this in a test environment and the script runs exactly as I want it. I am looking for a failback and I can't seem to get that script to remove the "1-" it instead removes the 1 from the beginning and the final number from the end of the fax so the output looks like this: "-(###)-###-###" instead of looking like the correct number format "(###)-###-####"
Get-ADUser -Filter {facsimileTelephoneNumber -like "*"} -Properties facsimileTelephoneNumber| foreach {Set-ADUser -Identity $_ –replace #{facsimileTelephoneNumber="1-$($_.facsimileTelephoneNumber)"}}
Get-ADUser -Filter {facsimileTelephoneNumber -like "*"} -Properties facsimileTelephoneNumber| foreach {Set-ADUser -Identity $_ –replace #{facsimileTelephoneNumber="$(($_.facsimileTelephoneNumber).Substring(1,($_.facsimileTelephoneNumber.length) -2 ))"}}

Following my answer to your previous question where the 1- is added to the fax number, this is how you can reverse that.
I see in your question you are trying to do it all as one-liners, thereby skipping all possibility to check your code step-by-step. Using the first oneliner in your question also prepends 1- to simply every faxnumber found, regardless if it is needed or not.
Especially when just starting PowerShell, writing things out is a good thing.
Having said that, here's the code to remove the leading 1- from faxnumbers
# Remove leading '1-' from ADUsers faxnumbers
Import-Module ActiveDirectory
# get all users in the specified OU that have a fax number starting with '1-'
Get-ADUser -LdapFilter '(facsimileTelephoneNumber=1-*)' -SearchBase 'OU=UserAccounts,DC=YourDomain,DC=com' -Properties 'Fax' | ForEach-Object {
# using Substring() to remove the first two characters. See: https://ss64.com/ps/substring.html
$newFax = ($_.Fax).Substring(2)
Write-Host "Setting Faxnumber to '$newFax' for user $($_.Name)"
# remove the '-WhatIf' if you are sure the number may be changed
$_ | Set-ADUser -Fax $newFax -WhatIf
}
Hope this helps

Related

Get samaccountname from display name - but with extras

First time poster but site has helped me so much in the past.
We are an MSP and regularly get requests from clients to pull various details off a list of users they send us. Unfortunately though their lists rarely (if ever) contain any unique identifiers for AD such as samAccountName or even e-mail.
So typically I only get their first and last names, job titles etc. and use a slight variation on the below to try and get the required samAccountNames to work in batch modify scripts.
Get Samaccountname from display name into .csv
The problem comes (and caused a big headache recently) when I try to put that output back into a table to line up with the displaynames. As if the script can't find the displayname it just moves onto the next one in the list and puts the samAccountName directly below the last one it found. making it out of line with the displayname column I've put it beside.
My question is is there something I can add to the below script that when an error occurs it simply inputs null or similar into the samAccountName output csv so I could spot that easily in an excel sheet.
Similarly some users have multiple accounts like an admin and non-admin account with the same display name but different samAccountName so it pulls both of them, which is less of a problem but also if there was any way to have the script let me know when that happens? That would be super useful for future.
Import-Module activedirectory
$displayname = #()
$names = get-content "c:\temp\users.csv"
foreach ($name in $names) {
$displaynamedetails = Get-ADUser -filter { DisplayName -eq $name } -server "domain.local"| Select name,samAccountName
$displayname += $displaynamedetails
}
$displayname | Export-Csv "C:\temp\Samaccountname.csv"
So the problem lies in that you rely on Get-ADUser to provide you with user objects and when it doesn't you have gaps in your output. You instead need to create an object for every name/line in your "csv" regardless of whether Get-ADUser finds anything.
Get-Content 'c:\temp\users.csv' |
ForEach-Object {
$name = $_
$adUser = Get-ADUser -Filter "DisplayName -eq '$name'" -Server 'domain.local'
# Create object for every user in users.csv even if Get-ADUser returns nothing
[PSCustomObject]#{
DisplayName = $name # this will be populated with name from the csv file
SamAccountName = $adUser.SamAccountName # this will be empty if $adUser is empty
}
} | Export-Csv 'C:\temp\Samaccountname.csv'

Prepend AD User description with PS - Duplicate Update with ForEach

I've seen many code examples where Get-ADUser can be used to append a description with the following code:
get-aduser username -Properties Description | ForEach-Object { Set-ADUser $_ -Description "$($_.Description) Some more stuff" }
I had thought I could simply invert the order of the code in order to prepend, like so:
get-aduser username -properties Description | ForEach-Object { Set-ADUser $_ -Description "Stuff To Use - $($_.Description)"}
The output then becomes:
"Stuff To Use - Stuff To Use"
In essence, whatever is there to start with is wiped out completely and replaced with a doubled up result of the intended goal.
What am I missing here?
The code is good and it likely ran twice accidentally.
Reset the description, run the code, then refresh Active Directory Users and Computers and recheck.

How to move multiple users to multiple OUs importing users from CSV and filtering by department

New to powershell and scripting in general. Trying to improve automation in our onboarding process, we have to move multiple user accounts to multiple OUs every couple of months.
Import-Module ActiveDirectory
$dept1 = "OU=Path1,DC=SOMEWHERE,DC=OUTTHERE"
$dept2 = "OU=Path2,DC=SOMEWHERE,DC=OUTTHERE"
Import-Csv "C:\Scripts\Incoming.csv" | ForEach-Object {
$samAccountName = $_."samAccountName"
Get-ADUser -Identity $samAccountName -Filter {Department -eq "Dept1"} | Move-ADObject -TargetPath $dept1
Get-ADUser -Identity $samAccountName -Filter {Department -eq "Dept2"} | Move-ADObject -TargetPath $dept2
}
This actually moves ALL users with the department marked into the path I have set.. but I only want it to look at those users in the csv and then filter their departments from AD - not the CSV. I feel like I'm missing a step but I've searched everywhere and tried the get-help. I feel like I need to get the identity, then search/filter against something else but I'm not quite sure how. Would appreciate any help.
edit
Okay, if I run the following:
Get-ADUser -Filter {Department -eq "Dept1"} -Properties Department
It returns everyone that fits that property but how do I compare those to the $samAccountName and ONLY try to move those accounts or run the commands against the accounts on the list? When I ran the second half of the command it tried to move them all and failed.
Move-ADObject $samAccountName -Target $dept1
I feel dumb.
It's ok to feel dumb. You're not and everyone feels that way at times when trying to learn a new thing. You're also here asking for help, so you're ahead of the game compared to a lot of others.
#Lee_Daily's comment is correct that Get-ADUser doesn't support using both -Identity and -Filter in the same command. They're part of different parameter sets. You can tell from the syntax output of Get-Help Get-ADUser or the online docs. Both show 3 different sets of parameters and Identity and Filter are not in the same one. What's odd is that your original script should have thrown an error because you tried to use both in the same command. No need to worry about that now though.
Here's a typical way one might approach this task. First, you query the user's details including the department you want to make a decision on. Then, you write your condition and perform the appropriate action. Doing it this way means you're only querying AD once for each user in your CSV rather than twice like your original script which is good for script performance and load on your AD. The inside of your ForEach-Object loop might look something like this. Note the addition of -Properties department in Get-ADUser. We need to ask for it explicitly because department isn't returned in the default result set.
# all of this goes inside your existing ForEach-Object loop
$u = Get-ADUser -Identity $_.samAccountName -Properties department
if ($u.Department -eq 'Dept1') {
$u | Move-ADObject -TargetPath $dept1
} elseif ($u.Department -eq 'Dept2') {
$u | Move-ADObject -TargetPath $dept2
}
Now let's talk about some alternative ways you might approach this.
The first way sort of flips things around so you end up only calling Get-ADUser once total, but end up doing a lot more filtering/processing on the client side. It's not my favorite, but it sets things up to understand my preferred solution. In particular, the Get-ADUser call uses the -LDAPFilter parameter. LDAP filter syntax is a little strange if you've never seen it before and this particular example could use the more common -Filter syntax just as easily. But in the next example it would be much more difficult and learning LDAP filter syntax enables you to query AD from anything rather than just PowerShell.
# instead of immediately looping on the CSV we imported, save it to a variable
$incoming = Import-Csv "C:\Scripts\Incoming.csv"
# then we make a single AD query for all users in either Dept1 or Dept2
$users = Get-ADUser -LDAPFilter '(|(department=Dept1)(department=Dept2))' -Properties department
# now we filter the set of users from AD by department and whether they're in the CSV and do the moves as appropriate
$users | Where-Object { $_.department -eq 'Dept1' -and
$_.samAccountName -in $incoming.samAccountName } | Move-ADObject -TargetPath $dept1
$users | Where-Object { $_.department -eq 'Dept2' -and
$_.samAccountName -in $incoming.samAccountName } | Move-ADObject -TargetPath $dept2
The benefit of this method is the single AD round trip for users rather than one for each in the CSV. But there are a lot more local loops checking the samAccountNames in the results with the samAccountNames from the CSV which can get expensive cpu-wise if your CSV and/or AD is huge.
The final example tweaks the previous example by expanding our LDAP filter and making AD do more of the work. AD is ridiculously good at returning LDAP query results. It's been fine-tuned over decades to do exactly that. So we should take advantange of it whenever possible.
Essentially what we're going to do is create a giant 'OR' filter out of the samAccountNames from the CSV so that when we get our results, the only check we have to do is the check for department. The way I verbalize this query in my head is that we're asking AD to "Return all users where SamAccountName is A or B or C or D, etc and Department is Dept1 or Dept2. The general form of the filter will look like this (spaces included for readability).
(& <SAM FILTER> <DEPT FILTER> )
# Where <DEPT FILTER> is copied from the previous example and
# <SAM FILTER> is similar but for each entry in the CSV like this
(|(samAccountName=a)(samAccountName=b)(samAccountName=c)...)
So let's see it in action.
# save our CSV to a variable like before
$incoming = Import-Csv "C:\Scripts\Incoming.csv"
# build the SAM FILTER
$samInner = $incoming.samAccountName -join ')(samAccountName='
$samFilter = "(|(samAccountName=$samInner))"
# build the DEPT FILTER
$deptFilter = '(|(department=Dept1)(department=Dept2))'
# combine the two with an LDAP "AND"
$ldapFilter = "(&$($samFilter)$($deptFilter))"
# now make our single AD query using the final filter
$users = Get-ADUser -LDAPFilter $ldapFilter -Properties department
# and finally filter and move the users based on department
$users | Where-Object { $_.department -eq 'Dept1' } | Move-ADObject -TargetPath $dept1
$users | Where-Object { $_.department -eq 'Dept2' } | Move-ADObject -TargetPath $dept2
There are more efficient ways to build the LDAP filter string, but I wanted to keep things simple for readability. It's also a lot easier to read with better PowerShell syntax highlighting than StackOverflow's. But hopefully you get the gist.
The only limitation with using this method is when your incoming CSV file is huge. There's a maximum size that your LDAP filter can be. Though I'm not sure what it is and I've never personally reached it with roughly ~4000 users in the filter. But even if you have to split up your incoming CSV file into batches of a few thousand users, it's still likely to be more efficient than the other examples.

Attempting to edit fax number in AD for all users with a fax number listed

I will first begin on saying I am very new to PowerShell and my question is probably very easy to solve. All I am trying to do is use Get-QADuser and grab all ad users with a fax number listed, once I have that I simply want to add a "1" to all those users at the beginning of said fax number. I am trying to go based on the code I see below, but I don't believe this is exactly what I need. Any and all help is appreciated!
Get-QADUser -SearchRoot "abc.com/ABC/Users" -LdapFilter '(facsimileTelephoneNumber=555-555-1234)' | Foreach-Object{Set-QADuser -Identity $_ -ObjectAttributes #{facsimileTelephoneNumber='555-555-4321'}}
Without using Quest tools, you could do something like below.
The assumption here is that you would like to add the 1 to a formatted faxnumber, so I'm going for prepending 1- to the existing number, but ONLY if the existing number does not already start with 1 or + (used for country codes).
Right now, the -WhatIf switch will make the code only output what WOULD happen so you can investigate if this is what you really want.
If you're happy with the output, remove the -WhatIf switch so the code actually updates the faxnumbers where applicable.
Import-Module ActiveDirectory
# get all users in the specified OU that have a fax number
Get-ADUser -LdapFilter '(facsimileTelephoneNumber=*)' -SearchBase 'OU=UserAccounts,DC=YourDomain,DC=com' -Properties 'Fax' | ForEach-Object {
# test if the number starts with a '1' or a '+' and if that is NOT the case, prepend '1-' to the number
if ($_.Fax -notmatch '^[+1].*') {
# the faxnumber does not already start with "1" or "+"
$newFax = '1-{0}' -f $_.Fax
Write-Host "Setting Faxnumber to '$newFax' for user $($_.Name)"
# remove the '-WhatIf' if you are sure the number may be changed
$_ | Set-ADUser -Fax $newFax -WhatIf
}
else {
Write-Host "Faxnumber '$($_.Fax)' for user $($_.Name) remains unchanged" -ForegroundColor Yellow
}
}
P.s. The -SearchBase is the DistinghuishedName property of the OU the users are in. Start 'Active Directory Users and Computers' (ADUC), select and right-click the wanted OU and choose 'Properties'. In tab 'Attributes' scroll down to distinghuishedName, double click and copy from there.

Edit Description field for users

I’m trying to clean up my AD user accounts, in the past my organization would put a date in the beginning of the Description field for the users…
I can get all the text in Description field using PowerShell but I don’t know how to delete only the date in the “Description” field.
And the date in the field is written in the following formats: mm/dd/yy or mm/dd/yyyy
Get-ADUser -SearchBase $OU_To_Search -Filter {(description -like '*/*/* ^az') -and (enabled -eq $true)} -Properties cn,description | Export-csv C:\temp\A_Users.csv
I’m sure there is a better way of getting the date… but I’m not there yet.
You could set the Description field to a variable and use the -replace parameter to remove the date like so:
$this = $this -replace "([0-9]+)/([0-9]+)/([0-9]+) ",""
Then, it's just a matter of using Set-ADUser to replace the current description
You can put your search, and then run your results through a -replace option and replace the regex filter of \d{1,2}/\d{1,2}/\d{2,4}\s? (that's 1 or 2 numbers, followed by a slash, followed by 1 or 2 number, followed by a slash, followed by two through four numbers, and then if there's a space after it include that) and just leave off the item to replace it with so it simply removes it. Then output the updated result. Lastly I have it exporting to a CSV as you did above.
Get-ADUser -SearchBase $OU_To_Search -Filter {(description -like '*/*/* ^az') -and (enabled -eq $true)} -Properties cn,description|%{$_.Description -Replace "\d{1,2}/\d{1,2}/\d{2,4}\s?";$_}| Export-csv C:\temp\A_Users.csv
Alternatively you could have it Set-ADUser $_ instead just outputting it to the pipe to be exported to CSV. To do that you would change ;$_} to ;Set-ADUser $_} and leave off the |Export-CSV bit at the end.