Local users and their groups - powershell

I want to get a similar report as in the following thread for a bunch of computers retrieved from the AD.
$adsi = [ADSI]"WinNT://$($WKS.name)"
$adsi.Children | where { $_.SchemaClassName -eq 'user' } | Foreach-Object {
$groups = $_.Groups() | Foreach-Object { $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null) }
$_ | Select-Object #{ n = 'UserName'; e = { $_.Name } }, #{ n = 'Groups'; e = { $groups -join ',' } } | | Export-Csv -Path "\\..\KontaLokalne.csv" -NoClobber -Append -Encoding UTF8 -Delimiter ";" -NoTypeInformation
}
I want to get an additional information about each account listed - is the account enabled or not.
Additionally, I would like to send the output to the file in the format: computer name; account name; member of the groups.
Could You help me?

To check whether a user account is enabled or not using ADSI, you will have to test if the ADS_UF_ACCOUNTDISABLE bit in the .UserFlags property is set or not.
To do this, you need to bitwise and the value of the UserFlags with the value of ADS_UF_ACCOUNTDISABLE (2):
$adsi = [ADSI]"WinNT://$($WKS.name)"
$result = $adsi.Children | Where-Object { $_.SchemaClassName -eq 'user' } | ForEach-Object {
$groups = $_.Groups() | Foreach-Object { $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null) }
$_ | Select-Object #{Name = 'UserName'; Expression = { $_.Name } },
#{Name = 'Enabled'; Expression = { ($_.UserFlags.Value -band 2) -eq 0} },
#{Name = 'Groups'; Expression = { $groups -join ',' } }
}
# now you can export the resulting collection
# do you really want to use -Append here?
$result | Export-Csv -Path "\\..\KontaLokalne.csv" -NoClobber -Append -Encoding UTF8 -Delimiter ";" -NoTypeInformation
See ADS_USER_FLAG_ENUM

Related

Powershell - cheking var is giving me the right results but Export-CSV gives numbers

what I want is that the $report_groups val gives me in Export-CSV the output that i get in Terminal. But i cant figure it why does he gives me Numbers.
$get_AD_Groups = Get-ADGroup -Filter '*' | Select-Object Name
$report_groups = New-Object -TypeName System.Collections.ArrayList
foreach ($item in $get_AD_Groups) {
$get_users = $item.Name | Get-ADGroupMember | Select-Object Name
$disabled_user = 0
foreach ($user in $get_users) {
$status = $user.Name | Get-ADUser -ErrorAction SilentlyContinue
if(($status.ObjectClass -eq 'user') -and ($status.Enabled -ne 'True')) {
$disabled_user++
}
}
if ($get_users.Count -eq $disabled_user) {
$report_groups.Add($item.Name)
}
}
$report_groups | Export-Csv -Path "..\report.csv" -NoTypeInformation -Force -Delimiter ";"
Now when i run $report_groups in Terminal i get the list of the AD Group BUT as soon i do the Export-CSV this is what i get:
So thanks again to Lee_Dailey for helping me on this.
Changes done.
$report_groups = #()
if ($get_users.Count -eq $disabled_user) {
$fill = [PSCustomObject]#{
AD_GROUP = $item.Name
}
$report_groups += $fill
}

Expanding System.Object[] for Export to CSV

Hello again and sorry!
To keep it really short. What am i doing wrong?
Im attempting to export a list of users filtered by using a customobject to a CSV and it outputs it into the same block. Is there no way to change this? I only ask because, all the other pages ive looked at it keeps telling me to use -join, to join them as strings which does the exact same thing. Is it not possible to output it as multiple rows for each user?
$GPMem = Get-ADGroupMember -Identity security.group | Select-Object -ExpandProperty Name
[array]$TPpl = $GPMem | Where-Object {$_ -like "T*"}
[array]$RPpl = $GPMem | Where-Object {$_ -like "r*"}
[array]$CPpl = $GPMem | Where-Object {$_ -like "c*"}
[pscustomobject]#{
TPeople = (#($TPpl) |Out-String).Trim()
TPCount = $TPpl.Count
RPeople = (#($RPpl) |Out-String).ToString()
RPCount = $TPpl.Count
CPeople = $CPpl
CPCount = $TPpl.Count
} | Export-Csv -Path C:\Users\abraham\Desktop\csv.csv -NoTypeInformation -Force
here is how to insert a ; OR newline into the values of a column ... [grin]
$ThingList = #('One Thing', 'Two Thing', 'Three Thing')
$ThingList -join '; '
'=' * 20
$ThingList -join [System.Environment]::NewLine
output ...
One Thing; Two Thing; Three Thing
====================
One Thing
Two Thing
Three Thing
create 3 more arrays for the count (each array will be exported to a column), then find the array with the most count and generate a psobject for each line.
[array]$TPpl = #("T1" ,"T2", "T3")
[array]$TPpl_count = #($TPpl.Count)
[array]$RPpl = #("R1" ,"R2", "R3", "R4")
[array]$RPpl_count = #($RPpl.Count)
[array]$CPpl = #("C1" ,"C2", "C3", "C4","C5")
[array]$CPpl_count = #($CPpl.Count)
$leng = [array]$TPpl.Count,$RPpl.Count,$CPpl.Count
$max = ($leng | measure -Maximum).Maximum
$csv = for($i=0;$i -lt $max;$i++){
New-Object -TypeName psobject -Property #{
"TPeople" = $(if ($TPpl[$i]) { $TPpl[$i]})
"TPCount" = $(if ($TPpl_count[$i]) { $TPpl_count[$i]})
"RPeople" = $(if ($RPpl[$i]) { $RPpl[$i]})
"RPCount" = $(if ($RPpl_count[$i]) { $RPpl_count[$i]})
"CPeople" = $(if ($CPpl[$i]) { $CPpl[$i]})
"CPCount" = $(if ($CPpl_count[$i]) { $CPpl_count[$i]})
}
}
$csv | Export-Csv C:\Temp\test.csv -NoTypeInformation
result:
your final code should be:
$GPMem = Get-ADGroupMember -Identity security.group | Select-Object -ExpandProperty Name
[array]$TPpl = $GPMem | Where-Object {$_ -like "T*"}
[array]$RPpl = $GPMem | Where-Object {$_ -like "r*"}
[array]$CPpl = $GPMem | Where-Object {$_ -like "c*"}
[array]$TPpl_count = #($TPpl.Count)
[array]$RPpl_count = #($RPpl.Count)
[array]$CPpl_count = #($CPpl.Count)
$leng = [array]$TPpl.Count,$RPpl.Count,$CPpl.Count
$max = ($leng | measure -Maximum).Maximum
$csv = for($i=0;$i -lt $max;$i++){
New-Object -TypeName psobject -Property #{
"TPeople" = $(if ($TPpl[$i]) { $TPpl[$i]})
"TPCount" = $(if ($TPpl_count[$i]) { $TPpl_count[$i]})
"RPeople" = $(if ($RPpl[$i]) { $RPpl[$i]})
"RPCount" = $(if ($RPpl_count[$i]) { $RPpl_count[$i]})
"CPeople" = $(if ($CPpl[$i]) { $CPpl[$i]})
"CPCount" = $(if ($CPpl_count[$i]) { $CPpl_count[$i]})
}
}
$csv | Export-Csv C:\Temp\test.csv -NoTypeInformation

Parse String with PowerShell

I'm getting a report for users. The 'membership of' is a string with all the groups per user between double quotes.
I need to place \ between each group. Now I have:
"GROUP1""GROUP2""GROUP3"
And I need:
"GROUP1"\"GROUP2"\"GROUP3"
Right now my code is:
foreach ($server in $servers) {
$Comp = $server
if (test-connection -computername $Comp -count 1 -quiet) {
([ADSI]"WinNT://$comp").Children | ?{$_.SchemaClassName -eq 'user'} | %{
$groups = $_.Groups() | %{$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}
$_ | Select #{n='Server';e={$comp}},
#{n='DistingishedName';e={$_.AdsPath}},
#{n='Nombre';e={$_.FullName}},
#{n='Departamento';e={$_.Department}},
#{n='Email';e={$_.EmailAddress}},
#{n='Active';e={if ($_.PasswordAge -like 0) {$false} else {$true}}},
#{n='PasswordExpired';e={if ($_.PasswordExpired) {$true} else {$false}}},
#{n='LastLogin';e={$_.LastLogin}},
#{n='Description';e={$_.Description}},
#{n='Groups';e={$Groups -join '"'}}
} | Export-Csv $ReportFile -Delimiter ';' -Force -Encoding UTF8 -NoTypeInformation -Append
} else {
Write-Warning "Server '$Comp' is Unreachable hence Could not fetch data" 3>> $LogFile
}
}
try -join '"\"' instead of -join '"'

How to count the variable storage value and filter which are less than 1

I am trying to extract the group membership count from each of the server I supply. Below script works for that:
$computers = gc D:\Samir-PS\serverlist.txt
$computers | foreach {
$computername = $_
[ADSI]$S = "WinNT://$($env:computername)"
$S.children.where({$_.class -eq 'group'}) |
Select #{Name="Name";Expression={$_.name.value}},
#{Name="Members";Expression={
[ADSI]$group = "$($_.Parent)/$($_.Name),group"
$members = $Group.psbase.Invoke("Members")
($members | ForEach-Object {
$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
}) -join ";"
}}
} | Export-Csv -Path d:\samir-ps\audit.csv
but, I want to refine the output while it is generated. If the group does not have any members in it, it should not write to the CSV file. So it should only write groups which got one or more members in it. The solution should also improve the performance. Please suggest all the possible ways to do this if there are more than one.
You can use .count to validate and loop around that.
Try this in your code:
if(($members.count) -gt 0)
below:
$computers = gc D:\Samir-PS\serverlist.txt
$computers | foreach {
$computername = $_
[ADSI]$S = "WinNT://$($env:computername)"
$S.children.where({$_.class -eq 'group'}) |
Select #{Name="Name";Expression={$_.name.value}},
#{Name="Members";Expression={
[ADSI]$group = "$($_.Parent)/$($_.Name),group"
$members = $Group.psbase.Invoke("Members")
if(($members.count) -gt 0)
{
($members | ForEach-Object {
$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
}) -join ";"
}
}}
} | Export-Csv -Path d:\samir-ps\audit.csv

Change the script to export Groups and nested objects differently

I created a similiar script like that:
$Groups = Get-QADGroup
$Result = #()
$Groups | ForEach-Object {
$Group = $_
$Members = Get-QADGroupMember $Group -Indirect | ? objectClass -eq "user"
$Obj = '' | Select-Object -Property Name, Members
$Obj.Name = $Group.Name
$Obj.Members = ($Members | % {$_.SamAccountName + "_" + 'Test'})
$Result += $Obj
}
$Result | Export-Csv -Path C:\Temp\groups.csv -NoTypeInformation -Encoding Unicode -Delimiter ";"
The output looks something like this (example data):
"Name";"Members"
"RootGroup01";"Subuser01_Test";"Subuser02_Test";"Subuser03_Test"
"RootGroup02";"Subuser02_Test"
"RootGroup03";"Subuser01_Test";"Subuser02_Test";"Subuser04_Test";
Is it possible to change the script, that I get something like this?:
"RootGroup01";"RootGroup02";"RootGroup03"
"Subuser01_Test";"Subuser02_Test";"Subuser01_Test"
"Subuser02_Test";;"Subuser02_Test"
"Subuser03_Test";;"Subuser04_Test"
The group names should be the header and the belonging users are in the right column. If there is no user, the column cell just stays empty.
You can write such function to transpose your data:
function Transpose-Data{
param(
[String[]]$Names,
[Object[][]]$Data
)
for($i = 0;; ++$i){
$Props = [ordered]#{}
for($j = 0; $j -lt $Data.Length; ++$j){
if($i -lt $Data[$j].Length){
$Props.Add($Names[$j], $Data[$j][$i])
}
}
if(!$Props.get_Count()){
break
}
[PSCustomObject]$Props
}
}
Then you invoke it in the following way:
$Groups = #(Get-QADGroup)
$Members = #(
$Groups | ForEach-Object {
,#(
Get-QADGroupMember $_ -Indirect |
? objectClass -eq user |
% {$_.SamAccountName + "_" + 'Test'}
)
}
)
Transpose-Data $Groups.Name $Members |
Export-Csv -Path C:\Temp\groups.csv -NoTypeInformation -Encoding Unicode -Delimiter ";"