Im having issues setting an attribute value in AD when using a function. When I use Set-ADUser under the same conditions without using a function I do not get an issue, it works great. When using Set-ADUser within a function I am getting an invalid argument error. I need to use a function as I am comparing a lot of data values. Alot of data is going to be compared this the need for a function. Im stumped.
function compareandset($value_ad, $value_csv, $userid, $propdata) {
$id = $userid.SamAccountName
IF($value_ad -eq $value_csv) {
Write-Host "The values were the same!"
}
ELSEIF($value_ad -ne $value_csv) {
Write-Host "AD value changed"
get-aduser -filter {SamAccountName -eq $userid} | Set-ADUser -$propdata $value_csv
}
}
$userid = "jsmith"
$value_ad = "A city"
$value_csv = "Not a city"
$propdata = "Office"
compareandset $Office $office_csv_value $userid $propdata
What does the full error message say? You can try using splatting and change:
...
Write-Host "AD value changed"
get-aduser -filter {SamAccountName -eq $userid} | Set-ADUser -$propdata $value_csv
}
...
to:
...
Write-Host "AD value changed"
$params = #{$propdata=$value_csv}
get-aduser -filter {SamAccountName -eq $userid} | Set-ADUser #params
}
...
More about splatting here: http://technet.microsoft.com/en-us/library/jj672955.aspx
Related
I need help with the code below. I want the script to perform the following: prompt the user for an AD group name, if the group name is found, export the group members to a CSV file. one of the requirements is that I must include a function statement. Thank you in advance.
The code works if I use a variable like the following example: $groupsusers = Get-ADGroup -Identity $nameofgroup, instead of the function statement.
However, I don't want to use a variable, I want to implement a function statement.
$prompt = "Enter A Group Name"
do
{
$nameofgroup = Read-Host $prompt
}
until(!$(dsquery Group-Object $nameofgroup; $prompt = "Group
'$nameofgroup' was not found, try again"))
$nameofgroup = Read-Host $prompt
function GetGroupInfoToCsv (#what parameters go here?){
ForEach-Object{
$settings = #{ Group = $_.DistinguishedName; Member = $null }
$_| Get-ADGroupMember |
ForEach-Object{
$settings.Member = $_.DistinguishedName
New-Object PsObject -Property $settings
}
}
}
GetGroupInfoToCsv | Export-Csv .\GroupMembers.csv -NoTypeInformation
You could combine the asking for user input and returning the info into the same function. Something like this:
function Get-GroupMembers {
$prompt = "Enter A Group Name. Press Q to quit"
# create an endless loop
while ($true) {
Clear-Host
$answer = Read-Host $prompt
# if the user has had enough, exit the function
if ($answer -eq 'Q') { return }
# try and find one or more AD groups using the answer as (part of) the name
$group = Get-ADGroup -Filter "Name -like '*$answer*'"
# if we have found something, exit the while loop and start enumerating the members
if ($group) { break }
$prompt = "Group '$answer' was not found, try again. Press Q to quit"
}
# you only get here if Get-ADGroup found one or more groups
$group | ForEach-Object {
# output a PSObject with the properties you are after
$members = $_ | Get-ADGroupMember
foreach ($member in $members) {
[PsCustomObject]#{
'Group' = $_.DistinguishedName
'Member' = $member.DistinguishedName
}
}
}
}
# call the function
$groupinfo = Get-GroupMembers
# test if the function returned anything.
# the user could have cancelled of the group had no members to output
if ($groupinfo) {
Write-Host "Adding $($groupinfo.Count) items to the CSV file"
# without -Append, you would overwrite your CSV file..
$groupinfo | Export-Csv .\GroupMembers.csv -NoTypeInformation -Append
}
else {
Write-Host 'Nothing found..'
}
As you can see, I have changed the function name so it complies with the Verb-Noun convention in PowerShell.
I would really appreciate it if somebody could point out what I am doing wrong in passing parameters from a function back to the mainline code. I have a variable which has been successfully extracted in a function, but I cannot seem to pass that back to the mainline code
This is the code I am using:
function get-field ($field, $heading) {
$fieldPos = $script:source.AllElements.InnerText.IndexOf($heading) +1
$field = $script:source.AllElements.InnerText[$fieldPos]
# If states "Not Available", or contains a heading, process as if not found.
if ($field -eq "Not Available ") {$fieldPos = 0}
if ($field -eq $heading) {$fieldPos = 0}
# Check that a valid entry was received
if ($fieldPos -eq 0) {
Write-Host "Warning:" $heading "was not found"
} else {
$field = $field.Trim()
}
return $field
}
get-field $email "Name"
get-field $address "Address"
I have verified that within the function, the $field and $heading parameters contain the correct information, so why aren't the $email and $address fields being populated?
You're not doing it totally wrong.
Have a look at this example:
function get-field ($field, $heading) {
return "$field - $heading"
}
$address = get-field "AddressFiled" "AddressHeading"
$address
to catch the returned value in a variable for further use, you should call the function like in the above example.
Parameters in PowerShell are normally used for passing values into a function. The output of a function must be assigned to a variable in the statement that invokes the function. Also, it's bad design to use global variables inside a function, because that makes debugging significantly more difficult.
Your code should look somewhat like this:
function Get-Field ($data, $heading) {
$fieldPos = $data.IndexOf($heading) + 1
$field = $data[$fieldPos].Trim()
# If states "Not Available", or contains a heading, process as if not found.
if ($field -eq 'Not Available' -or $field -eq $heading) {
Write-Host "Warning: ${heading} was not found"
}
$field
}
$email = Get-Field $script:source.AllElements.InnerText 'Name'
$address = Get-Field $script:source.AllElements.InnerText 'Address'
You can have out parameters if you want to, but they're rather uncommon in PowerShell, probably because they're not as straight-forward to use as one would like.
function Get-Field ([ref]$field, $data, $heading) {
$fieldPos = $data.IndexOf($heading) + 1
$field.Value = $data[$fieldPos].Trim()
# If states "Not Available", or contains a heading, process as if not found.
if ($field -eq 'Not Available' -or $field -eq $heading) {
Write-Host "Warning: ${heading} was not found"
}
}
$email = $null
Get-Field ([ref]$email) $script:source.AllElements.InnerText 'Name'
$address = $null
Get-Field ([ref]$address) $script:source.AllElements.InnerText 'Address'
function UpdateCSV
{
param(
[Parameter(Mandatory=$true)]$path,
[Parameter(Mandatory=$true)]$Row,
[Parameter(Mandatory=$true)]$exportpath,
[Parameter(Mandatory=$true)]$Delimiter
)
try{$csv = import-csv "$path" -Delimiter $Delimiter | Select-Object *,#{ Name= 'Department' ; Expression= {'Unkown'} },
#{ Name='Office' ; Expression= {'Unkown'} },
#{ Name= 'ADStatus' ; Expression= {'Unkown'} }
}
catch{break}
$result = foreach($user in $csv){
$userrow = $user.$row
write-host "$userrow"
$Username = $userrow.trim()
$ADUser = get-aduser -Filter {name -like $Username -or CN -like $Username -or sAMAccountType -like $Username} -Properties * -ErrorAction SilentlyContinue
if(!$ADUser){
$user.Department = "No ADUser"
$user.Office = "No ADUser"
$user.ADStatus = "No ADUser"
}
else{
$user.$row = $Username
if($ADUser.department -gt $null){$user.Department = $ADUser.department}
else{$user.Department = "Empty"}
if($ADUser.office -gt $null){$user.office = $ADUser.office}
else{$user.Office = "Empty"}
$user.ADStatus = $ADUser.enabled
}
$user
}
$result | export-csv "$exportpath" -Delimiter ";" -ErrorAction Stop
}
What I am trying to do is let a parameter reference the name of the row where I have the users name but when i user "$user.$row" it doesn't work and in the write-host section it writes out the full column instead of only the row I specify in $row
But if I instead hardcode $userrow = "$user.example" it works directly and in the write-host section it only writes out the that value instead all of the column
So the question is how do I call upon a row that i have the name of in a variable.
This is the first time writing something that will be used by others than me, so please do point out if there is some glaring misstakes
I think what you are looking for is $_.columnheading
When you import-csv and then pipe it, the column heading is the name of the value.
If you imagine each row as your object and each column heading as the values of the object. When you import-csv, each object is piped through individually.
$_ is the current object that has been piped through. Therefore:
$_.department or $_.name etc. will have the value you are looking for.
I hope this makes sense and is answering your question.
Thanks, Tim.
UPDATED AFTER COMMENTS
try{$csv = import-csv "$path" -Delimiter $Delimiter | Select-Object *,#{ Name= 'Department' ; Expression= {'Unkown'} },
#{ Name='Office' ; Expression= {'Unkown'} },
#{ Name= 'ADStatus' ; Expression= {'Unkown'} }
#{ Name= 'User' ; Expression= {$_.columnheadingforusercolumn}
}
$result = foreach($user in $csv){
$userrow = $user.user
write-host "$userrow"
}
I'm trying to compare a list of terminated employees to the AD attribute EmployeeNumber.
When I run the code below it appears that it only returns null for each employee number.
I receive the error for each user:
User does not exist in AD
What am I doing wrong with the compare?
$file = Import-CSV Term.csv
foreach ($u in $file) {
$user = Get-ADUser -LDAPFilter "EmployeeNumber -eq $($u.Emp)"
If ($user -eq $Null) {
"User does not exist in AD " + $u.EmployeeName + " - " + $u.Emp
} Else {
Disable-ADAccount $user
Move-ADObject $user -TargetPath 'OU=Disabled Users,OU=Org Users,DC=Company,Dc=com'
Set-ADUser $user -Description "Account Disabled on $(get-date)"
}
}
Your Get-ADUser command is using the LDAPFilter parameter, but not using LDAP Filtering syntax in it. You have two options here, change the parameter to -Filter or change the filtering sytax.
Get-ADUser -Filter
Get-ADUser -Filter "EmployeeNumber -eq $($u.Emp)"
Get-ADUser -LDAPFilter
Get-ADUser -LDAPFilter "(EmployeeNumber=$($u.Emp))"
I've got a function which works fine.
It pulls the first character of the firstname and the whole lastname from a text box in a PowerShell GUI and then it creates a sAMAccountName from both.
Now I need only the first 8 characters from the generated sAMAccountName.
Here is the function
Function Set-sAMAccountName {
Param([Switch]$Csv=$false)
if(!$Csv)
{
$GivenName = $txtFirstName.text
$Surname = $txtLastName.text
}
else{}
Switch($XML.Options.Settings.sAMAccountName.Style | Where{$_.Enabled -eq $True} | Select -ExpandProperty Format)
{
"FirstName.LastName" {"{0}.{1}" -f $GivenName,$Surname}
"FirstInitialLastName" {"{0}{1}" -f ($GivenName)[0],$Surname}
"LastNameFirstInitial" {"{0}{1}" -f $Surname,($GivenName)[0]}
Default {"{0}.{1}" -f ($GivenName)[0],$Surname}
}
}
Any ideas?
Thx a lot in advance
Substring works like that:
you pass the index of where you want to start
you pass the index of where you want to end the reading of the substring (if your not passing anything it will go until the end of the string's length)
so in your case it will be start reading at index 0 end reading at index 8:
$str = "a simple string"
$newString = $str.Substring(0,8)
I really recommend to read about string manipulation here
Okay I got it now!
I've added the -and condition to check the length of the sAMAccountName and said -lt 8 and it's working now. The sAMAccountName is now 8 characters long.
This was the code before:
$txtName_TextChanged={
Write-Verbose "Creating required account fields"
if ($XML.Options.Settings.DisplayName.Generate -eq $True) {$txtDN.Text = Set-DisplayName}
if ($XML.Options.Settings.sAMAccountName.Generate -eq $True) {$txtsAM.Text = (Set-sAMAccountName)}
if ($XML.Options.Settings.UPN.Generate -eq $True) {$txtUPN.Text = Set-UPN}
}
And after the change:
$txtName_TextChanged={
Write-Verbose "Creating required account fields"
if ($XML.Options.Settings.DisplayName.Generate -eq $True) {$txtDN.Text = Set-DisplayName}
if ($XML.Options.Settings.sAMAccountName.Generate -eq $True -and $txtsAM.Text.Length -lt 8) {$txtsAM.Text = (Set-sAMAccountName)}
if ($XML.Options.Settings.UPN.Generate -eq $True) {$txtUPN.Text = Set-UPN}
}