Powershell - AD Report create a new column with a generic value - powershell

I use this script to query my AD and extract user data.
Get-Aduser -filter * -Properties *| Select-Object -Property SamAccountName,CN,co,ExtensionAttribute10,extensionAttribute11,extensionAttribute12,EmailAddress,whenCreated,Enabled,LastLogonDate,accountexpirationdate, #{Name='parentOU'; Expression={[regex]::match($_.distinguishedname,'(?<=OU=.+?OU=).+?(?=,(OU|DC)=)').Value}},distinguishedname,description | Sort-Object -Property Name <#| Where-Object {$_.distinguishedname -like "*regular*"-or $_.distinguishedname -like "*remote*" -or $_.distinguishedname -like "*shopfloor*" -or $_.distinguishedname -like "*brp admin*" }#> | Export-Csv -append -Delimiter ";" -path $path
I would like to take the result of the "enable" column, which is True or False, and create a new column call "suspended" if the result of enable is true the value to put in "suspended" is no. If the result is false, the value to put in "suspended should be "yes"
Can someone help me with this ?

Just create a new calculated property that is based on the value of the Enabled property.
... | Select-Object ... ,Enabled,#{n='Suspended';e={if($_.Enabled){'no'}else{'yes'}}},...

Related

Get All AD Groups That Have Blank Managed By Field

I'm trying to get all AD groups that have a blank Managed By Name and the description of the AD group. I'm currently having issues with displaying no results using my filter, but am not sure why. Any help is appreciated.
Get-ADGroup -filter * | Where-Object {$_.ManagedBy -eq ""} | Select-Object manager,description | Export-Csv -Path C:\Users\User\Desktop\AllNullManagedBy.csv -NoTypeInformation
The current script is not showing any users which it should be showing several users
The problem is that Get-ADGroup does not return an object with the ManagedBy attribute by default, you need to ask for it (-Properties ManagedBy):
Get-ADGroup -Filter * -Properties ManagedBy, Manager, Description |
Where-Object {-not $_.ManagedBy } | Select-Object samAccountName, Manager, Description |
Export-Csv -Path C:\Users\User\Desktop\AllNullManagedBy.csv -NoTypeInformation
However, this operation is quite inefficient, you can use LDAP filtering capabilities for this:
Get-ADGroup -LDAPFilter "(!managedby=*)" -Properties Manager, Description |
Select-Object samAccountName, Manager, Description |
Export-Csv -Path C:\Users\User\Desktop\AllNullManagedBy.csv -NoTypeInformation
As a side note, Where-Object { $_.ManagedBy -eq "" } is likely to not return any results, you would be querying for AD Groups where their ManagedBy attribute is set and it's value is equal to an emptry string instead of filtering for groups that don't have the attribute set or it's value is $null or empty string ({-not $_.ManagedBy }):
$null -eq '' # => False: comparison fails here
-not $null # => True
-not '' # => True

get deactivated computers in ad from csv list

i'm tryin to figure out which computers are deactivated. for that i provide the computer names in a csv list. i just want to output the computers which are deactivated. this is what i have. unfortunately i get all deactivated computers. but i only want that names provided in the csv
Import-CSV -Path "C:\pc_names" | Select -expand Name | Get-ADComputer -searchbase 'XXX' -Filter {(Enabled -eq $False)} -Properties Name, OperatingSystem | Export-CSV “C:\Temp\DisabledComps.CSV” -NoTypeInformation
The problem is likely in the Get-ADComputer command, you specify a SearchBase (assumedly an OU), and a filter for all disabled computers - but never actually include the name of the PC that you piped in from the CSV, so it just returns every disabled PC under that search base.
Try something like this instead;
Import-CSV -Path "C:\pc_names" | Select -Expand Name | Get-ADComputer -SearchBase 'XXX' -Filter {(Enabled -eq $False) -and ($_.Name)} -Properties Name, OperatingSystem | Export-CSV "C:\Temp\DisabledComps.CSV" -NoTypeInformation
Note the $_.Name in the filter.
I've probably got that filter syntax wrong - but that should be the cause.
There is no way you can test if the computername is to be found in an array of names using the -Filter parameter..
You need to first collect computer objects within your SearchBase OU and filter the disabled ones only.
Following that, you filter out the ones that can be found in the $pcNames array using a Where-Object clause:
$pcNames = (Import-Csv -Path "C:\pc_names.csv").Name
Get-ADComputer -SearchBase 'XXX' -Filter "Enabled -eq 'False'" -Properties OperatingSystem |
Where-Object { $pcNames -contains $_.Name } | # or: Where-Object { $_.Name -in $pcNames }
Export-Csv -Path "C:\Temp\DisabledComps.csv" -NoTypeInformation
Note: Get-ADComputer by default already returns these properties: DistinguishedName, DNSHostName, Enabled, Name, ObjectClass, ObjectGUID, SamAccountName, SID, UserPrincipalName. That means you only have to ask for the extra property OperatingSystem in this case
It's pretty obvious that something like this ignores what's piped in and returns many computers.
'comp001' | get-adcomputer -filter 'Enabled -eq $False'
If you wait until the end, there is an error message:
get-adcomputer : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its
properties do not match any of the parameters that take pipeline input.
At line:1 char:13
+ 'comp001' | get-adcomputer -filter 'Enabled -eq $false'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (comp001:String) [Get-ADComputer], ParameterBindingException
+ FullyQualifiedErrorId : InputObjectNotBound,Microsoft.ActiveDirectory.Management.Commands.GetADComputer
You can do get-adcomputer inside a foreach loop and test Name as well:
$list = echo comp001 comp002 comp003
$list | % { get-adcomputer -filter 'Enabled -eq $False -and Name -eq $_' }

Creating a calculated property with data from prior calculated property in PowerShell

Apologies if this is a "Well, duh!" moment but I'm trying to figure out how to reference a prior calculated property in a script and I'm at a loss after searching various forums. The following script runs perfectly in my environment until the last line. The $theusers system array is pulled from a .csv
Get-MsolDevice -All -ReturnRegisteredOwners |
Where-Object {($_.DeviceOSType -eq 'iPhone' -or $_.DeviceOSType -eq 'iPad') -and $_.RegisteredOwners.Count -gt 0 -and $_.DeviceTrustLevel -eq 'compliant'} |
Select #{L='User';E={Get-ADUser -filter "UserPrincipalName -eq '$($_.RegisteredOwners -join(';'))'" -server "server.com" | Select -expandproperty name}},
#{L='EmailAddress';E={$_.RegisteredOwners -join(';')}},
#{L='Position';E={Get-ADUser -properties description -filter "UserPrincipalName -eq '$($_.RegisteredOwners -join(';'))'" -server "server.com" | Select -expandproperty description}},
#{L='Office';E={Get-ADUser -properties l -filter "UserPrincipalName -eq '$($_.RegisteredOwners -join(';'))'" -server "server.com" | Select -expandproperty l}},
#{L='DeviceName';E={$_.DisplayName}},
#{L='DeviceType';E={$_.DeviceOSType}},
#{L='DeviceOS';E={$_.DeviceOSVersion}},
#{L='LoginName';E={Get-ADUser -properties description -filter "UserPrincipalName -eq '$($_.RegisteredOwners -join(';'))'" -server "server.com" | Select -expandproperty samaccountname}},
#{L='TrueOffice';E={$theusers | where-object {$_.SamName -like $_.LoginName } | Select -expandproperty office }}
Everything works except the last line.
User : Doe, John Q.
EmailAddress : JDoe#server.com
Position : DAL.Court Jester
Office : Dallas
DeviceName : John’s iPad
DeviceType : IPad
DeviceOS : 13.3.1
LoginName : JDoe
TrueOffice :
I'm trying to use the "LoginName" created from the line above but it does not seem to be passed on as a variable.
I tried replacing $_.LoginName with the actual expression . . .
Get-ADUser -properties description -filter "UserPrincipalName -eq '$($_.RegisteredOwners -join(';'))'" -server "server.com" | Select -expandproperty samaccountname
. . . which created LoginName but still got blanks for TrueOffice.
On the last line, if I replace $_.LoginName with an actual login name, such as "JDoe", the "TrueOffice" information for "JDoe" is provided from $theusers, so I know the language is correct but I just can't figure out out to get LoginName to be recognized as a variable.
When $_.LoginName is changed to "JDoe"
User : Doe, John Q.
EmailAddress : JDoe#server.com
Position : DAL.Court Jester
Office : Dallas
DeviceName : John’s iPad
DeviceType : IPad
DeviceOS : 13.3.1
LoginName : JDoe
TrueOffice : North Texas
Thanks in advance for any insight into this.
I would avoid using Select-Object in this case and just use a foreach-object from which you cal Get-ADUser once and then return a custom PS object manually. I think the result is more flexible, readable and efficient:
Get-MsolDevice -All -ReturnRegisteredOwners |
Where-Object {($_.DeviceOSType -eq 'iPhone' -or $_.DeviceOSType -eq 'iPad') -and $_.RegisteredOwners.Count -gt 0 -and $_.DeviceTrustLevel -eq 'compliant'} | foreach {
$adUser = Get-ADUser -filter "UserPrincipalName -eq '$($_.RegisteredOwners -join(';'))'" -server "server.com"
[PSCustomObject] #{
'User"'= $adUser.name;
'EmailAddress' = $_.RegisteredOwners -join ';';
'Position' = $adUser.description;
# other properties omitted . . .
'LoginName' = $adUser.samaccountname
'TrueOffice' = $theusers | where-object {$_.SamName -like $adUser.samaccountname } | Select -expandproperty office
}
}
When you use $_.LoginName you are trying to access an output property which doesn't exist on the input object, $_. A workaround would be to wrap your Select in a ForEach-Object, inside of which you calculate and store in a variable the value on which both properties are based...
Get-MsolDevice -All -ReturnRegisteredOwners |
Where-Object {($_.DeviceOSType -eq 'iPhone' -or $_.DeviceOSType -eq 'iPad') -and $_.RegisteredOwners.Count -gt 0 -and $_.DeviceTrustLevel -eq 'compliant'} |
ForEach-Object -Process {
$emailAddress = $_.RegisteredOwners -join(';')
$user = Get-ADUser -filter "UserPrincipalName -eq '$emailAddress'" `
-server "server.com" -Properties 'Name', 'Description', 'l', 'SamAccountName'
$loginName = $user | Select -expandproperty samaccountname
$_ | Select #{L='User';E={$user.Name}},
#{L='EmailAddress';E={$emailAddress}},
#{L='Position';E={$user.Description}},
#{L='Office';E={$user.l}},
#{L='DeviceName';E={$_.DisplayName}},
#{L='DeviceType';E={$_.DeviceOSType}},
#{L='DeviceOS';E={$_.DeviceOSVersion}},
#{L='LoginName';E={$loginName}},
#{L='TrueOffice';E={$theusers | where-object {$_.SamName -like $loginName } | Select -expandproperty office }}
}
A few notes about the above code:
Instead of calling Get-ADUser once for each output property based on a user attribute, I retrieve the user object once with the exact properties that are needed.
The email address and login name are calculated once and stored in local variables for reuse.
There's not really any downside other than an imperceptible performance hit, but if you pass a pattern that doesn't contain any wildcard characters to -like (as in $_.SamName -like $loginName) you might as well use -eq.
If you really wanted to filter on partial string matches you could use $_.SamName -like "*$loginName*" or the case-sensitive $_.SamName.Contains($loginName) (but not -contains!).
I simplified usages like $user | Select -expandproperty name to $user.Name.

Get-AdUsers from specific AD Groups and filtering results

I am able to export to users that are not members of particular groups such as IT_Group like below. But, this script gives me all membership of users within memberof column in csv output. If they are members of any groups that matches "IT" they should be displayed within memberof column in csv output like below.
Also , If user is not member to any group that is beginning with IT_ then it will write "any IT group is not member" keyword within memberof column in csv output.
There are 3 security groups such as IT_Group,IT_Group1,IT_Group2
I have tried so far :
Get-ADUser -Filter {(emailaddress -like "*#contoso.com" -and Enabled -eq $false -and sAMAccountName -like "TEST*") -or (emailaddress -like "*#contoso.com" -and Enabled -eq $false -and sAMAccountName -like "PROD*")} -SearchBase "OU=USERS,DC=contoso,DC=com" -SearchScope Subtree -Properties * | Where { [string]$_.memberof -notmatch 'IT_Group'} | Select-Object name , samaccountname ,#{Name="MemberOf";Expression={($_.MemberOf | %{(Get-ADGroup $_).sAMAccountName}) -Join ";"}} |Export-CSV -Path "C:\tmp\output.csv" -NoTypeInformation -Encoding UTF8
My Desired output :
name,samaccountname,memberof
User01,TEST1,IT_Test
User02,PROD1,IT_Prod
User03,TEST4,any IT group is not member
The -Filter should not be written as script block ({..}), but as a normal string.
This should do what you are after:
$filter = "(Enabled -eq 'False' -and EmailAddress -like '*#contoso.com') -and (SamAccountName -like 'TEST*' -or SamAccountName -like 'PROD*')"
Get-ADUser -Filter $filter -SearchBase "OU=USERS,DC=contoso,DC=com" -SearchScope Subtree -Properties EmailAddress, MemberOf | ForEach-Object {
if ($_.MemberOf -match 'CN=IT_(Test|Prod)') {
# the user is a member of any IT_Group, get the names of all groups for this user
$groups = foreach ($grp in $_.MemberOf) { (Get-ADGroup -Identity $grp).Name }
$_ | Select-Object Name, SamAccountName, #{Name = 'MemberOf'; Expression = {$groups -join ', '}}
}
else {
# the user is not a member of any IT_Group
$_ | Select-Object Name, SamAccountName, #{Name = 'MemberOf'; Expression = {'Not a member of any IT_Group'}}
}
} | Export-CSV -Path "C:\tmp\output.csv" -NoTypeInformation -Encoding UTF8
Parsing the name of an object from the DistinghuishedName is tricky, because there can be special characters in there. That is why this code uses the Get-ADGroup cmdlet to get the group names.
If the SamAccountNames do not matter and you want to get ALL users in OU OU=USERS,DC=contoso,DC=com that are not Enabled AND have an EmailAddress ending in #contoso.com, than simply change the $filter variable to
$filter = "Enabled -eq 'False' -and EmailAddress -like '*#contoso.com'"
As per your latest comment, you would only want to list the groups IT_Test and/or IT_Prod for users that are member of any of these two groups, the code below should do that:
$filter = "(Enabled -eq 'False' -and EmailAddress -like '*#contoso.com') -and (SamAccountName -like 'TEST*' -or SamAccountName -like 'PROD*')"
Get-ADUser -Filter $filter -SearchBase "OU=USERS,DC=contoso,DC=com" -SearchScope Subtree -Properties EmailAddress, MemberOf | ForEach-Object {
$testgroups = $_.MemberOf | Where-Object { $_ -match 'CN=IT_(Test|Prod)'}
if ($testgroups) {
# the user is a member of group IT_Test and/or IT_Prod, get the names of these groups for this user
$groups = foreach ($grp in $testgroups) { (Get-ADGroup -Identity $grp).Name }
$_ | Select-Object Name, SamAccountName, #{Name = 'MemberOf'; Expression = {$groups -join ', '}}
}
else {
# the user is not a member of any IT_Group
$_ | Select-Object Name, SamAccountName, #{Name = 'MemberOf'; Expression = {'Not a member of any IT_Group'}}
}
} | Export-CSV -Path "C:\tmp\output.csv" -NoTypeInformation -Encoding UTF8
Hope that helps
This code get all users that have groups begining with "IT_" it's provided by $_.memberof -like 'CN=IT_*'.Then for each user getting his name,login and groups what beggins from"CN=IT_",format it with -replace and add it to csv file without rewrite.
$users=Get-ADUser -Filter {filter options} -Properties MemberOf| Where-Object { $_.memberof -like '*CN=IT_*'}
foreach ($user in $users){
$user|Select-Object name , samaccountname ,#{Name="MemberOf";Expression={((($_.MemberOf | Select-String -Pattern 'CN=IT_*')-replace "CN=")-replace ",.+$") -Join ";"}} |Export-CSV -Delimiter ';' -Path "D:\testdir\uss.csv" -NoTypeInformation -Encoding UTF8 -Append
}

detect if computer is not member of at least one group

I have a need to detect computer objects that are not a member of at least one group. I have come up with this script, but instead of listing just the machines that are not a member of at least one group, it returns all workstations. What am I doing wrong?
Get-ADComputer -Filter * -Property * | where {
$_.memberof -notmatch 'Group1' -and
$_.memberof -notmatch 'Group2' -and
$_.memberof -notmatch 'Group3'
} | Format-Table Name
The MemberOf property contains a list of distinguished names. You can't check if it doesn't contain something with the -notmatch operator. Instead get a list of the distinguished names of your groups:
$groups = 'Group1', 'Group2', 'Group3' |
ForEach-Object { Get-ADGroup -Filter "Name -eq '$_'" } |
Select-Object -Expand DistinguishedName
and check if the MemberOf property doesn't contain any of them:
Get-ADComputer -Filter * -Property * | Where-Object {
-not (Compare-Object $groups $_.MemberOf -IncludeEqual -ExcludeDifferent)
} | Format-Table Name
The Compare-Object is required, because you need to check if one array contains any of the elements of another array. Something like $_.MemberOf | Where-Object {$groups -contains $_} would also work.
Note that the MemberOf property does not include the primary group of a computer. If the primary group must also not be one of the groups from your list you need an additional check in the Where-Object filter:
Get-ADComputer -Filter * -Property * | Where-Object {
-not (Compare-Object $groups $_.MemberOf -IncludeEqual -ExcludeDifferent) -and
$groups -notcontains $_.PrimaryGroup
} | Format-Table Name
You're using the -NotMatch operator, which will evaluate to true if the entries do not exactly match. You'd be better served using -NotContain, like so
Get-ADComputer -Filter * -Property * | where {$.memberof -notContains 'Group1' -and $.memberof -notContains 'Group2' -and $_.memberof -notContains 'Group3'} | Format-Table Name