How to handle multiple objects in variable - powershell

I am trying to compare members is a list with the following script:
$Guid = "59041b96-c71d-436c-8297-7af5fcf4e22a"
$Members = Get-RetentionCompliancePolicy -identity $guid -DistributionDetail | Select -ExpandProperty OneDriveLocation | select name,displayname | sort displayname
$User = "Humbert, Jason"
$ODPolicy = $members.displayname | Select-String -Pattern "Humbert, Jason"
if($User -like $ODPolicy){
Write-host "USer $($USer.primarysmtpaddress) is in"
#$OD.RetentionSet = $True
}Else{
Write-Warning "User $($USer.primarysmtpaddress) not in Policy"}
The output for $ODPolicy returns 2 names because there are two mailboxes (Active, and inactive)
PS C:\Users\XYZ> $ODPolicy
Humbert, Jason
Humbert, Jason
When running the if($User -like $ODPolicy) the script doesn't seem to be able to handle that there are two objects that are returned and it returns the Else{ Write-Warning "User $($USer.primarysmtpaddress) not in Policy"}
How can I modify this so that the if($User -like $ODPolicy) sees it as true and returns the Write-host "USer $($USer.primarysmtpaddress) is in"?

The -like operator is not useful here because you want an exact match and you want to verify if a collection of items $members contains a specific single item $User.
So you should switch to the -contains operator, e.g.:
if ($members.displayname -contains "Humbert, Jason"){}

Related

Variable not passing to Where-Object in 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

I am trying to add members to a AD group based on a value in the "title" attribute [duplicate]

This question already has answers here:
I am trying to add members to a AD group based on a value in the "title" attribute
(3 answers)
Closed 2 months ago.
I am trying to add members to a AD group based on a value in the "title" attribute. I have about 30 different titles I want to use. Is there a way to write the command without 30 "OR" statements?
Thanks
Get-ADuser -filter {(title -eq "SECSCH") -or (title -eq "SEC12") -or (title -eq
"LTOSEC") -or (title -eq "LTO12")} | %{Add-ADGroupMember "SDK test print color"
$_.SamAccountName}
Also, for another group I would like All "custod" in title except if their "location" attribute is "85c" or location "42c" Below is where i am at.
Get-ADuser -filter {(title -eq "custod") -and (locationNumber -ne "85c") -or (title -eq
"custod") -and (locationNumber -ne "42c")} | %{Add-ADGroupMember "SDK test print
convert" $_.SamAccountName}
You can use the -in to specify list of values to compare with the title attribute
Here's an example :
$titles = "SECSCH", "SEC12", "LTOSEC", "LTO12"
Get-ADUser -Filter {title -in $titles} | ForEach-Object {
Add-ADGroupMember "SDK test print color" $_.SamAccountName
}
on the same strategy, you can exclude locations with operator -notin
$excludedLocations = "85c", "42c"
Get-ADUser -Filter {title -eq "custod" -and locationNumber -notin $excludedLocations} | ForEach-Object {
Add-ADGroupMember "SDK test print convert" $_.SamAccountName
}
I use a procedural method to build this kind of thing into an LDAPfilter, which is easier to construct than a load of -or statements, I feel.
$titles = #'
SECSCH
LTOSEC
???12
'# -split '\r?\n'
# begin filter
## (&(samAccountType=805306368) is not really needed for Get-Aduser
$filter = "(&(samAccountType=805306368)(|"
# append each title
$titles | Foreach { $filter += "(title=$_)"}
# end filter
$filter += "))"
# filter = (&(samAccountType=805306368)(|(title=SECSCH)(title=SEC12)(title=LTOSEC)(title=???12)))
Get-Aduser -ldapfilter $filter
Notice I slipped a wildcard in the list. For example, that one will catch all titles exactly 5 chars long ending with "12". There may be shortcuts like that you can use in your environment.
If you use a wildcard query, but want to exclude some possible results, you can always add NOT clauses (make sure they're inside an AND clause, not inside the OR clause!):
(&(samAccountType=805306368)(!title=SOP12)(|...
Also remember -searchbase to start from specific OUs if that might help you use wildcards or just better target sets of users with less noise/filtering required.

How come my condition determining if a user is in a group always returns as false?

I'm writing a script that requires detecting if the executing user account is a domain admin. I do this by getting the current user and checking if they are in the Domain Admins security group.
#Get current user
$CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name | Out-String
$CurrentUser = $CurrentUser -replace 'DOMAIN\\'
#Get list of Domain Admins members
$DomainAdmins = Get-ADGroupMember -Identity "Domain Admins" -Recursive | Select -ExpandProperty SamAccountName | Out-String
#Relevant condition
If ($DomainAdmins -like ($CurrentUser)) {
Write-Output "You're a domain admin." #example
}
Else {
Write-Output "You're not a domain admin."
}
Without fail, this script always runs the Else code when run from our domain controller using a domain administrator account.
I have also tried using -contains and .contains() with the exact same results. I've verified that the $CurrentUser value represents the current user accurately and that $DomainAdmins lists out the expected list of users.
I can also do this:
if ($DomainAdmins -contains ("USERNAME")) {Write-host "true"}
Where USERNAME is the current user typed out directly (case-correct or not) and it correctly returns true when that user is a member of the group.
Try with this:
$userSID = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value
$DomainAdmins = Get-ADGroupMember -Identity "Domain Admins" -Recursive
if($DomainAdmins.SID.Contains($userSID))
{
Write-Output "You're a domain admin."
}
...
# OR
if($userSID -in $DomainAdmins.SID)
{
Write-Output "You're a domain admin."
}
...
# OR
if($DomainAdmins.SID -contains $userSID)
{
Write-Output "You're a domain admin."
}
The Out-String on Get-ADGroupMember is converting your array into a string which is why you can't use it as comparison:
PS /> #(
'one'
'two'
'three'
) -contains 'one'
True
PS /> (#(
'one'
'two'
'three'
) | Out-String) -contains 'one'
False
An alternative, instead of using Get-ADGroupMember:
$userSID = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value
$domainAdminsDN = (Get-ADGroup -Identity "Domain Admins").DistinguishedName
$recursiveMembers = Get-ADUser -LDAPFilter "(memberOf:1.2.840.113556.1.4.1941:=$domainAdminsDN)"
if($recursiveMembers.SID.Contains($userSID))
{
Write-Output "You're a domain admin."
}
...
...
My preferred way to do this is by checking the MemberOf property of the user. It works a little better to keep them as AD objects when you have multiple domains or other oddities:
# check if DA
$DAdn = (Get-ADGroup 'Domain Admins').distinguishedname
If ( Get-ADUser -LDAPFilter "(&(SamAccountName=$Env:USERNAME)(MemberOf:1.2.840.113556.1.4.1941:=$DAdn))" ) {
Write-Output "You're a domain admin." #example
}
Your $DomainAdmins variable is a single string with the members instead of a list object. Using ... | Select -ExpandProperty SamAccountName is enough to get your list without Out-String.
-contains Looks for exact matches in collections, not for substrings.
You have to either remove Out-String from $DomainAdmins, to make it a list and make sure that the name matches entirely, or use .Contains(...) to look for a substring inside the $DomainAdmins string

Searching for User in Powershell. Allow Choice for Duplicate User

I wrote a PowerShell script that searches for a user based on given input and then removes said user from all groups (except for Domain Users). However, while you can't have a user with the same name in an OU group, you can have a user with the same name in a different OU group in the organization. Would it be possible to search for a user (John Smith), and allow one to select which user to remove from all groups if a duplicate user is returned? Here is my script so far. It works, but this is the functionality I would like to add.
#Requires -Module ActiveDirectory
Import-Module ActiveDirectory
function Disable-ADUser{
$msg = "Do you want to remove a user from all Security groups? [Y/N]"
do {
$response = Read-Host -Prompt $msg
if ($response -eq "y") { # Beginning of if statment
#Asks user via a text prompt to ender the firstname and lastname of the end user to remove
$firstName = Read-Host "Please provide the First name of the User"
$lastName = Read-Host "Please provide the Last name of the User"
#The user's samaccoutname is found by searching exactly for the user's first name and lastname given in the above prompts
$samName = Get-ADUser -Filter "GivenName -eq '$firstName' -and Surname -eq '$lastName'"| Select-Object -ExpandProperty "SamAccountName"
#All of the user's groups are queried based on their sam name
$listGroups = Get-ADUser -Identity $samName -Properties MemberOf | Select-Object -ExpandProperty MemberOf
#All of the user's groups are placed in an array
[System.Collections.ArrayList]$groupsArray = #($listGroups)
#Every group in the groupsArray is cycled through
foreach ($group in $groupsArray) {
#A text output is displayed before the user is removed from each group listed in the above array
#Once all groups have been cycled through, the for loop stops looping
Write-Host "Removing $samName " -f green -NoNewline
Write-Host "from $group" -f red
$OutputLine="Removing $samName from $group"
Out-File -FilePath remove_user_groups.log -InputObject $OutputLine -Append
Remove-ADGroupMember -Identity $group -Members $samName
}
} # End of if statement
} until ($response -eq "n")
}
Disable-ADUser
I use Out-GridView. It allows me to select user(s) with mouse, or to select no one. See -OutputMode parameter.
<# Example part #>
$data = #'
[
{displayName: "Don Pedro Fizikello", employeeNumber: "Emp001", phone: "+888888888" },
{displayName: "Don Pedro Gonzalez", employeeNumber: "Emp002", phone: "+77777777777" },
{displayName: "Natalia Marisa Oreiro", employeeNumber: "Emp456", phone: "+987654321" },
{displayName: "Juan Carlos Rodrigez", employeeNumber: "Emp123", phone: "+1234567890"}
]
'# | ConvertFrom-Json
$userList = #($data | Where-Object { $_.displayName -like 'Don*' })
#Real-world case from Active Directory: $userList = #( Get-ADUser -Filter "(displayName -like 'Don*')" -Properties #('displayName', 'phone') )
<# /Example part #>
$user = $null
if ($userList.Count -eq 1) {
$user = $userList[0] # // The only entry
} elseif ($userList.Count -gt 1) {
$user = $userList | Out-GridView -OutputMode Single -Title 'Select User you want co tall to or press cancel'
}
if ($null -eq $user) {
# // There is no users found or selected by human
Write-Host "Nothing to do" -f Yellow
} else {
# // Work with User
Write-Host "Call $($user.displayName) : $($user.phone)" -f Green
}
The negative option is that Out-GridView can not hide parameters that it will display. There are some workarounds depending on task. Example: I show only DisplayName and some ID in Out-GridView (no phone property), but I use returned ID to take full user (with phone) from cache I've created before.
This allows me not to break the original object ( if it's from Get-ADUser, it contains tons of human-useless data like SID, GUID, ObjectClass, ObjectCategory, etc. )
<# Example part #>
Same as previous
<# /Example part #>
$user = $null
$userCacheOriginal = #{}
$userCacheCut = #{}
for ($i = 0; $i -lt $userList.Count; $i++)
{
# !! Here I assign some entryUniqueId to two collections -
# - userCacheOriginal - Original user object with Phone field ( and others )
# - userCacheCut - Transformed objects that contains only ID and info I want to show in Out-GridView
$entryUniqueId = "Idx$($i)"
$userCacheOriginal[$entryUniqueId] = $userList[$i]
$userCacheCut[$entryUniqueId] = [PSCustomObject]#{ID = $entryUniqueId; displayName = $userList[$i].DisplayName;}
}
if ($userList.Count -eq 1) {
$user = $userList[0] # // The only entry
} elseif ($userList.Count -gt 1) {
$userChoice = $userCacheCut.Values | <# Set order of columns this way#> Select #('ID', 'DisplayName') | Out-GridView -OutputMode Single -Title 'Select User or press cancel'
if (($null -ne $userChoice.ID) -and ($userCacheOriginal.ContainsKey($userChoice.ID))) # Check if returned value contains ID,
{ # And select original user object from userCacheOriginal
$user = $userCacheOriginal[$userChoice.ID]
}
}
if ($null -eq $user) {
# // There is no users found or selected by human
Write-Host "Nothing to do" -f Yellow
} else {
# // Work with User
Write-Host "Call $($user.displayName) : $($user.phone)" -f Green
}
If you want to keep it console based, you can add a while loop that requires further input from the user.
#The user's samaccoutname is found by searching exactly for the user's first name and lastname given in the above prompts
$samName = Get-ADUser -Filter "GivenName -eq '$firstName' -and Surname -eq '$lastName'"|
Select-Object -ExpandProperty "SamAccountName"
if ($samname.count -gt 1) {
$newsamname = $null
while ($newsamname -notin $samname) {
$newsamname = Read-Host "Multiple names were found:`n$($samname -join ""`n"")`nPlease type the SamAccountName of the target user"
}
$samname = $newsamname
}
The idea is if multiple user objects are found, then $samname will initially be a collection of count greater than one. Here the executor will be required to enter a valid SamAccountName value from the presented list. Otherwise, the loop will go on forever until the program is manually halted. You could build in a counter to automatically exit the program after a certain number of retries or exit when no value is entered. You could implement a menu system where a number can be entered, which corresponds to the index of the list.

Determining if a given user is in a given global group

I’m trying to search through Active Directory using the AD module in PowerShell. I’m trying to determine whether a given user is in a given global group. The issue is that I’m using -match meaning if there is a username that contains another within it, such as 'smith_pl' containing 'smith_p'. The user 'smith_p' will be shown to be in the group.
So my question is: Is there a better way of getting a $True or $False return depending if a user is in a giving global group using the AD module?
If not
Is there a way of getting the output from $ListOfmembers into an array so I can use -eq instead of -match?
Part of Script:
$ListOfmembers = dsquery group domainroot -name $globalgroup |
dsget group -members |
dsget user -samid -L
$checkMember = $False
#Search if the user is in output the list
If($ListOfmembers -match $Logonname){
$checkMember = $True
}
ListOfmembers Output:
samid: user05_t
samid: user23_s
samid: Admin
samid: user45_s
dsget succeeded
Any help would be appreciated, Cheers.
$member = Get-ADGroupMember group1 -Recursive | where {$_.samaccountname -eq 'user1'}
if($member) {'user 1 is a member of group1'}
You can do it like this:
[reflection.assembly]::LoadWithPartialName("System.DirectoryServices.AccountManagement")
$username = "samaccountname"
$ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
$user = [System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($ct, $username)
$g = $user.GetGroups()
( $g | select -expa name ) -contains 'groupname'
You should checkout QAD: http://www.quest.com/powershell/activeroles-server.aspx
$user get-qaduser samAccountName
$user.memberof