Set-ADuser extensionAttribute won't work but things like title will - powershell

I am writing a simple script that takes an already created user and updates an attribute based on what the admin put in.
The code works just fine if I replace extensionAttribute with for example title or something like that, but it won't with extensionAttributes.
I have tried a few things and other extensionAttributes but the code is so simple and it works with other Attributes. I am guess extensionAttributes require a bit more in the code that I am missing.
$name = Read-Host "AD Logon Name"
$key = Read-Host "Azure Key"
Set-ADUser $name -extensionAttribute6 $key -PassThru
Set-ADUser : A parameter cannot be found that matches parameter name 'extensionAttribute6'
Even though it exists it is not finding it.

Set-ADUser has a limited set of parameters covering the most commonly used attributes in AD. However, given the sheer amount of existing attributes and the fact that the AD schema is extensible, an attempt to have all attributes represented as parameters just wouldn't be feasible.
For attributes that are not represented as parameters use the parameter -Add or -Replace with a hashtable argument.
Set-ADUser $name -Replace #{'extensionAttribute6' = $key} -PassThru

Old thread, but this worked for me:
Import-Csv -Path "C:\data\12345.csv" |ForEach-Object {
Set-ADUser $_.samAccountName -replace #{
description = "$($_.description)"
extensionAttribute1 = "$($_.extensionAttribute1)"
extensionAttribute3 = "$($_.extensionAttribute3)"
initials = "$($_.initials)";
#additionalAttributeName = "$($_.additionalAttributeName)"
#additionalAttributeName = "$($_.additionalAttributeName)"
#additionalAttributeName = "$($_.additionalAttributeName)"
#additionalAttributeName = "$($_.additionalAttributeName)"
#additionalAttributeName = "$($_.additionalAttributeName)"
}
}
The top row of your .csv file would look like the following for this example:
samAccountname,description,extensionAttribute1,extensionAttribute3,initials

Related

Add smtp Proxy Addresses from users listed in a text file using PowerShell

I am trying to create a simple script to add Proxy Addresses to the AD field using PowerShell.
I was able to get it working using this, but now I am at a roadblock on how I can do this importing the usernames from a text file.
$Username = Read-Host -Prompt "Enter the username'
Set-AdUser $Username -add #{ProxyAddresses = "smtp:$Username#example.com,smtp:$Username#marketing.example.com" -split ","}
What I want to do now is instead of prompting for a username to be entered I just want to have a text file with username like this.
Text File Of Usernames: These will all be on a separate line. I am not sure how to format that way on here.
jallen
sdiggs
gdavis
mhyde
twhite
I am confused how to go forward with this. To my understanding I want to use Get-Content to create the username array and then for each line in the text file add the proxy addresses.
$Username = Read-Host -Prompt "Enter the username'
Set-AdUser $Username -add #{ProxyAddresses = "smtp:$Username#example.com,smtp:$Username#marketing.example.com" -split ","}
I want to remove the need for user input and import the username variables from a text file.
Assuming you have the txt file with each user in a new line as shown in your question, you're right, you can use Get-Content to read your file then you need to loop over each line:
(Get-Content path\to\yourfile.txt).Trim() | ForEach-Object {
try {
Set-AdUser $_ -Add #{ ProxyAddresses = "smtp:$_#example.com,smtp:$_#marketing.example.com".Split(",") }
}
catch {
# can do error handling here
Write-Error $_
}
}
The use of Trim() in this example is so it removes any excess of white space from the beginning and end of all lines.

Using a Variable as a Parameter - Powershell

I am trying to pass a variable through to be used as a parameter within a function. I'm not even sure if this is possible but below is what i am attempting to accomplish, what i have tried so far keeps kicking out a "positional parameter cannot be found that accepts argument" error
$Var = Read-host "enter Attribute number"
$CustomAtt = "CustomAttribute$Var"
Get-Mailbox -Identity $Email | Set-Mailbox -$CustomAtt "TestTest"
You cannot set cmdlet arguments that way in powershell. You can do what your are attempting to do by using a feature called argument splatting. Simply store your arguments in an array or hashtable and then apply them to the cmdlet using # symbol.
Like this:
$mailBoxAttributes = #{
$CustomAtt = "TestTest" }
Get-Mailbox -Identity $Email | Set-Mailbox #mailBoxAttributes

Use value directly in script

I have the following script. The issue i have is that i need to create a value before using the information gathered from the csv file. The first code is what works for me, the second code is how i would want to use it, where the value $uid is not create before
$users = import-csv c:\temp\users.csv
foreach ($user in $users){
$uid= $user.UserPrincipalName+":\calendar"
add-mailboxfolderpermission -identity $uid -user "calendar_reviewer" -AccessRights LimitedDetails
}
$users = import-csv c:\temp\users.csv
foreach ($user in $users){
add-mailboxfolderpermission -identity $user.UserPrincipalName+":\calendar" -user "calendar_reviewer" -AccessRights LimitedDetails
}
In short, your string composition isn't working like you're expecting it to.
If we use the following test function it'll demonstrate what's happening:
function Invoke-MyFunction
{
param( $Identity, $OtherParams )
write-host "identity = '$Identity'";
write-host "otherparams = '$OtherParams'";
}
In your first (working) example, PowerShell is concatenating the strings:
$uid = $user.UserPrincipalName+":\calendar"
Invoke-MyFunction -Identity $uid
# identity = 'myname:\calendar'
# otherparams = ''
but in your broken sample, it's not treating the $user.UserPrincipalName+":\calendar" as a single expression - it's treating +":\calendar" as a separate string that it passes as a second positional parameter:
Invoke-MyFunction -Identity $user.UserPrincipalName+":\calendar"
# identity = 'myname'
# otherparams = '+:\calendar'
There's a few different ways to get PowerShell to treat your parameter as an expression so it evaluates it before passing the value as a parameter:
Grouping Operator
As recommended by #zilog80 in the comments, wrap it in the Grouping operator (i.e. ( ... )) to force PowerShell to evaluate the expression before passing the result into the parameter:
Invoke-MyFunction -Identity ($user.UserPrincipalName+":\calendar")
# identity = 'myname:\calendar'
# otherparams = ''
String Interpolation
Per #Abraham Zinala's comment, use string interpolation (note the use of the Subexpression operator (i.e. $( ... ) to substitute in the value of $User.UserPrincipalName)
Invoke-MyFunction -Identity "$($User.UserPrincipalName):\calendar"
# identity = 'myname:\calendar'
# otherparams = ''
Assign to a variable
As you've already found, you can force the expression to be evaluated by assigning it to a temporary variable, then pass the variable as a parameter:
$uid = $user.UserPrincipalName+":\calendar"
Invoke-MyFunction -Identity $uid
# identity = 'myname:\calendar'
# otherparams = ''

Trying to create a powershell user creation script, want to append number to username if it already exists

I am attempting to create a user creation script as a way to teach myself more Powershell. Currently I am only working on creating just the username and want to make sure each username is unique.
After a user inputs the name and number of a user the script should do the following.
Get the the first name
Get the middle initial
Get the last name
Combine the first letter of the first name + middle initial + 6 characters from the last name
If users already exists, add number starting at 1 until username is unique.
I am currently stuck on step 5. If the username is not unique it appends a number one. I.E. User Brenda T Follower has a username of BTFollow and if that username exists already it becomes BTFollow1.
However if BTFollow and BTFollow1 already exist instead of making BTFollow2 it makes BTFollow12.
Lastly, although not a huge issue I want my parameters to show what comes after Read-Host but that text is not appearing only the variable name.
Here is my code.
Param(
#Gather users first name, required input and must not be empty or null
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[string]
$FirstName = (Read-Host -Prompt 'Please input the users first name.'),
#Gather users middle initial, required input and must not be empty or null and must only be one character
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[ValidateLength(1,1)]
[string]
$MiddleInitial = (Read-Host -Prompt 'Please input the users middle initial.'),
#Gather users last name, required input and must not be empty or null
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[string]
$LastName = (Read-Host -Prompt 'Please input the users last name.'),
#Gathers user phone extension, required input, mustn ot be empty or null, and must only user numbers
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[ValidatePattern("[0-9][0-9][0-9][0-9]")]
[ValidateLength(4,4)]
[String]
$PhoneExtension = (Read-Host -Prompt 'Please input the users 4 digit exension, numbers only')
)
$i = 0
#Create user name
$Username = $FirstName.Substring(0,1) + $MiddleInitial + $LastName.Substring(0,6)
#Check username does not exist, if it does add numbers
Do {
Try {
Get-ADUser $UserName | Out-Null
$UserName = $Username + ++$i
Continue
}
Catch {
Break
}
} While ($True)
Write-Host "Username is $Username"
Figured it out with the help of Reddit. I needed to replace my current code.
Do {
Try {
Get-ADUser $UserName | Out-Null
$UserName = $Username + ++$i
Continue
}
Catch {
Break
}
} While ($True)
New code that works.
#Check username does not exist, if it does add numbers
$UniqueUserName = $Username
while (Get-ADUser -Filter "SamAccountName -like '$UniqueUserName'"){
$UniqueUserName = $Username + ++$i
}
Because you iteratively modified $UserName in your loop, you ended up appending an additional number in each iteration:
$UserName = $Username + ++$i
With BTFollow as the original value, the value is BTFollow1 after the first iteration, and in the second iteration you then append 2 to that, resulting in BTFollow12, and so on.
Your own answer works (though -like should be replaced with -eq) and, given its appealing concision and the presumed relative rarity of duplicate names, is probably the way to go.
The following solution provides optimizations, but the required complexity may not be worth it; at least I hope it showcases some interesting techniques.
You can avoid a costly loop around Get-AdUser altogether, by pre-filtering potential duplicates with Get-ADUser -Filter and then processing the candidates locally:
$highestIndexSoFar =
Get-ADUser -Filter "SamAccountName -like '$UserName*'" |
ForEach-Object { if ($_.SamAccountName -match '\d*$') { [int] $Matches[0] } } |
Sort-Object -Descending | Select-Object -First 1
if ($null -eq $highestIndexSoFar) { # no duplicates -> use as-is
$UniqueUserName = $UserName
} else { # increment the highest index to date to make the username unique
$UniqueUserName = $UserName + (1 + $highestIndexSoFar)
}
Another advantage of the above solution is that it determines the highest number suffix in the actual names, which reliably uses a suffix that is the highest to date + 1, whereas the call-Get-AdUser-in-a-loop approach uses the first index that isn't taken (though that would only be a concern if users got deleted over time or if out-of-sequence suffixes were manually created).
Get-ADUser -Filter "SamAccountName -like '$UserName*'" retrieves potential duplicates; the -Filter syntax isn't sophisticated enough to allow regex-based matching, so this pre-filtering can only find all usernames that share the same prefix, which may include false positives (e.g., jdoet for jdoe, whereas ultimately only a numeric suffix such as jdoe1 should be considered).
Regex '\d*$' is then used to weed out such false positives, and the actual, potentially empty numeric suffix (\d*) is reflected in the automatic $Matches variable's [0] entry.
The numeric suffix, if present or empty, is then cast to [int] and output.
Note that an initially unindexed username such as BTFollow will cause $Matches[0] to be the empty string, which cast [int] converts to 0, so the first index appended will be 1.
Sort-Object -Descending sorts the resulting numbers in descending order, and Select-Object -First 1 then extracts the first - i.e. the highest - suffix number found, if any.
If no matches are found at all, i.e. if the username isn't taken yet, there is nothing to sort, and Select-Object -First 1 effectively yields $null; otherwise, 1 must be added to highest number to form the new unique username.
Caveat: This approach may still fail if others are creating users simultaneously.

Line break issue when configuring "send on behalf of"

I have a script to set send on behalf of permissions in Exchange Management Shell, but when you try and use it it fails because the output of the first part is too long and truncates over 2 lines.
First thing we do is build our array from lists of people and put them into some variables to pass:
function Add-Send ($mailbox, $target) {
#"Granting send on behalf for $mailbox to $target"
Set-Mailbox -Identity $mailbox -GrantSendOnBehalfTo #{ Add = $target }
}
We pass a long list as the $target and the maibox name is $mailbox and if we output the text we get:
Set-Mailbox -Identity "mr.jeff" -GrantSendOnBehalfTo #{ Add = "alan.alanson", "bob.bobson", "steve.stevenson" }
All fine and good but if there are more than N characters in the output then we get a line break:
Set-Mailbox -Identity "mr.jeff" -GrantSendOnBehalfTo #{ Add = "alan.alanson", "bob.bobson", "steve.stevenson", ...
..., "cath.cathdotir" }
When you run this script with the overlength output, then command fails as the output which should be passed to the CLI is passed over more than one line. PowerShell treats each line as a separate command, and they obviously fail with bad syntax.
Our string is output from an array that we build like this:
function Send-Array ($mailbox) {
$target = Get-Content ".\list\dpt1.txt"
$target += Get-Content ".\list\$mailbox.txt"
$target += Get-Content ".\list\dpt2.txt"
$target = $target | Select-Object -Unique
$separator = '", "'
$target= $target -replace '^|$','"' -join ','
Add-Send $mailbox $target
}
This gives us an array with strings that look like:
"alan.alanson", "bob.bobson", "steve.stevenson"
From here I am at a loss any ideas would be much appreciated.
The obvious solution would be to pass the names one at a time, but due to a gotcha with Exchange Server every time you set send on behalf of permissions with PowerShell it wipes the existing permissions, so you only end up with he last person granted permissions being able to send on behalf of.
See this link for help with your underlying issue.
Very basically, you will have to:
get the DistinguishedName of the user you need to add
store the current value of GrantSendOnBehalfTo in a variable
append the new user's distinguished name to the list
replace GrantSendOnBehalfTo with the new list
Afterwards you should not need to pass endless strings to the EMS (I hope so).