Variable not passing to Where-Object in Powershell - powershell

I have tried the "filter" and "param" options from the post
-- In powershell passing variable to where-object not working -- with no luck. I am fairly new to powershell since I have not used it since 2014. Can anyone assist me in finding out why the $UName variable is not being passed to the Where-Object command?
cls
$UName = Read-Host -Prompt "Name or part of name to search"
Write-Output "Searching for: $UName, please wait"
Get-ADUser -Filter * -Properties * | Where-Object {
$_.name -like "*$UName*" -and
$_.company -like "*XYZ Corp*"
} | select Name, title, company, Country, mailnickname
Pause
My only output is:
Name or part of name to search: Justin
Searching for: Justin, please wait
Press Enter to continue...
I have even tried using -Contains $UName and -Contains "$UName" yet still get the same results as above.
I have searched, and searched but cannot figure this out. Any assistance would really help!

Your script can be simplified as follows, you really shouldn't query all Domain Users (-Filter *) to then filter them with PowerShell (Where-Object). Instead, you should use the Active Directory Filter. Same goes for querying all users properties (-Properties *) when you actually only need some of them (Name, title, company, Country, mailnickname).
# using Trim() to remove any excess whitespace (trailing and leading)
$UName = (Read-Host -Prompt "Name or part of name to search").Trim()
# if there was no input or input was purely whitespace
if(-not $UName) {
# exit this script
return
}
# if input was valid
Write-Output "Searching for: $UName, please wait"
# try to search for the user
$props = 'Name', 'title', 'company', 'Country', 'mailnickname'
Get-ADUser -LDAPFilter "(&(name=*$UName*)(company=*XYZ Corp*))" -Properties $props |
Select-Object $props | Format-Table -AutoSize

Related

Working with a list of AD 'displayNames' in Powershell. How to indicate which users were not found?

I have written enough PS code to go through a list of displayNames (e.g "John Smith", "Taylor Hanson" - all stored on seperate lines of a txt file) to spit back enough data into another text file that can be used for mailmerge etc. Convincing thousands of employees to simply update Windows is like breaking stones! It has to be automatted to some degree...
Here is the code... the functions that let the user open a specific text file and later save are out of view...
$displayname = #()
$names = get-content $FileIN
foreach ($name in $names) {
$displaynamedetails = Get-ADUser -filter { DisplayName -eq $name } | Select Name, GivenName, Surname, UserPrincipalName
$displayname += $displaynamedetails
}
$displayname | Export-Csv -NoTypeInformation -path $fileOUT -Encoding UTF8
From time to time, a name might be spelled incorrectly in the list, or the employee may have left the organisation.
Is there any way that a statement such as 'Not Found' can be written to the specific line of the text file if an error is ever made (so that an easy side-by-side comparison of the two files can be made?
For most of the other solutions I've tried to find, the answers are based around the samAccoutName or merging the first and last names together. Here, i am specifically interested in displaynames.
Thanks
You can give this a try, since -Filter or -LDAPFilter don't throw any exception whenever an object couldn't be found (unless you're feeding a null value) you can add an if condition to check if the variable where the AD User object is going to be stored is not null and if it is you can add this "not found" user into a different array.
$domain = (Get-ADRootDSE).DefaultNamingContext
$names = Get-Content $FileIN
$refNotFound = [System.Collections.Generic.List[string]]::new()
$displaynamedetails = foreach($name in $names)
{
if($aduser = Get-ADUser -LDAPFilter "(DisplayName=$name)")
{
$aduser
continue
}
$refNotFound.Add(
"Cannot find an object with DisplayName: '$name' under: $domain"
)
}
$displaynamedetails | Select-Object Name, GivenName, Surname, UserPrincipalName |
Export-Csv -NoTypeInformation -path $fileOUT -Encoding UTF8
$refNotFound # => Here are the users that couldn't be found
Side note, consider stop using $displayname = #() and += for well known reasons.
As for AD Cmdlets, using scriptblock based filtering (-Filter {...}) is not supported and even though it can work, it can also bring you problems in the future.

How to handle hyphenated names in powershell when getting active directory info

I'm trying to get the password expiration date in active directory using powershell for users with hyphenated names (IE firstname.last-name) and on the hyphenated names it gives an invalid cmdlet error. How do I query the hyphenated names?
The current command I have is
net user $username /DOMAIN | find "Password expires"
Maybe use the ActiveDirectory module instead of the net commands:
$MaxPwdAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.Days
Get-ADUser -Filter { Name -like "*-*" } -Properties 'PasswordLastSet', 'DisplayName' |
Select-Object Name,DisplayName,
#{ Name = 'PasswordExpires'; Expression = { $_.PasswordLastSet.AddDays( $MaxPwdAge ) } }
If needed You can change the filter to look at DisplayName instead -Filter { DisplayName -like "*-*" }
You may need to adjust the properties you're retrieving depending on what you want to include in the output. This is just an example but it works, and can be used to plot a path forward. It does seem like you have to calculate the expiration date. But I can work on that and see if there's a better way.
If you want to Query for a specific user:
Get-ADUser Name-Name -Properties 'PasswordLastSet',DisplayName |
Select-Object Name,DisplayName,
#{ Name = 'PasswordExpires'; Expression = { $_.PasswordLastSet.AddDays( $MaxPwdAge ) } }
This assumes the Hyphenated name is a samAccountName. If you need to search by DisplayName you'll have to resort back to filter, even if you are looking for only the one user.
Get-ADUser -Filter { DisplayName -eq "Name-Name" } -Properties 'PasswordLastSet',DisplayName |
Select-Object Name,DisplayName,
#{ Name = 'PasswordExpires'; Expression = { $_.PasswordLastSet.AddDays( $MaxPwdAge ) } }
Note: That you have to change the "Name-Name". Also in the last example I changed to using the -eq operator instead of -like. Obviously this assumes you know exactly what you're looking for. Though you can use -Like with DisplayName or even the surName attribute if you like.

Adding a ROW for missing Attribute values to Export-CSV

I using the following POWER SHELL script, to extract ( to csv ) managers name , from a "Manager" user attribute.
#This script, , Exports the Manager name of the employee`s in the TXT file.
# users.txt file - contains a simply list of user names ( samaccount-names )
Get-Content D:\powershell\permmisions\Users.txt | Foreach-Object {
Get-ADUser -Identity $_ -Properties Manager | Select-Object name, Manager | Export-Csv D:\Powershell\ADuserinformation\Export-Managers-of-specific-users.csv
-Append
}
The challenge i am facing, is when is on the exported CSV file,
the list "SKIPS" blank value-fields,In case there is no manager set for the user.
And a ROWS is not created , where MANAGER is missing.
What i would like to do , is the script to enter a charcter ( ~ ) for example, where, value is blank.
That way , a row will be created for the blank MANAGER value, on the CSV file
Please help ,
Thanks all in advance.
Note: At least the Name property should exist on all AD users retrieved, so you would get a row even for users where Manager is empty, but with an empty Manager column. If you do need to deal with possibly not all users named in Users.txt actually existing, see Theo's helpful answer.
The simplest approach is to use a calculated property:
Get-ADUser -Identity $_ -Properties Manager |
Select-Object Name, #{ Name='Manager';
Expression={ if ($_.Manager) { $_.Manager } else { '~' } } }
Note:
It is common to abbreviate the key names of the hashtable that defines the calculated property to n and e.
The if statement takes advantage of the fact that an empty string (or $null) evaluates to $false in a Boolean context; for an overview of PowerShell's implicit to-Boolean conversion, see the bottom section of this answer.
In PowerShell [Core] 7.0 or above, you could additionally take advantage of the ternary operator (<condition> ? <valueIfTrue> : <valueIfFalse>) to further shorten the command:
# PSv7+
Get-ADUser -Identity $_ -Properties Manager |
Select-Object Name, #{ n='Manager'; e={ $_.Manager ? $_.Manager : '~' } }
Note: If $_.Manager were to return $null rather than the empty string ('') if no manager is assigned, you could use ??, the PSv7+ null-coalescing operator instead: $_.Manager ?? '~'
Not concise at all, but this allows you to insert more properties of interest in your report, and does some error-checking if the user listed in your input file does not exist:
$report = foreach ($account in (Get-Content D:\powershell\permmisions\Users.txt)) {
$user = Get-ADUser -Filter "SamAccountName -eq '$account'" -Properties Manager -ErrorAction SilentlyContinue
if ($user) {
if (!$user.Manager) { $mgr = '~' }
else {
# the Manager property is the DistinghuishedName for the manager.
# if you want that in your report, just do
$mgr = $user.Manager
# if you want the Name for instance of that manager in your report,
# comment out the above line and do this instead:
# $mgr = (Get-ADUser -Identity $user.Manager).Name
}
# now output an object
[PsCustomObject]#{
UserName = $user.Name
Manager = $mgr
}
}
else {
Write-Warning "User '$account' does not exist"
}
}
# output on screen
$report | Format-Table -AutoSize
# output to CSV file
$report | Export-Csv -Path 'D:\Powershell\ADuserinformation\Export-Managers-of-specific-users.csv' -NoTypeInformation

Unable to pass formatted Get-ADOrganizationlUnit output into function in script

I'm unable to pass the results of Get-ADOrganizationalUnit into a function in a script.
I am storing the results in a variable that is being used to add the canonical name of the OUs returned by the cmdlet, to a dropdown list on a form.
I'm then attempting to use the same variable in a function that when called, will determine the distinguished of the OU based on the canonical name selected.
Since the variable is being set when the form loads so that the drop down in question will be populated with the various OUs, I added in a write-output $myVar just to make sure nothing strange was going on prior to being passed into the function. I've attempted to make $myVar global with $Global:varName and I've attempted to pass in the variable when calling the function: myFunction $myVar $myVar1. If I then use write-output $myVar within the function, there is no output, but I can use write-host $myVar and it will return a string of just the distinguishedNames of all the OUs in $myVar.
I tested this in the shell directly as well and I didn't have any issues with associating the canonical name back to the DN of the OU, but don't know what I'm doing incorrectly to cause it to not work when used in a script.
I'm using this to get the OU data for the dropdown list and function:
$userOUs = Get-ADOrganizationalUnit -SearchBase $ouRoot -Filter * -Properties CanonicalName | Where-Object {$_.Name -like '*user*'}
Note: The dropdown list is populated successfully using $userOUs.
I call the function with a button:
$myBtn.Add_Click({ myFunction $userID $userOUs})
The function I'm trying to pass it to:
function myFunction($userID, $userOUs) {
Write-Output $userOUs #returns nothing
Write-Host $userOUs #returns the string containing all of the OUs' distinguished names
$selectedOU = $OUList.SelectedItem
$targetOUCanonicalName = "$domainPrefix$selectedOU" #I remove the domain name from the canonical name for display in the dropdown but add it back here
$targetOu = $userOUs | Where-Object {$_.CanonicalName -eq $targetCanonicalName} | select -ExpandProperty distinguishedName
Get-ADUser -Identity $userID | Move-ADObject -TargetPath $targetOU
}
Ultimately, the goal is to be able to use the $userOus variable to determine the DN of the OU based on the selection made in a drop down of OU canonical names. I'd like to try and keep this more dynamic without having to define everything in a switch statement.
I expect once I get a bump in the right direction regarding why the variable is not passing into the function the way that I need it to, I'll be able to accomplish that.
Edit: I don't intend to use write-host or write-output since the script will have a form, I'm just using that to try and figure out what's going on.
I've tried your version and it seems to work just fine:
function myFunction($userID, $userOUs) {
Write-Output $userOUs #returns nothing
Write-Host $userOUs #returns the string containing all of the OUs' distinguished names
#$selectedOU = $OUList.SelectedItem
#$targetOUCanonicalName = "$domainPrefix$selectedOU" #I remove the domain name from the canonical name for display in the dropdown but add it back here
#$targetOu = $userOUs | Where-Object {$_.CanonicalName -eq $targetCanonicalName} | select -ExpandProperty distinguishedName
# Get-ADUser -Identity $userID | Move-ADObject -TargetPath $targetOU
}
$userOUs = Get-ADOrganizationalUnit -Filter * -Properties CanonicalName | Where-Object {$_.Name -like '*user*' }
$userOUs
myFunction -userID $UserID -userOUs $userOUs
$UserOus display data for me, when I execute your function as above I also get output. The only thing that comes to mind is that the issue is somewhere else.

Powershell Script to query Active Directory

I am trying to query all users in multiple OUs of the same name. Get the SamAccountName attribute and then check for a file at a specific location with that name.
Here is what I have so far:
$ous = Get-ADOrganizationalUnit -Filter "Name -eq 'Admin-User-Accounts'"
$ous | ForEach-Object {
$AccountName = Get-ADUser -Filter * -SearchBase $_.DistinguishedName |
Select SamAccountName
Test-Path "\\domain.net\SYSVOL\domain.net\IA\$AccountName.pdf"
}
If a file is not found. I want to add the user to a group, however here is the kicker. The account has to be added to the non-compliance group for the organization that the account belongs to.
I.E an admin account found under:
OU=Admin-User-Accounts,OU=Administration,OU=ORG1,OU=ORGS,DC=domain,DC=net
would be added to the group named 'ORG1 IA - Non-Compliant Users' located under:
OU=Groups,OU=ORG1,OU=Information Assurance,OU=ORGS,DC=domain,DC=net
Well your post is a bit confusing, and no way to really validate because I have nothing setup like this.
Yet, querying for users in all OU or the enterprise is a common everyday thing.
However, an OU name, just like any other AD object name, must be unique. So, querying for the same OU name is not a thing, in a single AD forest / domain. If you meant querying every OU for the same username, then alrighty then.
By stepping thru how you are explanation for your use case, that you have laid out.
(though maybe you want to edit your post to make it's more clear, well to me anyway...)
Using pseudo code, then trying to map that out... and with no real way to determine what you mean by several things in your post/sample. So, the below is a rough first example of how I'd do approach this... again this is untested, so, I leave that homework to you.
# query all users in multiple OUs
(Get-ADOrganizationalUnit -Filter *).DistinguishedName |
ForEach{
# Collect all members of the current OU
$AccountNames = Get-ADUser -SearchBase $PSItem -Filter *
# Process each member in the current OU collection
ForEach($AccountName in $AccountNames)
{
"Processing $($AccountName.SamAccoutnName)`n"
# Initialize properties needed for processing
$UserOrg = $AccountName.DistinguishedName.split(",")[1]
$MemberCheckOU = "OU=Admin-User-Accounts,OU=Administration,OU=ORG1,OU=$UserOrg,DC=domain,DC=net"
$NonCompliantOU = "OU=Groups,OU=ORG1,OU=Information Assurance,OU=$UserOrg,DC=domain,DC=net"
# Validate user file existence for the current user
If(-Not (Test-Path -LiteralPath "\\domain.net\SYSVOL\domain.net\IA\$($AccountName.SamAccoutnName).pdf)"))
{
# if no file Process the user groupmebership modification
"Processing $($AccountName.SamAccoutnName)"
# Notify that the file was not found and processing is required
Write-Warning -Message "$($($AccountName.SamAccoutnName).pdf) not found. Process group modify actions"
# If the current user is in the MemberCheckOU, add to the NonCompliantOU
If(Get-ADPrincipalGroupMembership -Identity $($AccountName.SamAccoutnName) | Where-Object -Property DistinguishedName -Match $MemberCheckOU )
{ Add-ADGroupMember -Identity $NonCompliantOU -Members $($AccountName.SamAccoutnName) }
Else
{
# Do something else
}
}
Else
{
# Notify that the file was found and no processing required
Write-Host "$($AccountName.pdf) found. No further actions taken" -ForegroundColor Green }
}
}
It seems that one of the variables is incorrect because PowerShell is giving me the following:
Get-ADPrincipalGroupMembership : Cannot validate argument on parameter 'Identity'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command
again.
Okay, so here is what I have so far based on your post above Postanote:
# query all users in multiple OUs
(Get-ADOrganizationalUnit -Filter "Name -eq 'Admin-User-Accounts'") |
ForEach{
# Collect all members of the current OU
$AccountNames = Get-ADUser -SearchBase $PSItem -Filter *
# Process each member in the current OU collection
ForEach($AccountName in $AccountNames)
{
"Processing $($AccountName.SamAccoutnName)`n"
# Initialize properties needed for processing
$UserOrg = $AccountName.DistinguishedName.split(",")[1]
$MemberCheckOU = "OU=Admin-User-Accounts,OU=Administration,OU=$UserOrg,OU=ORGS,DC=domain,DC=net"
$NonCompliantOU = "OU=Groups,OU=$UserOrg,OU=Information Assurance,OU=ORGS,DC=domain,DC=net"
# Validate user file existence for the current user
If(-Not (Test-Path -LiteralPath "\\domain.net\SYSVOL\domain.net\IA\$($AccountName.SamAccoutnName).pdf)"))
{
# if no file Process the user groupmebership modification
"Processing $($AccountName.SamAccoutnName)"
# Notify that the file was not found and processing is required
Write-Warning -Message "$($($AccountName.SamAccoutnName).pdf) not found. Process group modify actions"
# If the current user is in the MemberCheckOU, add to the NonCompliantOU
If(Get-ADPrincipalGroupMembership -Identity $($AccountName.SamAccoutnName) | Where-Object -Property DistinguishedName -Match $MemberCheckOU )
{ Add-ADGroupMember -Identity "$UserOrg IA - Non-Compliant Users" -Members $($AccountName.SamAccoutnName) }
Else
{
# Do something else
}
}
Else
{
# Notify that the file was found and no processing required
Write-Host "$($AccountName.pdf) found. No further actions taken" -ForegroundColor Green }
}
}
Looking at the original script fragment:
$ous = Get-ADOrganizationalUnit -Filter "Name -eq 'Admin-User-Accounts'"
$ous | ForEach-Object {
$AccountName = Get-ADUser -Filter * -SearchBase $_.DistinguishedName |
Select SamAccountName # note 1
Test-Path "\\domain.net\SYSVOL\domain.net\IA\$AccountName.pdf" # note 2
}
Note 1: Your going to end up with $accountname.accountname holding your value. I think your going to want to expand this instead.
Note2: Powershell may be getting confused and thinking your looking for the variable $accountname.pdf
Instead, try this...
$ous = Get-ADOrganizationalUnit -Filter "Name -eq 'Admin-User-Accounts'"
$ous | ForEach-Object {
$AccountName = $(Get-ADUser -Filter * -SearchBase $_.DistinguishedName).SamAccountName
Test-Path "\\domain.net\SYSVOL\domain.net\IA\$($AccountName).pdf"
}
here, we save the value of just .SamAccountName for the query to the $AccountName, and by adding $($accountname) we make clear the variable we want, and that .pdf is not part of the variable name.
Now, note as well, this doesn't save the results anywhere, it will just flash them to screen.