I have the following PowerShell code that should run and fetch the last login for the list of UPNs:
$UPNList = get-content c:\temp\users.txt
foreach ($User in $UPNList)
{
Start-Sleep -Milliseconds 1000
$result = Get-AzureADAuditSignInLogs -Filter "UserPrincipalName eq '$User'" -Top 1 | Select-Object CreatedDateTime, UserPrincipalName, IsInteractive, AppDisplayName, IpAddress, TokenIssuerType, #{Name = 'DeviceOS'; Expression = {$_.DeviceDetail.OperatingSystem}}
$result | Export-Csv -Path 'c:\temp\results.txt' -NoTypeInformation -Append
}
However, the "results.txt" file is empty when there is more than one (1) user in the input file.
If there's a single user, results are correctly returned.
How can I ensure the results are provided for all users?
Also, if the user did not log in at all, for example completely new account, how do I ensure that the UPN is still populated in the "results" file, but the rest of the details are empty?
Thank you.
Try not to write out to the output file in every iteration, but have PowerShell collect the objects you output inside the loop and then create the csv file:
# get the list of UPN's and skip empty lines
$UPNList = Get-Content -Path 'c:\test\users.txt' | Where-Object { $_ -match '\S' }
# loop through the list and collect the data in variable $result
$result = foreach ($User in $UPNList) {
# output the wanted data
Get-AzureADAuditSignInLogs -Filter "UserPrincipalName eq '$User'" -Top 1 |
Select-Object CreatedDateTime, UserPrincipalName, IsInteractive, AppDisplayName, IpAddress,
TokenIssuerType, #{Name = 'DeviceOS'; Expression = {$_.DeviceDetail.OperatingSystem}}
}
# now write the collected data to CSV file in one go
$result | Export-Csv -Path 'c:\test\results.csv' -NoTypeInformation
You may also try to do the filtering afterwards like below (could be slower than above code though)
# get the list of UPN's and skip empty lines
$UPNList = Get-Content -Path 'c:\test\users.txt' | Where-Object { $_ -match '\S' }
# filter with Where-Object afterwards and pipe through to the Export-Csv cmdlet
Get-AzureADAuditSignInLogs -All $true | Where-Object { $UPNList -contains $_.UserPrincipalName } |
Select-Object CreatedDateTime, UserPrincipalName, IsInteractive, AppDisplayName, IpAddress,
TokenIssuerType, #{Name = 'DeviceOS'; Expression = {$_.DeviceDetail.OperatingSystem}} |
Export-Csv -Path 'c:\test\results.csv' -NoTypeInformation
I tried to reproduce the same in my environment and got below results:
Initially, I checked with one user in users.txt file like this:
I ran the same script as you and got the response like below:
$UPNList = get-content c:\test\users.txt
foreach ($User in $UPNList)
{
Start-Sleep -Milliseconds 1000
$result = Get-AzureADAuditSignInLogs -Filter "UserPrincipalName eq '$User'" -Top 1 | Select-Object CreatedDateTime, UserPrincipalName, IsInteractive, AppDisplayName, IpAddress, TokenIssuerType, #{Name = 'DeviceOS'; Expression = {$_.DeviceDetail.OperatingSystem}}
$result | Export-Csv -Path 'c:\test\results.txt' -NoTypeInformation -Append
}
Output:
In results.txt file, I got the details of that user successfully like below:
Now I tried including more UPNs in users.txt file like below:
When I ran the same script, the results.txt file is empty as below:
Please note that, the response in results.txt file differs based on how you are giving input in users.txt file.
I tried changing the format of giving input in users.txt file like below:
Now, when I ran the script again, I got the details of those users successfully like below:
So, make sure to give input for users.txt file in correct format.
If the user did not log in at all, it's not possible to get their details using Get-AzureADAuditSignInLogs command.
Normally, you can make use of Get-AzureADUser command to get any user details.
Related
I have a fairly simple script that needs to check around 20,000 AD Groups for their membership count. That all works fine, I can take the list of groups run it through the script and for the most entries it works fine. However I was getting some errors that I couldn't figure out and hopefully someone here can point me in the right direction.
I am using the DN of the object to query AD and for around 10% it fails, but when I copy the DN from the file, paste it into a command window and run the command manually it works fine. Some more checking and it seems that when I read an offending line into my variable there is a line break in the middle for some reason.
When looking at the value of the variable I get the following:
Working Example - "CN=ABC, OU=Location, OU=Distribution Lists, DC=Domain, DC=COM"
Error Example - "CN=ABC, OU=Location, OU=Distribution
Lists, DC=Domain, DC=COM"
It seems to insert a return in-between Distribution and Lists on certain entries in the file. I have tried deleting the character in-between and replacing it with a space but I get the same result.
Could it be the length? I am still looking for a common factor but any suggestions would be great.
Thanks
Updated with requested content.
$Groups = Import-Csv C:\Temp\DLName.csv
write-host ($Groups).Count
$i=1
foreach ($Group in $Groups)
{
$GroupInfo = Get-ADGroupMembersRecursive -Groups $Group.Name
$MembersCount = ($GroupInfo | Measure-Object).Count
$MembersList = $GroupInfo | Select Name -ExcludeProperty Name
$FriendlyName = Get-ADGroup -Identity $Group.Name
$Export = $FriendlyName.Name + ", " + $MembersCount
$Export | Out-File C:\Temp\DLMembers.csv -Append
Write-host $FriendlyName "," $MembersCount
$i
$i++
}
Entry 1 and 3 work 2 doesn't, but the formatting here seems to have wrapped the entries.
Name
"CN=Company - DL Name1,OU=Country1 Distribution Lists,OU=Europe,OU=Acc,DC=Domain,DC=Domain,DC=com"
"CN=Company - DL Name2,OU=Country2 Distribution Lists,OU=Europe,OU=Acc,DC=Domain,DC=Domain,DC=com"
"CN=Company - DL Name3,OU=Country3 Distribution Lists,OU=America,OU=Acc,DC=Domain,DC=Domain,DC=com"
Top pic is the failure second pic works.
List Creation:
$SearchScope = "OU=OUName,DC=Domain,DC=Domain,DC=com"
$SearchFilter = {GroupCategory -eq 'Distribution'}
$Groups = Get-ADGroup -SearchBase $SearchScope -Filter
$SearchFilter | Sort-Object Name
foreach ($Group in $Groups)
{
$Group.DistinguishedName | Select Name -ExpandProperty Name
$Group.DistinguishedName | Out-File C:\Temp\DLName.csv -Append
}
Do not use a self-combined comma separated string and Out-File to create CSV files, because that will get you into trouble when fields happen to contain the delimiter character like in this case the comma (which will lead to mis-aligned data).
Your List Creation code should be like this:
$SearchBase = "OU=OUName,DC=Domain,DC=Domain,DC=com"
$SearchFilter = "GroupCategory -eq 'Distribution'"
Get-ADGroup -SearchBase $SearchBase -Filter $SearchFilter |
Sort-Object Name | Select-Object Name, DistinguishedName |
Export-Csv -Path 'C:\Temp\DLName.csv' -NoTypeInformation
Then you can use that csv later to do:
$Groups = Import-Csv -Path 'C:\Temp\DLName.csv'
Write-Host $Groups.Count
$result = foreach ($Group in $Groups) {
$GroupInfo = Get-ADGroupMember -Identity $Group.DistinguishedName -Recursive
# unnecessary.. $MembersCount = ($GroupInfo | Measure-Object).Count
# unused.. $MembersList = $GroupInfo.Name
# unnecessary.. $FriendlyName = Get-ADGroup -Identity $Group.Name
# output an object with the wanted properties
[PsCustomObject]#{
GroupName = $Group.Name
MemberCount = #($GroupInfo).Count # #() in case there is only one member in the group
}
}
# show on screen
$result | Format-Table -AutoSize
# output to CSV file
$result | Export-Csv -Path 'C:\Temp\DLMembers.csv' -NoTypeInformation
As you can see, I'm not using your custom function Get-ADGroupMembersRecursive because I have no idea what that outputs.. Also, there is no need for that because you can use the Get-ADGroupMember cmdlet with the -Recursive switch added
I've tried lots of different combinations at this point and I'm coming up dry. I have a CSV file that contains usernames (Users) of people in the format of 117321, which refers to their login name. I'm trying to get the homedirectory path of all these users and export them to a CSV. Here's what I have so far, but it doesn't seem to work. I've even tried filter.
$InputFile = 'C:\Users.csv'
$Users = Import-CSV $InputFile
$OutputFile = 'C:\Directory Results.csv'
$HomeDirOutput = ForEach ($User in $Users) {
Get-ADUser -LDAPFilter "(sAMAccountName=$user)" -Properties homedirectory
}
$HomeDirOutput | Export-Csv $OutputFile -NoTypeInformation
All I'm getting is a blank spreadsheet.
sAMAccountName is a valid value to pass to the -Identity parameter of Get-ADUser. Assuming that the CSV contains a column "AccountName", you should be able to do
Import-CSV -Path $InputFile | ForEach-Object { Get-ADUser -Identity $_.AccountName -Property sAMAccountName,HomeDirectory } | SelectObject -Property sAMAccountName,HomeDirectory | Export-CSV -NoTypeInformation -Path $OutputFile -Append
(after making sure that the output file doesn't already exist).
I am trying to complete a powershell script to automate account termination. I wanted to first capture some user information and write it to a csv before I then disable the account and remove all groups. I can easily run the script in individual parts, but when I create a loop it only works on one account in my text file. I am not to familiar with using objects but was told that I should learn and utilize them.
I have already tried to run the code without the desired results. The below code only has the capture part as I need to figure out how to include the rest as well.
$user_name = Get-Content -Path 'C:\Users\username\Documents\AD Test Files\*.txt'
foreach ($user in $user_name){
$users = Get-ADUser $user -Properties samaccountname,givenname,surname
$groups = Get-ADPrincipalGroupMembership $users | Select -Expand Name
$data = [PSCustomObject]#{
samaccountname = $users.samaccountname;
givenname = $users.givenname;
surname = $users.surname;
memberOf = ($groups | Out-String).Trim()
}
}
$data | Export-Csv C:\Users\username\Desktop\Term.csv -Delimiter "," -NoTypeInformation -Encoding UTF8
Right now you're overriding $data each iteration of the loop, which could explain why it's only outputting one account. Instead, you could make it an array and add to it in each iteration (notice the += in the loop):
...
$data = #()
foreach ($user in $user_name){
...
$data += [PSCustomObject]#{
...
}
}
$data | Export-Csv ...
It's a very simple solution if you want to get back data from a foreach.:
$all = foreach{}
$all | Export-Csv C:\Users\username\Desktop\Term.csv -Delimiter "," -NoTypeInformation -Encoding UTF8
I have this script that reads samaccountnames from a file and outputs the name of the user with its membership information. However, the output file only shows the last record. It seems that my code is overwriting the previous record. What am I missing? Thank you so much.
ForEach ($user in $(Get-Content -Path C:\MyScripts\UsersInput.csv))
{
$username = Get-ADUser –Identity $user -Properties *
Get-ADPrincipalGroupMembership $user | select $username.DisplayName, name |
export-csv "C:\MyScripts\UsersAndTheirADGroups.csv" -NoTypeInformation
}
Export-Csv has an -append parameter, so you could use that. ie it would append to the csv file with every iteration of the loop. You would need to make sure the file didn't exist before you start the loop or it would just get bigger and bigger each time you ran the code.
Another way it to add the items to an object and then export that at the end. ie $username += Get-ADUser......
You are reading a CSV file using Get-Content. This lets me think the file is simply a list of user SamAccountNames, each on a separate line. No headings.
Something like this perhaps:
jdoe
jsmith
If that is the case, read the input file like this:
$users = Get-Content -Path 'C:\MyScripts\UsersInput.csv'
To get an array of user SAMAccountnames.
If however it is a proper CSV file with headers, looking something like this:
"SamAccountName","Email","More","Stuff"
"jdoe","john.doe#yourdomain.com","blah","blah"
"jsmith","jane.smith#yourdomain.com","blah","blah"
Then you should use the Import-Csv cmdlet to get the entries as objects and obtain an array of SamAccountNames from that:
$users = Import-Csv -Path 'C:\MyScripts\UsersInput.csv' | Select-Object -ExpandProperty SamAccountName
Once you have that array, loop through it and get the group membership info for each user
Untested
$result = foreach ($accountName in $users) {
Get-ADUser –Identity $accountName -Properties DistinguishedName, DisplayName |
Select-Object #{Name = 'User'; Expression = {$_.DisplayName}},
#{Name = 'Groups'; Expression = { ( $_ | Get-ADPrincipalGroupMembership | Select-Object -ExpandProperty name) -join ', '}}
}
$result | Export-Csv "C:\MyScripts\UsersAndTheirADGroups.csv" -NoTypeInformation
You are indeed overwriting the code ForEach user. You included Export-Csv in the ForEach. Instead export the whole array that ForEach creates:
ForEach ($user in $(Get-Content -Path C:\MyScripts\UsersInput.csv))
{
$username = Get-ADUser –Identity $user -Properties *
Get-ADPrincipalGroupMembership $user | select $username.DisplayName, name
} | export-csv "C:\MyScripts\UsersAndTheirADGroups.csv" -NoTypeInformation
I have a PowerShell script below
$ous = 'ou=office,dc=xxx,dc=com',`
'ou=shop0,dc=xxx,dc=com',`
'ou=shop1,dc=xxx,dc=com',`
'ou=shop2,dc=xxx,dc=com'
$outfile = 'c:\work\userinfo.csv'
New-Item -Force -type "file" -Path 'c:\work\userinfo.csv'
$ous | ForEach {
Get-ADUser -Filter * -SearchBase $_ |
Select-Object -Property CN,`
DisplayName,`
GivenName,`
Surname,`
SamAccountName,`
PasswordExpired,`
mail,`
Description,`
Office,`
EmployeeNumber,`
Title |
Sort-Object -Property Name |
export-csv -Append $outfile -NoTypeInformation
}
Then when I run it, I got error message "New-Item: access to the path c:\work\userinfo.csv" is denied.
What's the cause for this error?
Update:
In my case, somehow, PowerShell is case-sensitive....the output folder name is uppercase, in my script is lowercase, it works after I match them.
I am bypassing the reason for the error ( of which I'm not sure of the cause.). Another way to get what you want
each time I run script, I could get an fresh result without previous results
You just need to move the output code outside the loop and remove the append. Pipeline handles the Append for you.
$ous | ForEach {
Get-ADUser -Filter * -SearchBase $_ |
Select-Object -Property CN,`
DisplayName,`
GivenName,`
Surname,`
SamAccountName,`
PasswordExpired,`
mail,`
Description,`
Office,`
EmployeeNumber,`
Title
} | Sort-Object -Property Name |
export-csv -Append $outfile -NoTypeInformation
Noticed something
You are not calling all the properties you are using in your select statement. That should lead to some null columns in your output. I would update your code to something like this.
$props = "CN","DisplayName","GivenName","Surname","SamAccountName","PasswordExpired","mail","Description","Office","EmployeeNumber","Title"
$ous | ForEach-Object {
Get-ADUser -Filter * -SearchBase $_ -Properties $props | Select-Object $props
} | Sort-Object -Property Name |
export-csv $outfile -NoTypeInformation