No output to CSV using PowerShell psobject in Active Directory - powershell

I have this portion of code here that has worked in the past in multiple AD environments, however after testing within a new AD environment, I am getting no output to CSV or any errors being thrown. The size of the CSV file is always zero.
if (![string]::IsNullOrEmpty($searchbase))
{
$ADComputers = get-adcomputer -searchBase $searchbase -filter * -properties * -ResultPageSize $resultpagesize
}
else
{
$ADComputers=Get-ADComputer -Filter * -Properties * -ResultPageSize $resultpagesize
}
$data = #()
foreach ($computer in $ADComputers) {
$computer.member| foreach-object {$members += $_}
$computer.memberof | foreach-object {$memberof += $_}
$memstr = ($members -join ";")
$memstr2 = ($memberof -join ";")
$ADcomp = Get-ADComputer $computer -properties logonCount, ManagedBy | select-object logonCount, ManagedBy
$row = New-Object -TypeName psobject -Property #{
PrincipalID = $script:ctr;
logonCount=$ADcomp.logonCount;
ManagedBy=$ADcomp.ManagedBy;
}
$data += $row
$script:ctr++
}
$data | Export-Csv "ADComputers.csv" -NoTypeInformation
I'm not sure exactly where to go from here because I have tested multiple different options, so any help would be greatly appreciated!

The only reason you get no output is that $ADComputers has no elements. This may be related to a value in the variable $searchbase that does not exist or simply has no computer accounts in it.
But here are some general recommendations:
you do:
if (![string]::IsNullOrEmpty($searchbase))
you could also do:
If ($searchbase)
In principle if you have different scenarios to cover and so the parameter may change take a look at splatting.
Then you query all computers with all available properties but later in the loop you query the specific computer again which is not necessary. Also you should avoid adding elements to an array by using +=, this causes to rebuild the array each time which is slow.
Furthermore $computer.memberof is already an array holding the information but you pipe it to foreach and build a new array holding the identical information only to join it later to a string.
If this is not part of function I don't know why you raise the scope of the variable $ctr from local to script think this is not necessary.
Putting this all together you could do:
#Define HashTable for splatting
$parametersHt = #{
filer='*'
properties='*'
resultsetpagesize=$resultpagesize
}
#If searchbase is specified add parameter to splatting HashTable
If ($searchbase){
$parametersHt.add('Searchbase',$searchbase)
}
#Get computers
$ADComputers = get-adcomputer #parametersHt
#Set Counter
$ctr = 0
$data = #(
foreach ($computer in $ADComputers){
$ctr++
[PSCustomObject]#{
PrincipalId = $ctr #Really the counter here - not $computer.samaccountname?
logonCount=$computer.logonCount
manageddBy=$computer.ManagedBy
memberof=($computer.memberof -join ";") #added this, but in your code sample you don't return this value, if not needed remove. btw. a computer can be memberof a group but it can't have members
}
}
)
$data | Export-Csv -path ".\ADComputers.csv" -NoTypeInformation

Related

Powershell Script to pull all AD users and last time password was changed and date of change

I am attempting to create a script to extract all AD users from 3 different domains with their last logon date as well as the last time they changed their password and extract it to a CSV. I have the following code:
$data = #()
$domains = "example.exa.com "," example.com",” ex.example.com”
foreach($domain in $domains)
{
$data | Foreach-Object –Process { get-aduser -filter * -server $domains -properties passwordlastset,lastlogondate | select name, passwordlastset,lastlogondate }
$data | Export-csv –Path C:\passwords.csv -notypeinformation
The following code does not produce any errors, but it runs infinitely with no results. Can anyone help with what I am doing wrong?
There are quite a few things wrong with your code:
You define the three domains with leading or trailing spaces
You loop through the $domains using iterating variable $domain, but in the loop you are using the complete array $domains
$data is defined as (empty) array on top, but still you use it to loop through its elements (which aren't there) by piping to Foreach-Object
Try to avoid adding items to an array with += as it needs to reconstruct the entire array in memory on every addition
Try:
$domains = 'example.exa.com','example.com','ex.example.com'
$data = foreach($domain in $domains) {
# just output the objects here, so they will be collected for you in variable $data
Get-ADUser -Filter * -Server $domain -Properties PasswordLastSet, LastLogonDate | Select-Object Name, PasswordLastSet, LastLogonDate
}
$data | Export-csv –Path 'C:\passwords.csv' -NoTypeInformation

Get-AdUser no acepting variable

im trying to pull out all the information regarding my domain admin adminsitrators
#set domains we are going to query
$domains = 'mydomainname.com'
#first here i bring the sam accounts names
Foreach ($domain in $domains)
{
$OUTPUT =Get-AdGroupMember -identity “Domain Admins” -recursive -server $domain |
Select-Object -Property samAccountName|
Select samAccountName;
$Outputs +=$OUTPUT;
$OUTPUT |Export-CSV "C:\File\$($domain).csv" -NoTypeInformation ;
}
$OUTPUT #this print the sam accounts
#here is the problem
Foreach ($user in $OUTPUT)
{
$Users2 =Get-ADUser -Filter "SamAccountName -like '$OUTPUT'" -Properties *
$USER3 +=$Users2;
$Users2 |Export-CSV "C:\File\$($domain)Userpop.csv" -NoTypeInformation ;
}
I think this is a problem with your filter. Try changing that line as follows:
Get-ADUser -Filter " SamAccountName -like `"$($user.samaccountname)`" " -Properties *
It can't be $OUTPUT as that's an array. Your loop variable is $user which is an object so you need the .samaccountname property. The filter needs a string with the -like matching a quoted string, so you need `" to pass the quote through to the final string.
Your CSV output of $user2 may not be what you expect either as each object is output to the same file. Perhaps you mean to have a -Append or write them to different files?
You'll probably want to reset $user3 as well. Perhaps add $user3 = #() before that loop.
You should always try to avoid adding to arrays with $array += $something, because that means the entire array gets rebuild in memory, costing time and resources.
Also, I would advise using more descriptive variable names, so the code will still be understandable after some time.
Then, because you are getting info from different domains, it is important to store the domain name in the first loop together with the samaccount names, so you can use these as -Server parameter in the second loop on Get-ADUser
Try
#set domains we are going to query
$domains = #('mydomainname.com') # since there is only one domain listed, use #() to force it into an array
$domainsAndAdmins = foreach ($domain in $domains) {
# store the SamAccountNames for this domain as objects in an array
$admins = Get-AdGroupMember -Identity 'Domain Admins' -Recursive -Server $domain |
Select-Object -Property SamAccountName
# export this to csv file
$outFile = 'C:\File\{0}.csv' -f $domain
$admins | Export-Csv $outFile -NoTypeInformation
# output an object with both the domain and the array of SamAccountNames
# this will be captured in variable $domainsAndAdmins
[PsCustomObject]#{Domain = $domain; Admins = $admins.SamAccountName }
}
# output on screen
$domainsAndAdmins | Format-Table -AutoSize
# will result in something like
#
# Domain Admins
# ------ ------
# mydomainname.com {jdoe, jbloggs, mpimentel}
# myseconddomainname.com {jdoe, mpimentel}
# next get ALL (?) properties from the users we found
$domainsAndAdmins | ForEach-Object {
$domain = $_.Domain
$result = foreach ($user in $_.Admins) {
Get-ADUser -Filter "SamAccountName -like '$user'" -Server $domain -Properties * -ErrorAction SilentlyContinue
}
$outFile = 'C:\File\{0}_Userpop.csv' -f $domain
$result | Export-Csv $outFile -NoTypeInformation
}

find members of groups excluding disabled users

I have 10 security groups all that are called " 'companyname' RDS Users"
I am trying to create a script that does the following: List all the groups and then list all of the members excluding the disabled members, then have it email a csv. I have done the following but cant get the disabled user excluded.
The Script belows shows how far i got but the disabled users show in there which basically means the script is pointless.
$mailServer = ""
$mailFrom = ""
$mailTo = ""
$mailSubject = ""
$file = "somepath\RDSUsers.csv"
Import-Module ActiveDirectory
$US = Get-ADUser -Filter * -Property Enabled |where {$_.Enabled -eq "True"}| FT Name, Enabled -Autosize
$Groups = (Get-AdGroup -filter * | Where {$_.name -like "*RDS Users" -and $_.name -ne "RDS Users"}| select name -expandproperty name)
$Table = #()
$Record = [ordered]#{
"Group Name" = ""
"Name" = ""
"Username" = ""
}
Foreach ($Group in $Groups)
{
$Arrayofmembers = Get-ADGroupMember -identity $Group |select name,samaccountname
foreach ($Member in $Arrayofmembers)
{
$Record."Group Name" = $Group
$Record."Name" = $Member.name
$Record."UserName" = $Member.samaccountname
$objRecord = New-Object PSObject -property $Record
$Table += $objrecord
}
}
if ($Table -eq "RDS Users") {}
$Table
there is usualy a line here that sends the email with excel attachment
The following should produce the output you want in the $Table variable. You can then pipe $Table to one of the format-* commands.
Import-Module ActiveDirectory
$US = Get-ADUser -Filter "Enabled -eq '$true'" -Property Enabled
$Groups = Get-ADGroup -Filter "Name -like '*RDS Users' -and Name -ne 'RDS Users'" |
Select-Object -ExpandProperty Name
$Table = Foreach ($Group in $Groups)
{
try
{
$Arrayofmembers = Get-ADGroupMember -Identity $Group -ErrorAction Stop | Select-Object Name, SamAccountName
$compare = Compare-Object -ReferenceObject $US -DifferenceObject $Arrayofmembers -ExcludeDifferent -IncludeEqual -PassThru -Property SamAccountName -ErrorAction Stop |
Select-Object Name, SamAccountName
$compare | ForEach-Object {
[pscustomobject]#{
"Group Name" = $Group
"Name" = $_.Name
"UserName" = $_.SamAccountName
}
}
}
catch
{
[pscustomobject]#{
"Group Name" = $Group
"Name" = $null
"UserName" = $null
}
Continue
}
}
$Table
Explanation:
The Get-ADGroupMember command will not provide the Enabled property of its returned objects. You will need to feed its output into another command like Get-ADUser for that data. Since you already stored all of the enabled users in $US, we can simply compare $US collection to the results of each Get-ADGroupMember output.
I removed most of the Where-Object commands in favor of using the -Filter parameter on the AD commands. Almost always, the -Filter parameter will be faster especially when you are comparing AD indexed attributes like Name and Enabled.
You do not need to store each output object in a variable unless you are going to further manipulate it. This is why $Record was removed. Instead, all returned objects are stored in the array $Table. I removed the += operator mainly because of its inefficiency when repeatedly building arrays. Also, you can simply set a variable to the output of a foreach loop, which will result in the array you require. Since we created a custom object on each loop iteration and provided the properties at the time of declaration, [ordered] is not required. However, if you create the hash table first and then create a corresponding object, you will potentially need to use [ordered]. As an aside when you are creating custom objects that are involved in a loop, it is usually best practice to create a new object each time. Otherwise, you could unintentionally update values on the wrong objects. Just because you add an object to an array, you can still update its properties after the fact.
The Compare-Object command ties everything together. The -ExcludeDifferent -IncludeEqual parameter combination will only output objects with matching property values. Since we are comparing $Arrayofmembers and $US, that is ideal. The -PassThru switch allows the objects to be returned with all of the properties that were passed into the command. Then you can use the Select-Object command to pick which properties matter to you.

Proxyaddresses added to the multivalued attribute not appearing on seperate lines

I am using the following script to create a spreadsheet of users and proxyaddress values (matching a string) as a record prior to removing them, in the case of an emergency I want to be able to put the values back.
The script works well if there is only a single entry per user, the issue is seen when a user has more than one entry. The problem is that when I attempt to revert back to the original values, when viewed through an attribute editor the proxyaddresses are appearing all on one line instead of a separate line for each proxy address. I am not sure if the fault is on the collection script, or the script I am using to set the values. To collect the values I am running the following:
$entry = "*test.com"
$users = get-content "Testusers.txt"
$date = get-date
$mydata = #()
$domain = [system.environment]::UserDomainName
$attribute = "Proxyaddresses"
$report = "{0}_{1}_{2:HHmm_dd-MM-yyyy}.txt" -f $attribute,$domain,$date
$px = $users | Get-ADUser -Properties proxyaddresses -server $domain
foreach ($user in $px){
if ($user.proxyaddresses -like $entry){
$name = $user.samaccountname
$proxyaddresses = $user.proxyaddresses -like $entry
$mydata += New-Object PSObject -Property #{
Samaccountname = $name
Proxyaddresses = $proxyaddresses
}
}
}
$mydata | select samaccountname,#{ l = "Proxyaddresses"; e = {$_.Proxyaddresses } }| export-csv "$PWD\$report" -NoTypeInformation -Append
To return the values back to the original state I am running the following:
$csv = import-csv "Proxyaddresses_Domain_1201_05-04-2017.csv"
$domain = [system.environment]::UserDomainName
$attribute = "Proxyaddresses"
foreach ($line in $csv){
$user = $line.samaccountname
$proxyaddresses = $line.proxyaddresses
Get-aduser $User -server $domain -Properties $attribute | Set-ADUser -add
#{$attribute = $proxyaddresses} -server $domain
}
I have tried various things such as in the collection script
$proxyaddresses = $line.proxyaddresses -join ","
I have also tried the same tactic in the script used to set the values but instead of creating a new line it removes a space between the entries on the same line when viewed through an AD attribute editor.
I have also tried to change
$proxyaddresses = $user.proxyaddresses -like $entry
to the following however this did not solve the problem
$proxyaddresses = ([Microsoft.ActiveDirectory.Management.ADPropertyValueCollection]$user.proxyaddresses -like $entry
HELP!!!
When you are exporting the data, change your select statement from this
select samaccountname,#{ l = "Proxyaddresses"; e = {$_.Proxyaddresses } }
to this
select samaccountname,#{Name="Proxyaddresses";Expression={$_.proxyaddresses -join "*"}}
Which will convert the ADPropertyValueCollection to a * separated string. If you are exporting to a CSV, you don't want to use a comma as the join separator as it will mess up the CSV. I've used a * in the example, as exchange uses colons and semi colons already.
Then when you re-import it, just make sure to convert the * seperated string back into a string array, and use -replace instead of -add
Set-ADUser -replace #{$attribute = $proxyaddresses.Split("*")} -server $domain

List user details from Username

I am trying to create a script that will check a list of user names and show the user full name and some attribute settings from AD. Basically I have been sent a list of usernames which are just numbers and management want to know the users full name for each username. they also want to know want division they work for.
Below is the script I have created which doesn't work.
$csv = Import-Csv "C:\temp\users.csv"
foreach ($user in $csv) {
$name = $user.myid
Get-ADUser -Filter {EmployeeID -eq $name} -Properties * |
Get-ADUser -Division $user.Programme
} | Export-Csv "C:\Temp\Results.csv"
So I'm working under the assumption that there is a column named myid in your csv file that contains the id you need to be looking up. Assuming that is the case you'll need to make a few changes here. You'll need to remove the second get-aduser as it is not really doing anything for you, and there is no -division switch available to the get-aduser cmdlet, if you need to restrict your results to just a few settings you can do that using the -properties switch and piping to select as shown below. Keep in mind that none of this will matter if the users do not have the "employeeid" and "division" properties set on their AD accounts, which is fairly rare in my experience but if your company does as a matter of policy when creating accounts should be fine. If you replace the get-aduser line in your script with this it should get the account of any user with an EmployeeID property that matches the one in your spreadsheet and then output that person's full name, division, and employeeid to your CSV file.
Get-ADUser -Filter {EmployeeID -eq $name} -Properties "displayname","division","employeeid" | Select-Object "employeeid","displayname","division"
When in doubt, read the documentation. Get-ADUser doesn't have a parameter -Division. You need to select the properties you want in the output file. Also, foreach loops don't pass output into the pipeline. You need a ForEach-Object loop if you want to pass the output directly into Export-Csv:
Import-Csv 'C:\temp\users.csv' |
ForEach-Object {
$name = $_.myid
Get-ADUser -Filter "EmployeeID -eq $name" -Properties *
} |
Select-Object SamAccountName, DisplayName, Division |
Export-Csv 'C:\Temp\Results.csv' -NoType
Otherwise you need to collect the output in a variable:
$users = foreach ($user in $csv) {
$name = $user.myid
Get-ADUser -Filter "EmployeeID -eq $name" -Properties *
}
$users | Export-Csv 'C:\Temp\Results.csv' -NoType
or run the loop in a subexpression:
$(foreach ($user in $csv) {
$name = $user.myid
Get-ADUser -Filter "EmployeeID -eq $name" -Properties *
}) | Export-Csv 'C:\Temp\Results.csv' -NoType
This is a generic code structure that can be adapted for data collection / enumeration and production of CSV files, tailored to your scenario. We use similar at my workplace. It contains some error handling - the last thing you'd want is inaccurate results in your CSV file.
# Create an array from a data source:
$dataArray = import-csv "C:\temp\users.csv"
# Create an array to store results of foreach loop:
$arrayOfHashtables = #()
# Loop the data array, doing additional work to create our custom data for the CSV file:
foreach($item in $dataArray)
{
try
{
$ADObject = Get-ADUser -Filter { EmployeeID -eq $item.MyID } -Properties DisplayName,Division -ErrorAction Stop
}
catch
{
Write-Output "$($item.MyID): Error looking up this ID. Error was $($Error[0].Exception.Message)"
}
if($ADObject)
{
# Create a hashtable to store information about a single item:
$hashTable = [ordered]#{
EmployeeID=$item.myID
DisplayName=$ADObject.DisplayName
}
# Add the hashtable into the results array:
$arrayOfHashtables += (New-Object -TypeName PSObject -Property $hashTable)
}
else
{
Write-Output "$($item.MyID): No result found for this ID."
}
}
# If the results array was populated, export it:
if($arrayOfHashtables.Count -gt 0)
{
$arrayOfHashtables | Export-CSV -Path "C:\Temp\Results.csv" -Confirm:$false -NoTypeInformation
}
As mentioned elsewhere, division isn't a property on an AD object so you might need to lookup this data elsewhere. If you can do that with another line of PowerShell inside your foreach loop, you could add this to your hashtable object like so:
$hashTable = [ordered]#{
EmployeeID=$item.myID
DisplayName=$ADObject.DisplayName
Division=$DivisionFromOtherSource
}