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.
Related
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
first time posting here.
I'm stuck with what i thought would be a simple task, trying to list Computers in AD with one or another Membership.
I just want to look in my #Ring variable for two strings as such as 'UPGRADE' or 'RING_'
Is there a simple way to do this ?
Thanks,
For now my code is like that
Get-ADComputer -SearchBase $Base_recherche -Properties * -Filter * |
Select-Object #{name="Nom machine";expression={$_.Name}},
#{n="Dernière date de connexion";e={$_.LastLogonDate}},
#{n="Systeme exploitation";expression={$_.OperatingSystem}},
#{n="Version";expression={$_.OperatingSystemVersion}},
#{n="CheminAD";expression={$_.CanonicalName}},
#{n="Ring";e={$_.memberof -like '*UPGRADE*'}} |
Export-CSV $Chemin_Export -Encoding UTF8 -NoTypeInformation
It seems if you need to only choose AD objects with a membership of 'UPGRADE' or 'RING_' you will need to use the -Filter parameter to filter out the objects ahead of time.
Get-ADComputer -SearchBase $Base_recherche -Properties * -Filter 'memberof -like '*UPGRADE*' -or memberof -like '*RING_*'
This will give you just the objects that satisfy the condition.
EDIT
You can combine the above code with your Select-Object but just add both elements you are looking for.
#{name="Ring";expression={$_.memberof -like '*Ring_*'}},
#{name="Upgrade";expression={$_.memberof -like '*UPGRADE*'}}
This will give you the two columns in your CSV with TRUE/FALSE values per computer line. This way you can know which systems belong to corresponding groups.
ComputerName,Ring,UPGRADE
machineA,true,false
machineb,true,true
machinec,false,true
Get-ADComputer by default returns objects with these properties:
DistinguishedName, DNSHostName, Enabled, Name, ObjectClass, ObjectGUID, SamAccountName, SID, UserPrincipalName
By writing -Properties * you're asking for ALL properties, which is wasteful and time consuming.
Better ask for the extra properties you DO need
Below joins the MemberOf DN's that have either 'UPGRADE' or 'RING_' with a semi-colon as Ring property in the output
$properties = 'LastLogonDate', 'OperatingSystem', 'OperatingSystemVersion', 'CanonicalName', 'MemberOf'
Get-ADComputer -SearchBase $Base_recherche -Properties $properties -Filter * |
Select-Object #{Name = "Nom machine"; Expression = {$_.Name}},
#{Name = "Dernière date de connexion"; Expression = {$_.LastLogonDate}},
#{Name = "Systeme exploitation"; Expression = {$_.OperatingSystem}},
#{Name = "Version"; Expression = {$_.OperatingSystemVersion}},
#{Name = "CheminAD"; Expression = {$_.CanonicalName}},
#{Name = "Ring"; Expression = {($_.MemberOf -match 'UPGRADE|RING_') -join '; '}} |
Export-CSV -Path $Chemin_Export -Encoding UTF8 -NoTypeInformation
If you want your Ring property to be just True if there is any MemberOf that has either 'UPGRADE' or 'RING_' found or False otherwise, then change this
#{Name = "Ring"; Expression = {($_.MemberOf -match 'UPGRADE|RING_') -join '; '}}
into
#{Name = "Ring"; Expression = {[bool]($_.MemberOf -match 'UPGRADE|RING_')}}
How to get displayname from direct reports attribute ?
Get-ADUser $foo -Properties * | select #{Name="directreports";Expression={($_.directreports | %{(Get-ADUser $_).displayname}) -Join ";"}}
Output :
directreports
-------------
;;;;;;;;;;;;;;;;;;
ISSUE resolved :
Get-ADUser $foo -Properties * | select #{Name="directreports";Expression={($_.directreports | %{(Get-ADUser $_).name}) -Join ";"}}
Apologies for misreading your question, try out the below and let me know if this does what you want it to do?
Get-ADUser $foo -Properties * | Select-Object -ExpandProperty DirectReports | ForEach-Object { Get-ADUser -Identity $_ | Select-Object Name }
You can always add on | Export-CSV -Path "c:\temp\directreports.csv" -NoTypeInformation at the end to get this out of course.
On your original code, the easiest way I found to expand out the list of direct reports was to do the select on it's own and then pipe into a foreach, rather than trying to do it all in one as an expression.
Also, DisplayName is not a default property returned by Get-ADUser, so this is why I used the Name property instead in my suggested solution.
Thanks!
I'm new to scripting with Powershell for Active Directory, and attempting to pull out users in a list and enumerating their groups; however when I do so the resultant information contains just the name of the group which is duplicated under many differently named OUs. Looking at them in AD Users and Computers under the Member Of tab shows the Name and the Active Directory Domain Services Folder which contains exactly the differentiating info I need, or alternately I could use the DistinguishedName which isn't as nicely formatted for readability but would also work.
Problem with simplified examples: If a group name is the same across different OUs (like "TestUsers") then the script currently dumps multiple group names without differentiation "TestUsers, TestUsers, TestUsers" instead of showing the underlying OUs in a clean format "Michigan\TestUsers, NewYork\TestUsers" or Distinguished Name format "CN=TestUsers,CN=Michigan,etc";"CN=TestUsers,CN=NewYork,etc".
$alist = "Name`tAccountName`tDescription`twhenCreated`tAcctEnabled`tGroups`n"
$userlist = Get-ADUser -SearchBase "OU=Service Accounts,OU=Information Systems,DC=conteso,DC=local" -Filter * -Properties * | Select-Object -Property Name,SamAccountName,Description,EmailAddress,LastLogonDate,Manager,Title,Department,Company,whenCreated,Enabled,MemberOf | Sort-Object -Property Name
$userlist | ForEach-Object {
$grps = $_.MemberOf | Get-ADGroup | ForEach-Object {$_.Name} | Sort-Object
$arec = $_.Name,$_.SamAccountName,$_.Description,$_.whenCreated,$_.Enabled
$aline = ($arec -join "`t") + "`t" + ($grps -join "`t") + "`n"
$alist += $aline
}
$alist | Out-File C:\psscripts\service_accounts_groups.csv
Any help is appreciated!
I agree that DistinguishedName already has this information but I think it is easier to just use Get-AdGroup to get some friendlier information. A little string manipulation on the CanonicalName of the group, while not as efficient maybe, would be easier to work with.
$grps = $_.MemberOf | Get-AdGroup -Properties CanonicalName | ForEach-Object{
$CN = ($_.CanonicalName -Split "/")
"{0}\{1}" -f $CN[-2],$CN[-1]
}
or as a one liner if you prefer.
$grps = $_.MemberOf | Get-AdGroup -Properties CanonicalName | ForEach-Object{$CN = ($_.CanonicalName -Split "/"); "{0}\{1}" -f $CN[-2],$CN[-1]}
What we do is take the CanonicalName which can be considered the path of the object in Active Directory. Since you only wanted the parent container we split up the path and join only the last two parts. The group object and its container.
Same result could come from just getting the second last element from CanonicalName and appending the group name to it. Might look at little nicer
$grps = $_.MemberOf | Get-AdGroup -Properties CanonicalName | ForEach-Object{"{0}\{1}" -f ($_.CanonicalName -Split "/")[-2],$_.Name}
Since the "$_.memberof" property already has the Distinguished name, you don't need to pass it to Get-Adgroup again. so simply replace your $grps line like this
$grps = $_.MemberOf -replace "CN=","" -replace "OU=","" -replace "DC=","" -replace ",","\" | Sort-Object
Or if you still want to proceed with your approach, use it with distinguishedname property instead of name property - like this (with the text replace)
$grps = $_.MemberOf | Get-ADGroup | ForEach-Object {$_.DistinguishedName -replace "CN=","" -replace "OU=","" -replace "DC=","" -replace ",","\"} | Sort-Object
Or as suggested by Matt in the comment, simply use canonicalname property.
$grps = $_.MemberOf | Get-ADGroup -Properties canonicalname | select -ExpandProperty canonicalname
Cheers, GJ
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