I am trying to get a pscustomobject to sort by Canonicalname length, but in order to do this I need the length of each CanonicalName within the PScustomobject.
The Canonicalnamelen is where the length needs to be stored and sorted.
The reason I need to do this is so I can delete OU's within AD that are longer before the lower OU's(But that is not the issue) - i.e. (delete OU /computers/location/IT/test before deleting /computers/location/IT)
So as a result of sorting the list by Canonical Length the canon locations would show like this:
/computers/location/IT/test
/computers/location/IT
The lesser length being always below.
Hope I have explained OK.
My code is as below:
$SourceOU = "OU=Computers,DC=domain,DC=my,DC=my"
##Load up OU's into variable
$OUszero = Get-ADOrganizationalUnit -Properties CanonicalName, DistinguishedName, Description -Filter * -SearchBase $SourceOU | Sort-Object CanonicalName |
ForEach-Object {
[pscustomobject]#{
Name = Split-Path $_.CanonicalName -Leaf
###I need the length of each object string from CanonicalName and display below in
##CanonicalNamelen.
CanonicalName = $_.CanonicalName
DistinguishedName = $_.DistinguishedName
#UserCount = #(Get-AdUser -Filter * -SearchBase $_.DistinguishedName -SearchScope Subtree).Count
ComputerCount = #(Get-AdComputer -Filter * -SearchBase $_.DistinguishedName -SearchScope Subtree).Count
###Here is where I need the length of the object to appear.
##But it just gives a count of canonical names
CanonicalNamelen = ($OUszero.Canonicalname.Length)
}
} | Where-Object ComputerCount -EQ 0
$OUszero | FT
Related
I'm looking to sort numerically my output with the numbers at the end of each.
Get-ADComputer -Filter * -SearchBase "OU=ComputerOU,DC=dc,DC=com" -Properties * | Select-Object -ExpandProperty Name
What i would like:
QCL-00010
JPL-00011
TUL-00012
TUL-00013
QCL-00014
What i have:
JPL-00011
QCL-00010
QCL-00014
TUL-00012
TUL-00013
Thank you in advance
Using the example names, where all numeric values have the same length, padded with leading zeroes, you could simply extend the code you have:
Get-ADComputer -Filter * -SearchBase "OU=ComputerOU,DC=dc,DC=com" |
Select-Object -ExpandProperty Name |
Sort-Object {($_ -split '-')[-1]}
However, to be on the safe side I'd cast to [int] as well:
Get-ADComputer -Filter * -SearchBase "OU=ComputerOU,DC=dc,DC=com" |
Select-Object -ExpandProperty Name |
Sort-Object {[int]($_ -split '-')[-1]}
Result:
QCL-00010
JPL-00011
TUL-00012
TUL-00013
QCL-00014
BTW. if all you need is the .Name property, do not ask for ALL properties with -Properties *
If every computer in the OU matches the nomenclature, I would just use a calculated property with Sort-Object and some pretty standard text munging:
Get-ADComputer -Filter * -SearchBase "OU=ComputerOU,DC=dc,DC=com" |
Sort-Object -Property #{e={$_.Name.Substring($_.Name.IndexOf('-') + 1)}} |
Select-Object -ExpandProperty Name
Also, you should avoid -Properties * with Get-AD* commands unless you absolutely have to. Name is returned by default.
There are a couple of ways to do something like this, somewhat depending on how static the format is.
$Names = #(
'JPL-00011'
'QCL-00010'
'QCL-00014'
'TUL-00012'
'TUL-00013'
)
$Names | Sort-Object {[Void]($_ -match "(\d{5}$)"); $matches[1]}
Here I used the matches collection as the sort expression.
I'm looking for some guidance on creating a powershell script that will check security and distribution groups from specific OU's and see if the owner is a user who's disabled.
We have lots of old groups in our AD created by ex employees that need to be cleaned up.
This is what i've started with.
$managedByGroups = get-adgroup -filter 'groupCategory -eq "Distribution"' -SearchBase "OU=SydExchangeGroups,OU=SydGroups,OU=Sydney,DC=my,DC=org,DC=biz" -Properties distinguishedname, managedby | select sAMAccountName, managedby
$disabledUsers = Get-ADUser -Filter {Enabled -eq $false} -SearchBase "OU=SydDisabledUsers,OU=SydMisc,OU=Sydney,DC=my,DC=org,DC=biz" | select distinguishedname
foreach ($group in $managedByGroups){
if($managedByGroups.managedby -eq $disabledUsers.distinguishedname)
{
write-output
}
}
Thanks
There are a number of issues with your if block:
you are looping through $managedByGroups, but you are never using that variable (it should be $group.managedby)
you are trying to compare 1 element with a list of elements, in this case consider using -in operator instead of -eq.
you should treat the case when there is no value for managedby attribute, in case you do not get the desired results.
An alternative to your code may is below.
I'm first getting the list of managedby users, then i'm looping though each entry, and if it is not null, we try to do a get-aduser filtering by enabled status and the distinguishedname.
$DisabledManagedBy variable will contains ADUser objects which are disabled.
$grp = get-adgroup -filter 'groupCategory -eq "Distribution"' -Properties ManagedBy,DistinguishedName
$DisabledManagedBy = foreach ($item in $grp.ManagedBy) {
if ($item) {
Get-ADUser -Filter {Enabled -eq $false -and DistinguishedName -like $item} -Properties DistinguishedName
}
}
I worked this out eventually by doing the following:
$myDisabledUsers = #()
$date = get-date -format dd-MM-yyyy
$managedSydGroups = Get-ADGroup -Filter * -Properties * -Searchbase "OU=SydExchangeGroups,OU=SydGroups,OU=Sydney,DC=my,DC=biz,DC=org" | where {$_.managedby -ne $null} | select name, managedby
$disabledSydUser = Get-ADUser -Filter * -SearchBase "OU=SydDisabledUsers,OU=SydMisc,OU=Sydney,DC=my,DC=biz,DC=org" | where {$_.enabled -eq $false} | select -ExpandProperty distinguishedname
$disabledOwners = foreach($group in $managedSydGroups)
{
$managedByString = [string]$group.managedby
if($disabledSydUser -contains $managedByString)
{$myDisabledUsers += $group}
}
I am trying to get AD Users with a last login greater than X number of days, and also retrieve their managers email.
I have searched a lot but not getting what I need, right now below is what I have. It does not filter users with latest login timestamp or not logged on in more than X days.
Once I am able to filter both these attributes I can add the email syntax for each user to send email to their manager.
$dcs = Get-ADDomainController -Filter * | Select-Object -Property Name
foreach ($dc in $dcs)
{
$lastlogon = Get-ADUser -Filter * -SearchBase "OU=Sandbox_Users,DC=twi-test,DC=com" -Properties * | Select-Object -Property displayname,lastlogon,samaccountname,EmailAddress,#{Name = "Manager" ; Expression = {(Get-ADUser $_.Manager).Name}},#{Name = "ManagerEmail" ;`
Expression = {(Get-ADUser $_.manager -Properties emailaddress).EmailAddress}
}}
You should (in theory) be able to do this by filtering on the lastlogondate field as part of the get-aduser command (with a $days variable of the X days you want, or just define an integer directly instead):
-filter { lastlogondate -lt ((get-date).adddays($days)) }
Full code:
$days = 7
$dcs = Get-ADDomainController -Filter * | Select-Object -Property Name
foreach ($dc in $dcs) {
$lastlogon = Get-ADUser -Filter { lastlogondate -lt ((get-date).adddays($days)) } -SearchBase "OU=Sandbox_Users,DC=twi-test,DC=com" -Properties * |
Select-Object -Property displayname,lastlogon,samaccountname,EmailAddress,`
#{Name = "Manager";Expression = {(Get-ADUser $_.Manager).Name}},`
#{Name = "ManagerEmail"; Expression = {(Get-ADUser $_.manager -Properties emailaddress).EmailAddress}}
}
Per your comment regarding how to get the only the result with the most recent lastlogon result, i'd suggest switching to a ForEach-Object loop as you can then pipe the results for further filtering:
$days = 7
$dcs | foreach-object {
Get-ADUser -Server $_ -SearchBase "OU=Sandbox_Users,DC=twi-test,DC=com" -Properties * |
Where-Object { $_.LastLogonDate -le (Get-Date).AddDays(-$days) } |
Select-Object -Property displayname,lastlogon,samaccountname,EmailAddress,`
#{Name = "Manager";Expression = {(Get-ADUser $_.Manager).Name}},`
#{Name = "ManagerEmail"; Expression = {(Get-ADUser $_.manager -Properties emailaddress).EmailAddress}}
} | sort lastlogon -desc | select -first 1
I just noticed also that in your original code you weren't actually making use of the $dcs collection. In this revision i've added a -server switch on the first get-aduser to make use of it.
I'm working on a script that will run down a csv of LastName and FirstName of users on a domain and return someinfo about them in another csv.
Returning the properties is not an issue, but when I try to convert pwdLastSet and LastLogonTimeStamp to a readable format, it crashes when writing to the csv.
Here is my code. in this example, pwdLastSet will result in an unreadable 64bit number.
$names = import-csv C:\Users\me\Desktop\input.csv
$users = #()
foreach ($name in $names){
$filter = "givenName -like ""*$($name.FirstName)*"" -and sn -like ""$($name.LastName)"""
$users += get-aduser -filter $filter -Properties * | select-object employeeID, sn, givenName, distinguishedName, whencreated, passwordnotrequired, enabled, admincount, pwdlastset
}
$users | select employeeID, sn, givenName, distinguishedName, whencreated, passwordnotrequired, enabled, admincount, pwdlastset | export-csv c:\users\me\desktop\results.csv -NoTypeInformation
I'd like to throw $([datetime]::FromFileTime($user.pwdLastSet)) so it's readable in the output.
Any ideas?
You can use a calculated property to replace the value of a property or create an additional property:
$users += Get-ADUser -Filter $filter -Properties * |
select employeeID, ..., admincount,
#{n='pwdLastSet';e={[DateTime]::FromFileTime($_.pwdLastSet)}}
In this case it's an unnecessary step, though, because Get-ADUser already did that for you and placed that value in the PasswordLastSet property, as #user3815146 already pointed out (+1).
To get an overview of the properties of a user object you can use the Get-Member cmdlet:
Get-ADUser -Filter * -Property * | Get-Member
or list the members of any given user object:
Get-ADUser -Identity 'someuser' -Property * | Format-List *
On a more general note: never append to an array in a loop. The construct
$arr = #()
foreach ($item in $list) {
$arr += Do-StuffWith $item
}
guarantees poor performance, because with each iteration a new array is created (size + 1) and all elements are copied from the old array to the new one. Using a ForEach-Object loop in a pipeline provides far better performance:
$arr = $list | ForEach-Object { Do-StuffWith $_ }
Don't use pwdLastSet, try using PasswordLastSet.
On a different note, have you considered shortening your command to this:
$users += get-aduser -filter $filter -Properties employeeID,sn,givenName,distinguishedName, whencreated,passwordnotrequired,enabled,admincount,passwordlastset
I would like to compare two organizational units users.
I can get my user list with this command:
OU_NUMBER_1:
Get-ADUser -filter * -SearchBase "OU=OU_NUMBER_1,OU=OU-SNE_SharePoint,DC=vf,DC=local" | Select sAMAccountName
OU_NUMBER_2:
Get-ADUser -filter * -SearchBase "OU=OU_NUMBER_2,OU=OU-SNE_SharePoint,DC=vf,DC=local" | Select sAMAccountName
I would like to get homonymous from these lists. Do I have to put my users in some lists and compare them ? Or anyone get a better idea ?
To summary, I would like to get a list with homonymous of my OU's.
/Update
Try
$UserGroup1 = Get-ADUser -filter * -SearchBase "OU=OU_NUMBER_1,OU=OU-SNE_SharePoint,DC=vf,DC=local" | select sAMAccountName
$UserGroup2 = Get-ADUser -filter * -SearchBase "OU=OU_NUMBER_2,OU=OU-SNE_SharePoint,DC=vf,DC=local" | Select sAMAccountName
$UserInBothOU = Compare-Object $UserGroup1 $UserGroup2 -IncludeEqual
Be aware that the Array $UserInBothOU contains PowerShell Objects.
When you want the sAMAccountName, then you must do something like that:
foreach($User in $UserInBothOU)
{
Write-host $User.sAMAccountName
}
Because sAMAccountName is only an attribute.
$OLDGroup = Get-ADUser -filter * -SearchBase "OU=InactiveObjects,DC=gov,DC=au" -server "gov.au" | select sAMAccountName
$NEWGroup = Get-ADUser -filter * -SearchBase "OU=StandardUsers,OU=Users,DC=nsw,DC=gov,DC=au" -server "nsw.gov.au" | Select sAMAccountName
compare-object $OLDGroup $NEWGroup -Property 'SamAccountName' -IncludeEqual