Parsing CSV Data to another CSV based on Samaccountmatch - powershell

I have 2 csv's, 1 from exchange and 1 from AD. I am querying for samaccountname, emailaddress, enabled in AD. I am querying for samaccountname, primarysmtpaddress where recipienttype is 'usermailbox'.
After these are compared it spits out a 3rd csv based on the mismatches it finds. I need to parse the primarysmtpaddress from the exchange csv to the next column and only the addresses based on the samaccountname.
Also, any suggestions are welcome. First time here :)
AD Script
$ErrorActionPreference = 'Continue'
$SamAccountPath = "Path\get_adusers.csv"
$SamAccountPathE = "Path\get_adusers_edit.csv"
$Folder = "Path\mismatch_script"
$logfile = "Path\mismatch_script\get-user.txt"
Try{
if (Test-Path $Folder)
{}
else
{
New-Item -Path "$Folder" -ItemType Directory -Force | Out-Null
}
} Catch {
Write-Output "Could not create log folder" | Out-File $logfile -Append
}
Try
{
Import-Module ActiveDirectory
} Catch {
Write-Output "Could not import ActiveDirectory module." | Out-File $logfile -Append
}
Try{
Get-Aduser -filter * -properties Samaccountname, emailaddress, enabled | ? { $_.enabled -eq $true } | select samaccountname, emailaddress |`
?{$_.emailaddress -ne $null} | Sort-Object samaccountname |`
Export-Csv -Path $SamAccountPath -NoTypeInformation -Force | Out-Null
Get-Content $SamAccountPath | select -Skip 1 | ConvertFrom-Csv -Header 'Samaccountname','primarysmtpaddress' | Export-Csv -Path $SamAccountPathE -NoTypeInformation -Force |Out-Null
Remove-Item $SamAccountPath -Force
} Catch {
Write-Output "Could not get ad users" | Out-File $logfile -Append
}
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -version 2.0 -noexit -command ". 'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1'; Connect-ExchangeServer -auto; Path\get-exuser_information.ps1"
Exchange Script
$AliasPath = "Path\get_exusers.csv"
$SamAccountPath = "Path\get_adusers_edit.csv"
$MismatchPath = "Path\get_diff.csv"
$logfile = "Path\get-user.txt"
$mboxes = get-mailbox -Resultsize Unlimited -identity
$samobj.Samaccountname | Where-Object {$_.recipienttype -eq "UserMailbox"} | select samaccountname, primarysmtpaddress
$ExUserL = Import-Csv $AliasPath
$AdUserL = Import-Csv $SamAccountPath | Where-Object {$_.samaccountname}
$samobj = New-Object PSObject -Property #{ 'Samaccountname' = $_.samaccountname }
$Compare = Compare-Object -ReferenceObject $ExUserL -DifferenceObject
$AdUserL = Import-Csv $SamAccountPath | Where-Object {$_.samaccountname}
Try {
ForEach-Object{
Import-Csv $SamAccountPath | select samaccountname | Out-Null
}
$mboxes | Sort-Object samaccountname | Export-Csv $AliasPath -NoTypeInformation -Force | Out-Null
} Catch {
Write-Output "Could not get mailboxes" | Out-File $logfile -Append
}
Try {
$compare | foreach {
if ($_.sideindicator -eq '<=')
{$_.sideindicator = ''
$_.samaccountname = ''
$_.primarysmtpaddress = ''
}
if ($_.sideindicator -eq '=>')
{$_.sideindicator = "Mismatch"}
}
$compare | Export-Csv $MismatchPath -NoTypeInformation -Force | Out-Null
} Catch {
Write-Output "Could not compare ex and ad csvs" | Out-File $logfile -Append
}
Send-MailMessage -SmtpServer "server" -Attachments $MismatchPath -From "email" -to "email" -Subject "Mismatch Report"
I rewrote it and found this solution:
#Globals for warnings/error action
$WarningPreference = 'SilentlyContinue'
$ErrorActionPreference = 'SilentlyContinue'
#import activedirectory cmdlets
import-module -name activedirectory
#Collects Exchange cmdlets into PSSession and imports it into the current session.
$exchangeuser = "user"
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionURI http://exchange/powershell/ -Authentication kerberos
import-PSSession $session -AllowClobber
#Declare paths
$MismatchPath = "Path\AD_EX_Mismatches.csv"
$MismatchPathE = "Path\AD_EX_MismatchesE.csv"
#Creates empty array
$errorstatus = #()
#Gets all mailboxes that are 'UserMailboxes' and not 'Contacts' it then pipes sam and psmtp to get-aduser. The #{n="";e={}} is creating a table and running an expression or cmdlet.
$gUser = Get-Mailbox -ResultSize Unlimited | Where-Object {$_.recipienttype -eq "UserMailbox"} | select samaccountname, primarysmtpaddress,#{n="ADEmail";e = {Get-ADuser $_.samaccountname -Properties emailaddress | select -ExpandProperty emailaddress}},#{n="Error";e={$errorstatus}}
#Foreach object (Samaccountname,primarysmtpaddress,emailaddress,error). Check if the conditions are met, if so, output the $gUser.Error to the CSV
$gUser | ForEach-Object {
if($_.ADEmail -ne $_.PrimarySmtpAddress){
$_.Error = "Mismatch"
}
if($_.ADEmail -eq ' '){
$_.Error = "Corrupted"
}
}
$gUser | Export-Csv $MismatchPath -NoTypeInformation -Force | Out-Null
#Finds blanks in the csv and re-exports it to a new path.
Import-Csv $MismatchPath | Where-Object {$_.samaccountname -and $_.primarysmtpaddress -and $_.error -notlike ""} | select * | export-csv $MismatchPathE -NoTypeInformation -Force
#Finds EX session and removes it
Get-PSSession | Remove-PSSession
#Send email with args
Send-MailMessage -SmtpServer "mailserver" -Attachments $MismatchPathE -From "emailaddress" -to "email address" -Subject "Mismatch Report" -Body "Attached is a report of mismatches of email addresses between AD and Exchange."

#Globals for warnings/error action
$WarningPreference = 'SilentlyContinue'
$ErrorActionPreference = 'SilentlyContinue'
#import activedirectory cmdlets
import-module -name activedirectory
#Collects Exchange cmdlets into PSSession and imports it into the current session.
$exchangeuser = "user"
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionURI http://EX/powershell/ -Authentication kerberos
import-PSSession $session -AllowClobber
#Declare paths
$MismatchPath = "E:\Utilities\Scripts\Set_DashboardData\Mismatch\1.csv"
$MismatchPathE = "E:\Utilities\Scripts\Set_DashboardData\Mismatch\1E.csv"
$ReportPath = "E:\Reports\Exchange\EXDashboard\"
#Creates empty array
$errorstatus = #()
$Fix = #()
#Gets all mailboxes that are 'UserMailboxes' and not 'Contacts' it then pipes sam and psmtp to get-aduser. The #{n="";e={}} is creating a table and running an expression or cmdlet.
$gUser = Get-Mailbox -ResultSize Unlimited | Where-Object {$_.recipienttype -eq "UserMailbox"} | select samaccountname, primarysmtpaddress,#{n="ADEmail";e = {Get-ADuser $_.samaccountname -Properties emailaddress | select -ExpandProperty emailaddress}},#{n="Error";e={$errorstatus}}
#Foreach object (Samaccountname,primarysmtpaddress,emailaddress,error). Check if the conditions are met, if so, output the $gUser.Error to the CSV
$gUser | ForEach-Object {
if($_.ADEmail -ne $_.PrimarySmtpAddress){
$_.Error = "Mismatch"
}
if($_.ADEmail -eq ' '){
$_.Error = "Corrupted"
}
}
$gUser | Export-Csv $MismatchPath -NoTypeInformation -Force | Out-Null
#Finds blanks in the csv and re-exports it to a new path.
Import-Csv $MismatchPath | Where-Object {$_.samaccountname -and $_.primarysmtpaddress -and $_.error -notlike ""} | export-csv $MismatchPathE -NoTypeInformation -Force
#Deletes original file
Remove-Item $MismatchPath -Force
#Finds EX session and removes it
Get-PSSession | Remove-PSSession

Related

O365 Report Script Enhancements

So, I've created myself a script for generating CSV files from an O365 tenant. It pulls various data sets such as users, groups etc. However when running this script on larger tenants with 10,000+ users it can take some time and I've been made aware I'm using a lot of Disk I/O. Does anyone have any suggestions on how to enhance the speed of this script?
# PS 7.2 Compatible
# Module Installations (required once)
Install-Module MicrosoftTeams
Install-Module ExchangeOnlineManagement
Install-Module Microsoft.Online.SharePoint.PowerShell
# Module Imports (required everytime a new terminal is ran)
Import-Module ExchangeOnlineManagement -UseWindowsPowerShell
Import-Module MicrosoftTeams
Import-Module Microsoft.Online.SharePoint.PowerShell -UseWindowsPowerShell
# Configurable Vars
$tenantName = "M365x51125269"
$OutputFolder = "C:\Users\admin\Documents\Scripts\O365 Reporting\Output"
# Connecting to Services
Connect-MgGraph -Scopes DeviceManagementApps.Read.All, DeviceManagementApps.ReadWrite.All, DeviceManagementManagedDevices.Read.All, DeviceManagementManagedDevices.ReadWrite.All, DeviceManagementServiceConfig.Read.All, DeviceManagementServiceConfig.ReadWrite.All, Directory.Read.All, Directory.ReadWrite.All, User.Read.All, User.ReadBasic.All, User.ReadWrite.All
Connect-ExchangeOnline
Connect-SPOService -Url https://$tenantName-admin.sharepoint.com
# Generate a list of all users with the given properties in a variable
$users = Get-MgUser -Property 'accountEnabled, userPrincipalName, displayName, givenName, surname, department,id' -All
$OneDriveUsage = Get-SPOSite -IncludePersonalSite $true -Limit all -Filter "Url -like '-my.sharepoint.com/personal/'"
$MailboxInfo = Get-EXOMailbox
# Iterate through the variable to pull individual details out
foreach ($user in $users) {
# License
$license = Get-MgUserLicenseDetail -UserId $user.Id
$CurrentOneDrive = $OneDriveUsage| Where-Object{$_.Owner -eq $user.UserPrincipalName}
$CurrentMailboxInfo = $MailboxInfo | Where-Object{$_.PrimarySmtpAddress -eq $user.UserPrincipalName}
$sortedArray = ($CurrentMailboxInfo.EmailAddresses | Select-String '(?<=smtp:)\S+(?!=\S)' -AllMatches).Matches.Value
$stringSMTP = $sortedArray -join ";"
[PSCustomObject]#{
'Enabled Credentials' = $user.AccountEnabled
'Unique ID' = $user.UserPrincipalName
'Display Name' = $user.DisplayName
'Assigned Products' = $license.SkuPartNumber -join " ; "
'First Name' = $user.GivenName
'Last Name' = $user.Surname
'Department' = $user.Department
'Proxy Addresses' = $stringSMTP
'OneDrive Storage Usage (MB)' = $CurrentOneDrive.StorageUsageCurrent
} | Export-Csv -path "$OutputFolder\UserInfo.csv" -Append -NoTypeInformation
}
# Generate list of all sites in a variable
$siteList = Get-SPOSite -Limit ALL
# Iterate through the variable to pull individual details out
foreach($site in $siteList){
# Checking the value result to determine a connection
if ($site.IsTeamsConnected){
$connectionWrite = 'TRUE'
}
else{
$connectionWrite = 'FALSE'
}
# Generate a custom object with our desired properties for export
[PSCustomObject]#{
'Unique ID' = $site.Url
'Display Name' = $site.Title
'Teams Connected' = $connectionWrite
'Sharepoint Storage (MB)' = $site.StorageUsageCurrent
'SharePoint Last Activity Date' = $site.LastContentModifiedDate
} | Export-Csv -path "$OutputFolder\Sites.csv" -Append -NoTypeInformation
}
$teamList = Get-Team
foreach($team in $teamlist){
$teamInfo = $team
$teamReport = Import-CSV "$InputFolder\TeamReport.csv"
$teamDetails = $teamReport | Where-Object{$_."Team Name" -eq $team.DisplayName}
$Sites = Get-SPOSite | Where-Object{$_.Title -eq $team.DisplayName}
[PSCustomObject]#{
'Display Name' = $teamInfo.DisplayName
'Teams Last Activity Date' = $teamDetails."Last Activity Date"
'Sharepoint Storage (MB)' = $Sites.StorageUsageCurrent
} | Export-Csv -path "$OutputFolder\TeamReport.csv" -Append -NoTypeInformation
}
$Groups = Get-MgGroup -Property "Members" -All
foreach($group in $Groups){
if ($group.SecurityEnabled -And -not $group.MailEnabled){
$members = Get-MgGroupMember -GroupId $group.Id
[PSCustomObject]#{
'Display Name' = $group.DisplayName
'Members' = $members.AdditionalProperties.displayName -join ";"
} | Export-Csv -path "$OutputFolder\SecurityGroups.csv" -Append -NoTypeInformation
}
continue
}
$Groups = Get-MgGroup -Property "Members" -All
foreach($group in $Groups){
if ($group.GroupTypes -eq 'Unified'){
$members = Get-MgGroupMember -GroupId $group.Id
[PSCustomObject]#{
'Display Name' = $group.DisplayName
'Members' = $members.AdditionalProperties.displayName -join ";"
} | Export-Csv -path "$OutputFolder\UnifiedGroups.csv" -Append -NoTypeInformation
}
continue
}
$Groups = Get-MgGroup -Property "Members" -All
foreach($group in $Groups){
if ( ( ($group.SecurityEnabled) -and ($group.MailEnabled) ) -and ('Unified' -notin $group.GroupTypes) ){
$members = Get-MgGroupMember -GroupId $group.Id
[PSCustomObject]#{
'Display Name' = $group.DisplayName
'Members' = $members.AdditionalProperties.displayName -join ";"
} | Export-Csv -path "$OutputFolder\MailEnabledSecurityGroups.csv" -Append -NoTypeInformation
}
continue
}
$Groups = Get-MgGroup -Property "Members" -All
foreach($group in $Groups){
if ( (($group.MailEnabled) -and (-not $group.SecurityEnabled)) -and ('Unified' -notin $group.GroupTypes))
{
$members = Get-MgGroupMember -GroupId $group.Id
[PSCustomObject]#{
'Display Name' = $group.DisplayName
'Members' = $members.AdditionalProperties.displayName -join ";"
} | Export-Csv -path "$OutputFolder\DistributionGroups.csv" -Append -NoTypeInformation
}
continue
}
$sharedmailList = Get-EXOMailbox
$filteredList = $sharedmailList | Where-Object {$_.RecipientTypeDetails -notcontains "UserMailbox" -and "DiscoveryMailbox"}
foreach($sharedmail in $filteredList){
if ($sharedmail.RecipientTypeDetails -eq 'DiscoveryMailBox'){
continue
}
else{
[PSCustomObject]#{
'Unique ID' = $sharedmail.PrimarySmtpAddress
'Display Name' = $sharedmail.DisplayName
} | Export-Csv -path "$OutputFolder\SharedMailbox.csv" -Append -NoTypeInformation
}
}
# Disconnect from services to avoid error before finalising script
Disconnect-Graph
Disconnect-ExchangeOnline
Disconnect-SPOService
People are welcome to take this for their own use by the way - I've found it useful for migrations when needing to merge multiple tenancies together but needing input from clients on what they wish to keep or exclude.

Script to remove user profiles using powershell

I'm trying to build a powershell script that I can use to delete all or some of the user profiles on multiple pc's since they often cause the drives to go full.
I found the current script which I got to work for me, but I'd like to optimize it so I can input or import a list of computers where I want him to remove all the user profiles from.
Can you guys help me to input this feature?
Current Code:
$ExcludedUsers ="admin","test"
$RunOnServers = $false
[int]$MaximumProfileAge = 0 # Profiles older than this will be deleted
$osInfo = Get-CimInstance -ClassName Win32_OperatingSystem
if ($RunOnServers -eq $true -or $osInfo.ProductType -eq 1) {
New-EventLog -LogName Application -Source "Stone Profile Cleanup" -ErrorAction SilentlyContinue
$obj = Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special -and $_.Loaded -eq $false )}
#$output = #()
foreach ($littleobj in $obj) {
if (!($ExcludedUsers -like $littleobj.LocalPath.Replace("C:\Users\",""))) {
$lastwritetime = (Get-ChildItem -Path "$($littleobj.localpath)\AppData\Local\Microsoft\Windows\UsrClass.dat" -Force ).LastWriteTime
if ($lastwritetime -lt (Get-Date).AddDays(-$MaximumProfileAge)) {
$littleobj | Remove-WmiObject
# $output += [PSCustomObject]#{
# 'RemovedSID' = $littleobj.SID
# 'LastUseTime' = $litteobj.LastUseTime
# 'LastWriteTime' = $lastwritetime
# 'LocalPath' = $littleobj.LocalPath
# }
}
}
}
#$output | Sort LocalPath | ft
#$output | Sort LocalPath | ft * -AutoSize | Out-String -Width 4096 | Out-File -filepath "C:\MyOutput.TXT" -append -Encoding Unicode
Write-EventLog –LogName Application –Source "Stone Profile Cleanup" –EntryType Information –EventID 1701 -Category 2 -Message ("Profiles older than $MaximumProfileAge days have been cleaned up")
}$ExcludedUsers ="adminbholemans","testbholemans1"
$RunOnServers = $false
[int]$MaximumProfileAge = 0 # Profiles older than this will be deleted
$osInfo = Get-CimInstance -ClassName Win32_OperatingSystem
if ($RunOnServers -eq $true -or $osInfo.ProductType -eq 1) {
New-EventLog -LogName Application -Source "Stone Profile Cleanup" -ErrorAction SilentlyContinue
$obj = Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special -and $_.Loaded -eq $false )}
#$output = #()
foreach ($littleobj in $obj) {
if (!($ExcludedUsers -like $littleobj.LocalPath.Replace("C:\Users\",""))) {
$lastwritetime = (Get-ChildItem -Path "$($littleobj.localpath)\AppData\Local\Microsoft\Windows\UsrClass.dat" -Force ).LastWriteTime
if ($lastwritetime -lt (Get-Date).AddDays(-$MaximumProfileAge)) {
$littleobj | Remove-WmiObject
# $output += [PSCustomObject]#{
# 'RemovedSID' = $littleobj.SID
# 'LastUseTime' = $litteobj.LastUseTime
# 'LastWriteTime' = $lastwritetime
# 'LocalPath' = $littleobj.LocalPath
# }
}
}
}
#$output | Sort LocalPath | ft
#$output | Sort LocalPath | ft * -AutoSize | Out-String -Width 4096 | Out-File -filepath "C:\MyOutput.TXT" -append -Encoding Unicode
Write-EventLog –LogName Application –Source "Stone Profile Cleanup" –EntryType Information –EventID 1701 -Category 2 -Message ("Profiles older than $MaximumProfileAge days have been cleaned up")
}
I found this piece of code for the computer input but I'm not sure how I can implement it properly.
Get-CimInstance -ComputerName SRV1,SRV2,SRV3 -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('\')[-1] -eq 'UserA' } | Remove-CimInstance
Thanks for the help everyone.
Get-CimInstance -ComputerName SRV1,SRV2,SRV3 -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('')[-1] -eq 'UserA' } | Remove-CimInstance
Do u test it before? Work OK?

Output running services to csv with computer name

I need to generate a csv containing running services to csv with the corresponding computer name
I know there is a simple way to do this and I have been tinkering with creating a new psobject, but I am not sure how to pipe the results to the new-object...
Here is what I am using:
$Input = "SomePath"
$Output = "SomeOtherPath"
$CompNames = Get-Content -Path "$Input"
ForEach ($CompName in $CompNames){
Get-Service -ComputerName $CompName | Where-Object {$_.Status -eq "Running"} | Export-csv -Path "$Output"
}
What I need in the CSV is:
ComputerName, ServiceName, DisplayName
basically, I need to add the computer name to the array.
If you want to be able to pipe the results, use a foreach-object.
$Output = "SomeOtherPath"
Get-Content -Path "SomePath" | ForEach-Object {
Get-Service -ComputerName $_ | Where-Object {$_.Status -eq "Running"} | Select-Object ComputerName, ServiceName, DisplayName
} | Export-csv -Path "$Output"
If you want to stick to a foreach statement, collect it all first then export it.
$Output = "SomeOtherPath"
$CompNames = Get-Content -Path "SomePath"
$results = ForEach ($CompName in $CompNames){
Get-Service -ComputerName $CompName | Where-Object {$_.Status -eq "Running"} | Select-Object ComputerName, ServiceName, DisplayName
}
$results | Export-csv -Path "$Output"
Try like this (Don't use $Input as variable name)
$InputX = "SomePath"
$Output = "SomeOtherPath"
$CompNames = Get-Content -Path "$Input"
ForEach ($CompName in $CompNames){
Get-Service -ComputerName $CompName | Where-Object {$_.Status -eq "Running"} | Select-Object ComputerName, ServiceName, DisplayName | Export-csv -Path "$Output"
}

Out-File unnecessary characters

I have the script below which pings a list of machines, outputs the result to CSV and gets the lastlogontimestamp of the machine.
It works fine, except the lastlogontimestamp comes out like this:
CCC-APP01,172.22.100.15,#{lastLogonDate=07/25/2018 13:24:54}
How can I get rid of the extra characters: #{lastlogondate=...}?
$OutputCSV = "C:\TEMP\OUPingResults.csv"
$SearchLocation = "OU=AA,OU=Servers,DC=LocA,DC=XYZ,DC=com"
$Computers = Get-ADComputer -Filter * -SearchBase $SearchLocation |
Select Name |
Sort-Object Name
$Computers = $Computers.Name
$Headers = "ComputerName,IP Address,LastLogonTimeStamp"
$Headers | Out-File -FilePath $OutputCSV -Encoding UTF8
foreach ($computer in $Computers) {
Write-host "Pinging $Computer"
$Test = Test-Connection -ComputerName $computer -Count 1 -ErrorAction SilentlyContinue -ErrorVariable Err
if ($test -ne $null) {
$IP = $Test.IPV4Address.IPAddressToString
$LastLogonTimeStamp = Get-ADComputer $Computer -Prop CN,lastLogonTimestamp |
Select #{n="lastLogonDate";e={[datetime]::FromFileTime($_.lastLogonTimestamp)}}
$Output = "$Computer,$IP,$LastLogonTimeStamp"
$Output | Out-File -FilePath $OutputCSV -Encoding UTF8 -Append
} else {
$Output = "$Computer,$Err"
$Output | Out-File -FilePath $OutputCSV -Encoding UTF8 -Append
}
}
The expression ... |Select-Object #{N='SomeName';E={"SomeValue"}} will produce an object that has a property named SomeName with the value "SomeValue".
What you see in the output is a string representation of this object.
If you want only the value, change the $LastLogonTimeStamp assignment to:
$LastLogonTimeStamp = [datetime]::FromFiletime((Get-ADComputer $Computer -Prop lastLogonTimestamp).lastLogonTimestamp)

Get group member names from Get-Acl and Append to CSV

I need to extract all the members of a group and then format that into Names, so I only get the Full Names like "Don Joe" is member of my-domain\UNCShareDrive
I need that to appear in my CSV after I have exported the ACL lists.
As an example:
Path FileSystemRights AccessControlType IdentityReference
---- ---------------- ----------------- -----------------
Microsoft.PowerShell.Core\FileSystem::\\fileshare\management\DK FullControl Allow MY-DOMAIN\Drev Management
Microsoft.PowerShell.Core\FileSystem::\\fileshare\management\ FullControl Allow BUILTIN\Administratorer
Microsoft.PowerShell.Core\FileSystem::\\fileshare\management\ FullControl Allow MY-DOMAIN\Drev Management
Microsoft.PowerShell.Core\FileSystem::\\fileshare\management\ FullControl Allow BUILTIN\Administratorer
**These persons has access to the drive:**
**Finding group: MY-DOMAIN\Administrators**
Name SamAccountName Mail
---- -------------- ----
Administrator Administrator Administrator#my-domain.dk
This is what I have so far done in Powershell:
$Searching = Get-ADGroup -Filter * -SearchBase "DC=my-domain,DC=local"
$mypath = "U:\mytest.csv"
if((Test-Path -Path "U:\mytest.csv" -pathtype Container) -eq $True){
Write-Host -ForegroundColor red "We found a file: $mypath --> REMOVING!`r`n"
Remove-Item $mypath -Force
}
$ShareName = "\\\sharename\D$"
$shares = Get-Childitem -path $ShareName |
Where-Object {$_.PSIsContainer} |
Get-ACL |
Select-Object Path -ExpandProperty Access |
Select Path, FileSystemRights,AccessControlType,IdentityReference |
export-csv $mypath -Delimiter ';' -NoTypeInformation -Encoding UTF8
$foldertotal = 0
Add-Content $mypath ""
Add-Content $mypath ""
Add-Content $mypath "Disse personer har adgang til share navnet"
Add-Content $mypath ""
Add-Content $mypath ""
$myLoop = ''
foreach ($testLoop in $myLoop) {
$Group = Get-ADGroup -Filter * -SearchBase "DC=my-domain,DC=local" -Properties IdentityReference |
Select-Object Name # Need only groups in $Shares - who are displayed
$myLoop += Write-Host -ForegroundColor Yellow "Finding group: $($Group.name).....`n"
$myLoop += ForEach ($Group in $share) {
Get-ADGroupMember -identity $($Group.name) -recursive |
Get-ADUser -Properties Name,SamAccountName,Mail |
Select-Object Name,SamAccountName,Mail
}
$testLoop | Out-File -filePath $mypath -append -encoding utf8
}
Write-Host -ForegroundColor Cyan "$($Group.name) is now exported to: $mypath`n"
I have also a hard time to filter out only the share path:
$shares.Replace('Microsoft.PowerShell.Core\FileSystem::', ' ') |
Out-File -filePath $mypath -append -encoding utf8
How come that this thing Works when I use User Input and not just automatically loop through it without the console prompt:
$Searching = Get-ADGroup -Filter * -SearchBase "DC=MY-DOMAIN,DC=local"
$mypath = "U:\mytest.csv"
$networkPath = "\\ShareName\D$"
$acl = Get-acl -path $networkPath
if((Test-Path -Path "U:\mytest.csv" -pathtype Container) -eq $True){
Write-Host -ForegroundColor red "We found a file: $mypath --> REMOVING!`r`n"
Remove-Item $mypath -Force
}
Write-Host -ForegroundColor Yellow "Eksempel på share: "`r`n\\ShareName\D$`r`n\\ShareTwo\\E$`r`n\\ShareName\management`r`n""
$ShareName = Read-host "Hvilket sharenavn vil du finde Access Control List fra?"
if($ShareName -eq "1"){
$Sharename = "\\ShareName\D$"
}
if($ShareName -eq "2"){
$Sharename = "\\ShareTwo\\E$"
}
if($ShareName -eq "3"){
$Sharename = "\\ShareName\management"
}
Get-Childitem -path $ShareName |
Where-Object {$_.PSIsContainer} |
Get-ACL |
Select-Object Path -ExpandProperty Access |
Select Path, FileSystemRights,AccessControlType,IdentityReference |
FT -AutoSize |
Out-File -Encoding utf8 $mypath
Add-Content $mypath ""
Add-Content $mypath ""
Add-Content $mypath "Disse personer har adgang til share navnet"
Add-Content $mypath ""
$users = get-aduser -Filter {Name -Like "*"} -Searchbase "dc=MY-DOMAIN,dc=local" -Properties MemberOf |
Where-Object { $_.Enabled -eq 'True' }
Write-Host -ForegroundColor red "Example: Drev Management`r`n"
$myGroups = Read-Host "Hvilken Gruppe vil du bruge?"
if($myGroups -eq "1"){
$myGroups = " Drev Management"
}
$Groups = Get-ADGroup -filter {Name -like $myGroups} | Select-Object Name
Add-Content $mypath "Finding group: $($group.name)"
Write-Host -ForegroundColor Yellow "Finding group: $($Group.name).....`n"
Add-Content -Path $mypath $result
ForEach ($Group in $Groups) {
Get-ADGroupMember -identity $($Group.name) -recursive |
Get-ADUser -Properties Name,SamAccountName,Mail |
Select-Object Name,SamAccountName,Mail |
FT -AutoSize |
Out-File -Append -encoding utf8 $mypath
}
Write-Host -ForegroundColor Cyan "$($Group.name) is now exported to: $mypath`n"
Your second code sample works, because it doesn't make the same mistakes as the first one.
$myLoop = ''
foreach ($testLoop in $myLoop) {
$Group = Get-ADGroup -Filter * ...
$myLoop += Write-Host ...
$myLoop += ForEach ($Group in $share) {
Get-ADGroupMember ...
}
$testLoop | Out-File -filePath $mypath -append -encoding utf8
}
You make $myLoop an empty string, then iterate over each element of $myLoop (one empty string), so you get a single loop cycle, no matter what you append to $myLoop inside the loop.
Instead of the group members you write the content of $testLoop (an empty string) to the output file.
You read AD groups into the variable $Group, and then overwrite its content when you use $Group as the loop variable in foreach ($Group in $share).
$share is emtpy, because it's never initialized anywhere. Even $shares is empty, because when you write the ACL information to the CSV, no output is left that could be assigned to the variable.
And as a side-note: you can't append Write-Host output to anything, because the cmdlet writes to the host process (i.e. the console), not a stream that could be captured or redirected.
You need to capture the ACL information in $shares before writing it to a file:
$shares = Get-Childitem -Path $ShareName |
Where-Object {$_.PSIsContainer} |
Get-ACL |
Select-Object Path -ExpandProperty Access |
Select Path, FileSystemRights,AccessControlType,IdentityReference
$shares | Export-Csv $mypath -Delimiter ';' -NoTypeInformation -Encoding UTF8
Then you can determine the members of the groups having access to shares like this:
$shares | Select-Object -Expand IdentityReference |
Select-Object -Expand Value |
ForEach-Object {
$name = $_ -replace '^DOMAIN\\' # <-- replace with actual domain name
Get-ADObject -Filter { Name -eq $name }
} |
Where-Object { $_.ObjectClass -eq 'group' } |
Get-ADGroupMember |
Get-ADUser -Properties * |
Select-Object Name, SamAccountName, Mail |
Out-File $mypath -Append -Encoding UTF8
Note that this will not resolve nested groups, and also won't distinguish between shares.
If you want to store both the group name and its members you need to add a loop to the pipeline:
$shares | Select-Object -Expand IdentityReference |
Select-Object -Expand Value |
ForEach-Object {
$name = $_ -replace '^DOMAIN\\' # <-- replace with actual domain name
Get-ADObject -Filter { Name -eq $name }
} |
Where-Object { $_.ObjectClass -eq 'group' } |
ForEach-Object {
$_
Get-ADGroupMember -Identity $_ |
Get-ADUser -Properties * |
Select-Object Name, SamAccountName, Mail
} |
Out-File $mypath -Append -Encoding UTF8