How to receive OU values separately in different columns via powershell? - powershell

The powershell query I use to get the list of all the workstations registered in AD is on below:
Get-ADComputer -Filter {OperatingSystem -NotLike "*server*"} -Property * | Select-Object Name,SID,DistinguishedName,whenCreated,LastLogonDate | Export-CSV allworkstations2.csv -NoTypeInformation -Encoding UTF8
An example of "DistinguishedName" is like:
CN=500-AV,OU=Workstations,OU=SecondOU,OU=ThirdOU,OU=FourthOU,DC=myDC1,DC=myDC2
CN=600-AV,OU=FirstOU,OU=SecondOU,OU=ThirdOU,OU=FourthOU,OU=FifthOU,DC=myDC1,DC=myDC2
Please note that the number of OU values for each workstation can differ, can't say it is always 4. Edit: Maximum number of OU a workstation can have is 5.
I need all the OU values separately, as different columns (OU1, OU2, ... etc). In Excel, I was using this formula below to receive all the OU values in separate columns:
=TRIM(MID(SUBSTITUTE(MID($B2,FIND(",OU=",$B2)+4,FIND(",DC=",$B2)-FIND(",OU=",$B2)-4),",OU=",REPT(" ",999)),(COLUMN(A:A)-1)*999+1,999))
What I want is to get the OU values in different columns directly from the powershell. I couldn't find out the correct syntax to update my query accordingly. Any help would be appreciated.
Here is the version info:
Edit2: Example of expected output:
WorkstationName SID OU1 OU2 OU3 OU4 OU5 createdDate LastLogin
500-AV X Workstations SecondOU ThirdOU FourthOU null 1/1/2018 6/1/2018
600-AV X FirstOU SecondOU ThirdOU FourthOU FifthOU 1/1/2018 6/1/2018

now that you clarified things a tad, i think this does what you want. [grin]
what it does ...
creates two user objects to work with
delete this when you are ready to work with your data set. [grin]
iterates thru the user list
splits the DistinguishedName to get the OUs
makes the $OuList variable into an array even if there is only one OU
builds a custom object with the anticipated max number of OUs
you will need to determine that ahead of time.
sends that object out to the $Results collection
displays that collection
at that point, you have a collection that will gracefully export to a CSV file. [grin]
here's the code ...
$UserList = #(
[PSCustomObject]#{
ComputerName = '111-AV'
SID = '1-22-333'
DistinguishedName = 'CN=111-AV,OU=SolitaryOU,DC=myDC1,DC=myDC2'
DateCreated = '2011-11-11'
LastLogon = '2019-08-11'
}
[PSCustomObject]#{
ComputerName = '500-AV'
SID = '1234-5678-90'
DistinguishedName = 'CN=500-AV,OU=Workstations,OU=SecondOU,OU=ThirdOU,OU=FourthOU,DC=myDC1,DC=myDC2'
DateCreated = '2001-01-01'
LastLogon = '2019-08-08'
}
[PSCustomObject]#{
ComputerName = '666-AV'
SID = '777-888-999'
DistinguishedName = 'CN=666-AV,OU=Servers,OU=SrvOu2,OU=SrvOu3,OU=SrvOu4,OU=SrvOu5,DC=myDC1,DC=myDC2'
DateCreated = '1999-12-31'
LastLogon = '2019-08-20'
}
)
$Results = foreach ($UL_Item in $UserList)
{
[array]$OuList = #($UL_Item.DistinguishedName.Split(',')).
Where({$_ -match 'OU='}).
ForEach({$_.Split('=')[-1]}).
Trim()
[PSCustomObject]#{
ComputerName = $UL_Item.ComputerName
SID = $UL_Item.SID
OU_1 = $OuList[0]
OU_2 = $OuList[1]
OU_3 = $OuList[2]
OU_4 = $OuList[3]
OU_5 = $OuList[4]
DateCreated = $UL_Item.DateCreated
LastLogon = $UL_Item.LastLogon
}
}
$Results
output to screen ...
ComputerName : 111-AV
SID : 1-22-333
OU_1 : SolitaryOU
OU_2 :
OU_3 :
OU_4 :
OU_5 :
DateCreated : 2011-11-11
LastLogon : 2019-08-11
ComputerName : 500-AV
SID : 1234-5678-90
OU_1 : Workstations
OU_2 : SecondOU
OU_3 : ThirdOU
OU_4 : FourthOU
OU_5 :
DateCreated : 2001-01-01
LastLogon : 2019-08-08
ComputerName : 666-AV
SID : 777-888-999
OU_1 : Servers
OU_2 : SrvOu2
OU_3 : SrvOu3
OU_4 : SrvOu4
OU_5 : SrvOu5
DateCreated : 1999-12-31
LastLogon : 2019-08-20

Related

Getting most accurate last logon time for Computer Objects via powershell

I want to get most accurate last logon time for Computer Objects via powershell.
why is returning lastlogon attribute like below ? is it normal ?
Name : SRV01
samAccountName : SRV01$
DistinguishedName : CN=SRV01,DC=contoso,DC=local
lastLogon : 133000120204176004
OperatingSystem : Windows Server 2016 Standard
LastLogonDate : 6/18/2022 10:47:00 AM
Script :
$AllDCs = Get-ADDomainController -Filter * # Get all DCs in the Domain
$logons = [System.Collections.Generic.Dictionary[string,object]]::new()
$params = #{
LDAPFilter = '(LastLogon=*)' # Only find computers that have this Property
SearchBase = 'DC=contoso,DC=local'
Properties = #(
'Name'
'samAccountName'
'DistinguishedName'
'lastLogon'
'OperatingSystem'
)
}
foreach($DC in $AllDCs)
{
$params.Server = $DC
# Find all computers using this target DC
$computerList = Get-ADComputer #params |
Select-Object #(
$params.Properties
#{
Name = 'LastLogonDate'
Expression = { [datetime]::FromFileTime($_.LastLogon) }
}
)
foreach($computer in $computerList)
{
if($logons[$computer.samAccountName].lastLogonDate -lt $computer.lastLogonDate)
{
$logons[$computer.samAccountName] = $computer
}
}
}
$logons.Values
As NiMux explained in his helpful comment and as stated in the Active Directory Schema (AD Schema) MS Docs for this attribute:
The last time the user logged on. This value is stored as a large integer that represents the number of 100-nanosecond intervals since January 1, 1601 (UTC). A value of zero means that the last logon time is unknown.
Below code shows you how you can exclude this property from the output and only keep it's friendly / human readable representation - [datetime]::FromFileTime($_.LastLogon) - as well as some performance improvements.
Dictionary<TKey,TValue> can be replaced with a hashtable, in this case, it is not a performance improvement but also using the generic class will likely not provide a performance gain.
Constructing new objects of all queried computers per Domain Controller is inefficient and should be removed, we're only interested in reconstructing the objects once (once we have the results from the query - bottom part of the code).
$AllDCs = Get-ADDomainController -Filter *
$logons = #{}
$params = #{
LDAPFilter = '(LastLogon=*)'
SearchBase = 'DC=contoso,DC=local'
Properties = 'lastLogon', 'OperatingSystem'
}
foreach($DC in $AllDCs) {
$params['Server'] = $DC
# Find all computers using this target DC
foreach($computer in Get-ADComputer #params) {
# if the reference `lastLogon` in the hashtable is lower than this `lastLogon`
if($logons[$computer.samAccountName].lastLogon -lt $computer.lastLogon) {
# replace the value for this key with this object
$logons[$computer.samAccountName] = $computer
}
}
}
# construct the output
& {
foreach($key in $logons.PSBase.Keys) {
$value = $logons[$key]
[pscustomobject]#{
Name = $value.Name
samAccountName = $value.samAccountName
DistinguishedName = $value.DistinguishedName
LastLogonDate = [datetime]::FromFileTime($value.LastLogon)
OperatingSystem = $value.OperatingSystem
}
}
} | Export-Csv path/to/output.csv -NoTypeInformation

Past only select fields to out-gridview

How can I past only a selection of fields from an object to show in out-gridview, but still keep the whole object as a result.
For example, I retrieve an object that gives me:
$listcreds = get-listofcredentials
Id : 03c0e0c0-0951-4698-9ba9-a70508b5467f
IsLocalProtect : True
Name : vsphere.local\Administrator
CurrentUser : False
UserName : vsphere.local\Administrator
UserNameAtNotation : Administrator#vsphere.local
UserNameSlashNotation : vsphere.local\Administrator
UserNameOnly : Administrator
DomainName : vsphere.local
EncryptedPassword : Veeam.Backup.Common.CCodedPassword
In the gridview I want to only see Name and ID. After the user selects the row desired, I would like to have the result as the same type of object again.
When I use select-object,
$selectedcred = $listofcredentials | select-object Name, Id | out-gridview -passthru
I get the result back but I would now have to search the original object again to get the other properties of that row.
What better way to do this?
You need to find the full object again in the list with Where-Object
This answer assumes the Id property is unique for every item in $listcreds
$listcreds = get-listofcredentials
$selectedcred = $listofcredentials | select-object Name, Id | out-gridview -passthru
$selectedcred = $listcreds | Where-Object {$_.Id -eq $selectedcred.Id}
I don't think there's a better solution here. If performance is a concern, you can convert the Where-Object into a foreach as below:
$listcreds = get-listofcredentials
$selectedcred = $listofcredentials | select-object Name, Id | out-gridview -passthru
foreach ($cred in $listcreds) {
if ($cred.Id -eq $selectedcred.Id) {
$selectedcred = $cred
break
}
}
However, the performance difference may be negligible or even negative.

Get Distribution List muliple Owners in exchange

i need a power shell cmd or script which will give me the list of all the Distributions list along with the OWNERS of that like managed by.
But , if there are multiple users inside managedby attribute then I am getting System.Object[].
My question are :
1- how can we get multiple users for managedby attribute ?
2- how can we add employeeid and samaccountname for managedby users ?
3 - if there is no managed by user then it display "NO MANAGED BY USER"
4- I want to get mail groups not hidden.
script :
$DGroups=Get-DistributionGroup -resultsize unlimited
$mastertable=#()
ForEach($Group in $DGroups){
$table=[pscustomobject][ordered]#{
Name = $group.name
"Managed By" = $group.managedby.name
"DistinguishedName" = $group.DistinguishedName
}
$Mastertable += $table
}
$Mastertable | export-csv C:\tmp\managedby.csv -NoTypeInformation
My output :
"Name","Managed By","DistinguishedName"
"IT research","System.Object[]","CN=IT research,OU=TEST,DC=contoso,DC=com"
"Test Mail Group 1","User01","CN=\Test Mail Group 1,OU=Test,OU=COMPANY,DC=contoso,DC=com"
"Test Mail Group 2",,"CN=\Test Mail Group 2,OU=Test,OU=COMPANY,DC=contoso,DC=com"
My desired output :
"Name","Managed By","DistinguishedName","OWNERSAMACCOUNTNAME","OWNEREMPLOYEEID"
"IT research","User01;User02","CN=IT research,OU=TEST,DC=contoso,DC=com","tst124;tst125","242333;344232"
"Test Mail Group 1","User01","CN=\Test Mail Group 1,OU=Test,OU=COMPANY,DC=contoso,DC=com","tst124","242333"
"Test Mail Group 2","NO MANAGED BY USER","CN=\Test Mail Group 2,OU=Test,OU=COMPANY,DC=contoso,DC=com"
LAST UPDATE :
[PS] C:\Windows\system32>$group.ManagedBy
OrgHierarchyToIgnore :
IsDeleted : False
Rdn : CN=John T
Parent : contoso.com/COMPANY/IT
Depth : 5
DistinguishedName : CN=John T,OU=IT,DC=contoso,DC=com
IsRelativeDn : False
DomainId : contoso.com
PartitionGuid : 59ce2f71-eaa2-4ddf-a4fa-f25069d0b324
PartitionFQDN : contoso.com
ObjectGuid : 62d578e8-b69c-45bc-967a-e530d72792e1
Name : John T
[PS] C:\Windows\system32>$group.ManagedBy | ForEach-Object { $_ | Get-ADUser -Properties EmployeeId }
Get-ADUser : 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:42
+ $group.ManagedBy | ForEach-Object { $_ | Get-ADUser -Properties EmployeeId }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (contoso.com/COMPANY/IT/John T:PSObject) [Get-ADUser], ParameterBindingException
+ FullyQualifiedErrorId : InputObjectNotBound,Microsoft.ActiveDirectory.Management.Commands.GetADUser
It is my understanding the ManagedBy attribute stores the DistinguishedName(s) of one or more users (or none at all).
I haven't tested this myself, but you could try:
$DGroups = Get-DistributionGroup -ResultSize Unlimited
$mastertable = foreach($group in $DGroups) {
# initialize a PsCustomObject
$data = [PsCustomObject]#{
Name = $group.Name
DistinguishedName = $group.DistinguishedName
ManagedBy = 'NOT MANAGED'
OwnerSamAccountName = $null
OwnerEmployeeId = $null
}
if ($group.ManagedBy) {
$managedBy = $group.ManagedBy | ForEach-Object { Get-ADUser -Identity $_.DistinguishedName -Properties EmployeeId }
$data.ManagedBy = $managedBy.Name -join ';'
$data.OwnerSamAccountName = $managedBy.SamAccountName -join ';'
$data.OwnerEmployeeId = $managedBy.EmployeeId -join ';'
}
# output this data to be collected in $mastertable
$data
}
$mastertable | Export-Csv 'C:\tmp\managedby.csv' -NoTypeInformation

Powershell - trimming/splitting an object to export-csv

I am trying to do a very simple task in powershell, I am trying to export a list of users from AD with certain properties. The problem is I need to trim the manager property to only include the name not the OUs etc. When I do this though I have to convert the object to a string which then I cant export to csv and cant get convertto-csv to work.
Get-ADUser gmclean -Properties * | Select sapid,EmailAddress,GivenName,Surname,department,costcenter,Title,Office,MobilePhone,StreetAddress,City,State,PostalCode,Country,manager
sapid : 111111
EmailAddress : test#123.ca
GivenName : Gray
Surname : Mclean
department : Edmonton Sales
costcenter : 213456
Title : Account manager
Office : EDM
MobilePhone : 123456789
StreetAddress : 123 street sw
City : Edmonton
State : AB
PostalCode : Z2Z Z2Z
Country : CA
manager : CN=Tea Ping,OU=Users,OU=EDM,OU=CA,OU=Countries,DC=test,DC=testinc,DC=ca
In this I am able trim the manager property and combine the variables. But I cant figure out how to make headers for all the properties.
$Everything = Get-ADUser gmclean -Properties * | Select sapid,EmailAddress,GivenName,Surname,department,costcenter,Title,Office,MobilePhone,StreetAddress,City,State,PostalCode,Country | ForEach-Object {$_.sapid,$_.EmailAddress,$_.GivenName,$_.Surname,$_.department,$_.costcenter,$_.Title,$_.Office,$_.MobilePhone,$_.StreetAddress,$_.City,$_.State,$_.PostalCode,$_.Country} | Out-string
$manager = Get-ADUser gmclean -Properties * | Select -Property manager | Out-string
$manager1 = $manager.split("="",")
$manager2 = $manager1[1]
$Everything1 = $Everything+$manager2
$Everything1
111111
test#123.ca
Gray
Mclean
Edmonton Sales
213456
Account manager
EDM
123456789
123 street sw
Edmonton
AB
Z2Z Z2Z
CA
Tea Ping
I am sure there is an easier way to do this but unfortunately I cant seem to figure it out.
Thanks,
Use a calculated property on your first pass through Select (all the way at the end):
Get-ADUser gmclean -Properties * | Select sapid,EmailAddress,GivenName,Surname,department,costcenter,Title,Office,MobilePhone,StreetAddress,City,State,PostalCode,Country,#{Name='manager';Expression={$_.manager.Split("=,")[2]}}

How to select multiple subobjects of an object in powershell

The goal is to select all users from a list of groups which contains the subojects "Users" with X users. This user list should be written later as batch to an SQL Server. The goal ist to have a table with the user properties and the groupname + id.
To make the selection and mapping faster, i have tried to work with the select command of powershell. But there is a problem when more than one user is in the group
$GroupUsers = #()
foreach ($group in $groups) {
$GroupUsers = New-Object -TypeName PSObject -Property #{
UserLoginName = $group.Users.LoginName
UserTitle = $group.Users.Title
UserEmail = $group.Users.Email
GroupName = $group.Title
} | Select UserLoginName, UserTitle, UserEmail, GroupName
$GroupUsers+= $GroupUsers
}
The output which is generated looks like the following:
UserId : 33
UserLoginName : WalterX.test.com
UserTitle : Walter X
UserEmail : x#mail.de
GroupName : Group1
GroupId : 1
UserId : {1, 2, 3, 4...}
UserLoginName : {User1.test.com, User2.test.com,User3.test.com ...}
UserTitle : {User1,User2,User3...}
UserEmail : {User1#mail.com,User2#mail.com...}
GroupName : Group2
GroupId : 2
As you can see the first user is exported correctly. The second entry in the array has on the UserLoginName, Title and EMail property multiple users in it...
Don't use +=it's ineffective as it rebuilds the complete array on each addition
Assign the output of the foreach to a variable instead, using a [PSCustomObject]
nest another foreach to iterate the users of the group.
$GroupUsers = foreach($group in $groups) {
foreach($user in $group.Users){
[PSCustomObject]#{
UserLoginName = $User.LoginName
UserTitle = $User.Title
UserEmail = $User.Email
GroupName = $group.Title
}
}
}