From 96b62b201109b6929c16b4f58e8dd8d1774d6ff1 Mon Sep 17 00:00:00 2001 From: Vasil Michev <38553333+michevnew@users.noreply.github.com> Date: Sat, 22 Jul 2023 11:57:30 +0300 Subject: [PATCH] Replace with BOM-less files --- AADRolesInventory-Graph.ps1 | 2 +- AADRolesInventory-MG.ps1 | 2 +- AADRolesInventory.ps1 | 4 +- AAD_Groups_MemberOf_inventory.ps1 | 2 +- AAD_Groups_MemberOf_inventoryMG.ps1 | 2 +- AAD_Groups_Members_inventory.ps1 | 2 +- AAD_Groups_Members_inventoryMG.ps1 | 2 +- AU_memberOf_inventory.ps1 | 2 +- Calendar_Permissions_inventory.ps1 | 4 +- Calendar_Permissions_inventoryV2.ps1 | 2 +- DG_MemberOf_inventory.ps1 | 4 +- DG_MemberOf_inventoryV2.ps1 | 2 +- DG_members_recursive.ps1 | 2 +- DG_members_recursiveV2.ps1 | 2 +- GraphSDK_Bulk_change_service.ps1 | 2 +- Graph_Bulk_change_service.ps1 | 2 +- Graph_CA_report.ps1 | 2 +- Graph_Devices_MemberOf.ps1 | 2 +- Graph_Flow_report.ps1 | 2 +- Graph_Last_Login_Date.ps1 | 65 +-- Graph_ODFB_remove_all_shared.ps1 | 2 +- Graph_ODFB_shared_files.ps1 | 6 +- Graph_Remove_all_licenses.ps1 | 4 +- Graph_Teams_channel_SMTP.ps1 | 2 +- Groups_Owner_Inventory.ps1 | 2 +- Groups_Owner_InventoryV2.ps1 | 2 +- Mailbox_Folder_Permissions_inventory.ps1 | 153 +++---- Mailbox_Folder_Permissions_inventoryV2.ps1 | 2 +- Mailbox_Forwarding_inventory.ps1 | 2 +- Mailbox_Forwarding_inventoryV2.ps1 | 2 +- Mailbox_Permissions_inventory.ps1 | 4 +- Mailbox_Permissions_inventoryV2.ps1 | 2 +- Mailbox_Permissions_inventory_SOB.ps1 | 2 +- Mailbox_Permissions_inventory_SOB_V2.ps1 | 2 +- Mobile_devices_inventory.ps1 | 4 +- Mobile_devices_inventoryV2.ps1 | 2 +- O365_Groups_links_report.ps1 | 2 +- O365_Groups_links_reportV2.ps1 | 2 +- O365_aliases_inventory.ps1 | 2 +- O365_aliases_inventoryV2.ps1 | 2 +- OU_report.ps1 | 2 +- OU_reportV2.ps1 | 2 +- OwnerlessGroupPolicy.ps1 | 2 +- Remove_Folder_Permissions_recursive_BULK.ps1 | 396 +++++++++---------- Remove_User_All_Groups.ps1 | 8 +- Remove_User_All_GroupsV2.ps1 | 7 +- Remove_User_MBpermissions.ps1 | 2 +- Report_Team_Sites.ps1 | 2 +- Report_Teams_Apps.ps1 | 6 +- Reset_Folder_Permissions_recursive_BULK.ps1 | 2 +- Role_assignments_Inventory.ps1 | 4 +- Set_Folder_Permissions_recursive_BULK.ps1 | 39 +- app_Permissions_inventory_GraphAPI.ps1 | 2 +- app_reg_Permissions_inventory_GraphAPI.ps1 | 2 +- 54 files changed, 379 insertions(+), 407 deletions(-) diff --git a/AADRolesInventory-Graph.ps1 b/AADRolesInventory-Graph.ps1 index 13db769..7d02e90 100644 --- a/AADRolesInventory-Graph.ps1 +++ b/AADRolesInventory-Graph.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 [CmdletBinding(SupportsShouldProcess)] #Make sure we can use -WhatIf and -Verbose Param([switch]$IncludePIMEligibleAssignments) #Indicate whether to include PIM elibigle role assignments in the output. NOTE: Currently the RoleManagement.Read.Directory application permissions seems to be required! diff --git a/AADRolesInventory-MG.ps1 b/AADRolesInventory-MG.ps1 index e2d946e..1057acb 100644 --- a/AADRolesInventory-MG.ps1 +++ b/AADRolesInventory-MG.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 [CmdletBinding(SupportsShouldProcess)] #Make sure we can use -WhatIf and -Verbose Param([switch]$IncludePIMEligibleAssignments) #Indicate whether to include PIM elibigle role assignments in the output. NOTE: Currently the RoleManagement.Read.Directory scope seems to be required! diff --git a/AADRolesInventory.ps1 b/AADRolesInventory.ps1 index 8601f81..d5b6f57 100644 --- a/AADRolesInventory.ps1 +++ b/AADRolesInventory.ps1 @@ -1,4 +1,4 @@ -#Do a check for the AzureAD module +#Do a check for the AzureAD module if (!(Get-Module AzureAD -ListAvailable)) { Write-Host -BackgroundColor Red "This script requires a recent version of the AzureAD PowerShell module. Download it here: https://www.powershellgallery.com/packages/AzureAD/"; return } #Do a connectivity check @@ -31,4 +31,4 @@ foreach ($AADRole in $AADRoles) { #format and export $report = foreach ($key in ($RolesHash.Keys)) { $RolesHash[$key] | % { [PSCustomObject]$_ } } -$report | sort DisplayName #| Export-CSV -nti -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_AzureADRoleInventory.csv" \ No newline at end of file +$report | sort DisplayName | Export-CSV -nti -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_AzureADRoleInventory.csv" \ No newline at end of file diff --git a/AAD_Groups_MemberOf_inventory.ps1 b/AAD_Groups_MemberOf_inventory.ps1 index f481836..1c175e2 100644 --- a/AAD_Groups_MemberOf_inventory.ps1 +++ b/AAD_Groups_MemberOf_inventory.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Make sure to fill in all the required variables before running the script #Also make sure the AppID used corresponds to an app with sufficient permissions, as follows: # Directory.Read.All diff --git a/AAD_Groups_MemberOf_inventoryMG.ps1 b/AAD_Groups_MemberOf_inventoryMG.ps1 index 2f4e894..2288e13 100644 --- a/AAD_Groups_MemberOf_inventoryMG.ps1 +++ b/AAD_Groups_MemberOf_inventoryMG.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Make sure to fill in all the required variables before running the script #Also make sure the AppID used corresponds to an app with sufficient permissions, as follows: # Directory.Read.All diff --git a/AAD_Groups_Members_inventory.ps1 b/AAD_Groups_Members_inventory.ps1 index e279a52..72d72c9 100644 --- a/AAD_Groups_Members_inventory.ps1 +++ b/AAD_Groups_Members_inventory.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Make sure to fill in all the required variables before running the script #Also make sure the AppID used corresponds to an app with sufficient permissions, as follows: # Directory.Read.All diff --git a/AAD_Groups_Members_inventoryMG.ps1 b/AAD_Groups_Members_inventoryMG.ps1 index 6dcaf29..f1944ff 100644 --- a/AAD_Groups_Members_inventoryMG.ps1 +++ b/AAD_Groups_Members_inventoryMG.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Requires -Modules @{ ModuleName="Microsoft.Graph.Groups"; ModuleVersion="1.19.0" } #Requires -Modules @{ ModuleName="Microsoft.Graph.Users"; ModuleVersion="1.19.0" } diff --git a/AU_memberOf_inventory.ps1 b/AU_memberOf_inventory.ps1 index 5162b65..a9d4f54 100644 --- a/AU_memberOf_inventory.ps1 +++ b/AU_memberOf_inventory.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Make sure to fill in all the required variables before running the script #Also make sure the AppID used corresponds to an app with sufficient permissions, as follows: # Directory.Read.All diff --git a/Calendar_Permissions_inventory.ps1 b/Calendar_Permissions_inventory.ps1 index 8d750d7..fcd3a33 100644 --- a/Calendar_Permissions_inventory.ps1 +++ b/Calendar_Permissions_inventory.ps1 @@ -1,4 +1,4 @@ -param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$CondensedOutput) +param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$CondensedOutput) function Get-CalendarPermissionInventory { <# @@ -145,4 +145,4 @@ function Get-CalendarPermissionInventory { } #Invoke the Get-CalendarPermissionInventory function and pass the command line parameters. Make sure the output is stored in a variable for reuse, even if not specified in the input! -Get-CalendarPermissionInventory @PSBoundParameters -OutVariable global:varPermissions | Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_CalendarPermissions.csv" -NoTypeInformation -Encoding UTF8 -UseCulture +Get-CalendarPermissionInventory @PSBoundParameters -OutVariable global:varPermissions #| Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_CalendarPermissions.csv" -NoTypeInformation -Encoding UTF8 -UseCulture \ No newline at end of file diff --git a/Calendar_Permissions_inventoryV2.ps1 b/Calendar_Permissions_inventoryV2.ps1 index 3837540..3b9da1b 100644 --- a/Calendar_Permissions_inventoryV2.ps1 +++ b/Calendar_Permissions_inventoryV2.ps1 @@ -1,4 +1,4 @@ -param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes) +param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes) #For details on what the script does and how to run it, check: https://www.michev.info/blog/post/4007/updated-version-of-the-calendar-permissions-inventory-script diff --git a/DG_MemberOf_inventory.ps1 b/DG_MemberOf_inventory.ps1 index 6769b3c..d4dda80 100644 --- a/DG_MemberOf_inventory.ps1 +++ b/DG_MemberOf_inventory.ps1 @@ -1,4 +1,4 @@ -param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeMailUsers,[switch]$IncludeMailContacts,[switch]$IncludeGuestUsers) +param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeMailUsers,[switch]$IncludeMailContacts,[switch]$IncludeGuestUsers) function Check-Connectivity { #Make sure we are connected to Exchange Remote PowerShell @@ -121,4 +121,4 @@ function Get-DGMembershipInventory { } #Invoke the Get-DGMembershipInventory function and pass the command line parameters. Make sure the output is stored in a variable for reuse, even if not specified in the input! -Get-DGMembershipInventory @PSBoundParameters -OutVariable global:varDGMemberOf #| Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_DGMemberOfReport.csv" -NoTypeInformation +Get-DGMembershipInventory @PSBoundParameters -OutVariable global:varDGMemberOf #| Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_DGMemberOfReport.csv" -NoTypeInformation \ No newline at end of file diff --git a/DG_MemberOf_inventoryV2.ps1 b/DG_MemberOf_inventoryV2.ps1 index db33758..9fb4494 100644 --- a/DG_MemberOf_inventoryV2.ps1 +++ b/DG_MemberOf_inventoryV2.ps1 @@ -1,4 +1,4 @@ -param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$IncludeMailUsers,[switch]$IncludeMailContacts,[switch]$IncludeGuestUsers,[switch]$IncludeUsers) +param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$IncludeMailUsers,[switch]$IncludeMailContacts,[switch]$IncludeGuestUsers,[switch]$IncludeUsers) function Check-Connectivity { #Make sure we are connected to Exchange Online PowerShell diff --git a/DG_members_recursive.ps1 b/DG_members_recursive.ps1 index 2020a6d..c257f45 100644 --- a/DG_members_recursive.ps1 +++ b/DG_members_recursive.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 [CmdletBinding()] #Make sure we can use -Verbose Param([switch]$IncludeAll,[switch]$IncludeDGs,[switch]$IncludeDynamicDGs,[switch]$IncludeO365Groups,[switch]$RecursiveOutput,[switch]$RecursiveOutputListGroups) diff --git a/DG_members_recursiveV2.ps1 b/DG_members_recursiveV2.ps1 index 5f2c4d0..610d100 100644 --- a/DG_members_recursiveV2.ps1 +++ b/DG_members_recursiveV2.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Requires -Modules @{ ModuleName="ExchangeOnlineManagement"; ModuleVersion="3.0.0" } [CmdletBinding()] #Make sure we can use -Verbose Param([switch]$IncludeAll,[switch]$IncludeDGs,[switch]$IncludeDynamicDGs,[switch]$IncludeO365Groups,[switch]$RecursiveOutput,[switch]$RecursiveOutputListGroups,[string[]]$GroupList) diff --git a/GraphSDK_Bulk_change_service.ps1 b/GraphSDK_Bulk_change_service.ps1 index 6628665..f020ce9 100644 --- a/GraphSDK_Bulk_change_service.ps1 +++ b/GraphSDK_Bulk_change_service.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Requires -Modules @{ ModuleName="Microsoft.Graph.Users"; ModuleVersion="1.19.0" } #Requires -Modules @{ ModuleName="Microsoft.Graph.Identity.DirectoryManagement"; ModuleVersion="1.19.0" } diff --git a/Graph_Bulk_change_service.ps1 b/Graph_Bulk_change_service.ps1 index f410b86..b48f49d 100644 --- a/Graph_Bulk_change_service.ps1 +++ b/Graph_Bulk_change_service.ps1 @@ -1,4 +1,4 @@ -#For details on what the script does and how to run it, check: https://www.michev.info/blog/post/3555/bulk-enable-specific-services-via-the-graph-api +#For details on what the script does and how to run it, check: https://www.michev.info/blog/post/3555/bulk-enable-specific-services-via-the-graph-api #Set the authentication details #oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo diff --git a/Graph_CA_report.ps1 b/Graph_CA_report.ps1 index 9407421..21c2a89 100644 --- a/Graph_CA_report.ps1 +++ b/Graph_CA_report.ps1 @@ -1,4 +1,4 @@ -#Set up +#Set up $AppId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" #clientID of your AAD app, must have Policy.Read.All permissions. Also needs Directory.Read.All permissions if you want the "readable" object names $client_secret = Get-Content .\ReportingAPIsecret.txt | ConvertTo-SecureString $app_cred = New-Object System.Management.Automation.PsCredential($AppId, $client_secret) diff --git a/Graph_Devices_MemberOf.ps1 b/Graph_Devices_MemberOf.ps1 index cc0e08c..6a6690f 100644 --- a/Graph_Devices_MemberOf.ps1 +++ b/Graph_Devices_MemberOf.ps1 @@ -1,4 +1,4 @@ -#Set the authentication details +#Set the authentication details $tenantID = "tenant.onmicrosoft.com" #your tenantID or tenant root domain $appID = "12345678-1234-1234-1234-1234567890AB" #the GUID of your app. For best result, use app with Directory.Read.All scope granted $client_secret = "XXXXXXXXXXXXXXXXXXX" #client secret for the app diff --git a/Graph_Flow_report.ps1 b/Graph_Flow_report.ps1 index 5ca29e8..9f31895 100644 --- a/Graph_Flow_report.ps1 +++ b/Graph_Flow_report.ps1 @@ -1,4 +1,4 @@ -#Load the MSAL binaries +#Load the MSAL binaries Add-Type -LiteralPath "C:\Program Files\PackageManagement\NuGet\Packages\Microsoft.IdentityModel.Abstractions.6.22.0\lib\net45\Microsoft.IdentityModel.Abstractions.dll" Add-Type -LiteralPath "C:\Program Files\PackageManagement\NuGet\Packages\Microsoft.Identity.Client.4.54.1\lib\net45\Microsoft.Identity.Client.dll" diff --git a/Graph_Last_Login_Date.ps1 b/Graph_Last_Login_Date.ps1 index 6a4588f..8183c17 100644 --- a/Graph_Last_Login_Date.ps1 +++ b/Graph_Last_Login_Date.ps1 @@ -1,31 +1,34 @@ -#Set up -$AppId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" #clientID of your AAD app, must have User.Read.All, Directory.Read.All, Auditlogs.Read.All permissions -$client_secret = Get-Content .\ReportingAPIsecret.txt | ConvertTo-SecureString -$app_cred = New-Object System.Management.Automation.PsCredential($AppId, $client_secret) -$TenantId = "tenant.onmicrosoft.com" #your tenant - -$body = @{ - client_id = $AppId - scope = "https://graph.microsoft.com/.default" - client_secret = $app_cred.GetNetworkCredential().Password - grant_type = "client_credentials" -} - -#simple code to get an access token, add your own handlers as needed -try { $tokenRequest = Invoke-WebRequest -Method Post -Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing -ErrorAction Stop } -catch { Write-Host "Unable to obtain access token, aborting..."; return } - -$token = ($tokenRequest.Content | ConvertFrom-Json).access_token - -#prepare auth header -$authHeader1 = @{ - 'Content-Type'='application\json' - 'Authorization'="Bearer $token" -} - -#exectue the actual query -$LastLogin = Invoke-WebRequest -Headers $AuthHeader1 -Uri "https://graph.microsoft.com/beta/users?`$select=displayName,userPrincipalName,signInActivity" -$result = ($LastLogin.Content | ConvertFrom-Json).Value -$result | select DisplayName,UserPrincipalName,@{n="LastLoginDate";e={$_.signInActivity.lastSignInDateTime}} - -#$result | Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_LastLoginDate.csv" -NoTypeInformation -Encoding UTF8 -UseCulture +#Set up +$AppId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" #clientID of your AAD app, must have User.Read.All, Directory.Read.All, Auditlogs.Read.All permissions +$client_secret = Get-Content '.\Login script\ReportingApiSecret.txt' | ConvertTo-SecureString +$app_cred = New-Object System.Management.Automation.PsCredential($AppId, $client_secret) +$TenantId = "michev.onmicrosoft.com" #your tenant + +$body = @{ + client_id = $AppId + scope = "https://graph.microsoft.com/.default" + client_secret = $app_cred.GetNetworkCredential().Password + grant_type = "client_credentials" +} + +#simple code to get an access token, add your own handlers as needed +try { $tokenRequest = Invoke-WebRequest -Method Post -Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing -ErrorAction Stop } +catch { Write-Host "Unable to obtain access token, aborting..."; return } + +$token = ($tokenRequest.Content | ConvertFrom-Json).access_token + +#prepare auth header +$authHeader1 = @{ + 'Content-Type'='application\json' + 'Authorization'="Bearer $token" +} + +#exectue the actual query +$LastLogin = Invoke-WebRequest -Headers $AuthHeader1 -Uri "https://graph.microsoft.com/beta/users?`$select=displayName,userPrincipalName,signInActivity" +$result = ($LastLogin.Content | ConvertFrom-Json).Value +$result | select DisplayName,UserPrincipalName,@{n="LastLoginDate";e={$_.signInActivity.lastSignInDateTime}} + +#$result | Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_LastLoginDate.csv" -NoTypeInformation -Encoding UTF8 -UseCulture + + +#https://docs.microsoft.com/en-us/graph/api/user-list?view=graph-rest-beta&tabs=http#example-5-list-the-last-sign-in-time-of-users-in-a-specific-time-range \ No newline at end of file diff --git a/Graph_ODFB_remove_all_shared.ps1 b/Graph_ODFB_remove_all_shared.ps1 index 3cc9b33..bcd54f0 100644 --- a/Graph_ODFB_remove_all_shared.ps1 +++ b/Graph_ODFB_remove_all_shared.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 # Make sure to fill in all the required variables before running the script # Also make sure the AppID used corresponds to an app with sufficient permissions, as follows: # User.Read.All to enumerate all users in the tenant diff --git a/Graph_ODFB_shared_files.ps1 b/Graph_ODFB_shared_files.ps1 index 49eb655..e0527c3 100644 --- a/Graph_ODFB_shared_files.ps1 +++ b/Graph_ODFB_shared_files.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 # Make sure to fill in all the required variables before running the script # Also make sure the AppID used corresponds to an app with sufficient permissions, as follows: # User.Read.All to enumerate all users in the tenant @@ -199,7 +199,7 @@ function Renew-Token { } try { - Set-Variable -Name authenticationResult -Scope Global -Value (Invoke-WebRequest -Method Post -Uri $url -Debug -Verbose -Body $body) + Set-Variable -Name authenticationResult -Scope Global -Value (Invoke-WebRequest -Method Post -Uri $url -Debug -Verbose -Body $body -ErrorAction Stop) $token = ($authenticationResult.Content | ConvertFrom-Json).access_token } catch { $_; return } @@ -271,7 +271,7 @@ if ($ExpandFolders -and ($depth -le 0)) { $depth = 0 } #Get a list of all users, make sure to handle multiple pages $GraphUsers = @() -$uri = "https://graph.microsoft.com/v1.0/users/?$`select=displayName,mail,userPrincipalName,id,userType&`$top=999&`$filter=userType eq 'Member'" +$uri = "https://graph.microsoft.com/v1.0/users/?`$select=displayName,mail,userPrincipalName,id,userType&`$top=999&`$filter=userType eq 'Member'" do { $result = Invoke-GraphApiRequest -Uri $uri -Verbose:$VerbosePreference -ErrorAction Stop $uri = $result.'@odata.nextLink' diff --git a/Graph_Remove_all_licenses.ps1 b/Graph_Remove_all_licenses.ps1 index bd2c44a..3fe9e47 100644 --- a/Graph_Remove_all_licenses.ps1 +++ b/Graph_Remove_all_licenses.ps1 @@ -1,4 +1,4 @@ -#Set the authentication details +#Set the authentication details $tenantID = "tenant.onmicrosoft.com" #your tenantID or tenant root domain $appID = "12345678-1234-1234-1234-1234567890AB" #the GUID of your app. For best result, use app with User.ReadWrite.All scope granted $client_secret = "XXXXXXXXXXXXXXXXXXX" #client secret for the app @@ -63,4 +63,4 @@ foreach ($user in $users) { }} #Simple anti-throttling control Start-Sleep -Milliseconds 200 -} +} \ No newline at end of file diff --git a/Graph_Teams_channel_SMTP.ps1 b/Graph_Teams_channel_SMTP.ps1 index 686baa1..7fd1e13 100644 --- a/Graph_Teams_channel_SMTP.ps1 +++ b/Graph_Teams_channel_SMTP.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 # Make sure to fill in all the required variables before running the script # Also make sure the AppID used corresponds to an app with sufficient permissions, as follows: # Group.Read.All or Directory.Read.All to read all Groups diff --git a/Groups_Owner_Inventory.ps1 b/Groups_Owner_Inventory.ps1 index f2c47f5..c01f586 100644 --- a/Groups_Owner_Inventory.ps1 +++ b/Groups_Owner_Inventory.ps1 @@ -1,4 +1,4 @@ -param([switch]$IncludeExchangeManagedBy) +param([switch]$IncludeExchangeManagedBy) #Make sure we try the AzureADPreview module first, as it surfaces more details... Remove-Module AzureAD -ErrorAction SilentlyContinue diff --git a/Groups_Owner_InventoryV2.ps1 b/Groups_Owner_InventoryV2.ps1 index 8b87112..7beb167 100644 --- a/Groups_Owner_InventoryV2.ps1 +++ b/Groups_Owner_InventoryV2.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Requires -Modules @{ ModuleName="ExchangeOnlineManagement"; ModuleVersion="3.0.0" } #Requires -Modules @{ ModuleName="Microsoft.Graph.Groups"; ModuleVersion="1.19.0" } #Requires -Modules @{ ModuleName="Microsoft.Graph.Users"; ModuleVersion="1.19.0" } diff --git a/Mailbox_Folder_Permissions_inventory.ps1 b/Mailbox_Folder_Permissions_inventory.ps1 index 07b1cab..120f18f 100644 --- a/Mailbox_Folder_Permissions_inventory.ps1 +++ b/Mailbox_Folder_Permissions_inventory.ps1 @@ -1,20 +1,11 @@ -#Requires -Version 3.0 -Modules ExchangeOnlineManagement -param( - [switch]$IncludeAll, - [switch]$IncludeUserMailboxes, - [switch]$IncludeSharedMailboxes, - [switch]$IncludeRoomMailboxes, - [switch]$CondensedOutput, - [switch]$IncludeDefaultPermissions, - [string[]]$ExcludeUsers -) +#Requires -Version 3.0 +param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$CondensedOutput,[switch]$IncludeDefaultPermissions,[string[]]$ExcludeUsers) function Get-MailboxFolderPermissionInventory { - <# - .SYNOPSIS +<# +.Synopsis Lists permissions for all user-accessible folders for all mailboxes of the selected type(s). - - .DESCRIPTION +.DESCRIPTION The Get-MailboxFolderPermissionInventory cmdlet enumerates the folders for all mailboxes of the selected type(s) and lists their permissions. To adjust the list of folders, add to the $includedfolders or $excludedfolders array, respectively. Running the cmdlet without parameters will return entries for all User mailboxes only. Specifying particular mailbox type(s) can be done with the corresponding switch parameter. The Default permission entry level is not returned unless you specify the -IncludeDefaultPermissions switch when running the cmdlet/script. @@ -22,20 +13,19 @@ function Get-MailboxFolderPermissionInventory { To specify a variable in which to hold the cmdlet output, use the -OutVariable parameter. To use condensed output (one line per folder), use the -CondensedOutput switch. - .EXAMPLE +.EXAMPLE Get-MailboxFolderPermissionInventory -IncludeUserMailboxes This command will return a list of permissions for the user-accessible folders for all User mailboxes. - .EXAMPLE +.EXAMPLE Get-MailboxFolderPermissionInventory -IncludeAll -OutVariable global:var $var | Export-Csv -NoTypeInformation "accessrights.csv" To export the results to a CSV file, use the OutVariable parameter. - .INPUTS +.INPUTS None. - - .OUTPUTS +.OUTPUTS Array with information about the mailbox, delegate and type of permissions. #> @@ -43,58 +33,52 @@ function Get-MailboxFolderPermissionInventory { Param ( - #Specify whether to include user mailboxes in the result - [Switch]$IncludeUserMailboxes, - #Specify whether to include Shared mailboxes in the result - [Switch]$IncludeSharedMailboxes, - #Specify whether to include Room and Equipment mailboxes in the result - [Switch]$IncludeRoomMailboxes, - #Specify whether to return all mailbox types - [Switch]$IncludeAll, - #Specify whether to write the output in condensed format - [Switch]$CondensedOutput, - #Specify whether to return permissions for the Default entry - [switch]$IncludeDefaultPermissions, - #Specify a list of users (SMTP addresses) for which NOT to return permissions (think service accounts, admin accounts, etc) - [string[]]$ExcludeUsers - ) + #Specify whether to include user mailboxes in the result + [Switch]$IncludeUserMailboxes, + #Specify whether to include Shared mailboxes in the result + [Switch]$IncludeSharedMailboxes, + #Specify whether to include Room and Equipment mailboxes in the result + [Switch]$IncludeRoomMailboxes, + #Specify whether to return all mailbox types + [Switch]$IncludeAll, + #Specify whether to write the output in condensed format + [Switch]$CondensedOutput, + #Specify whether to return permissions for the Default entry + [switch]$IncludeDefaultPermissions, + #Specify a list of users (SMTP addresses) for which NOT to return permissions (think service accounts, admin accounts, etc) + [string[]]$ExcludeUsers) #Add switch for GroupMailboxes: Get-MailboxFolderPermission -GroupMailbox itsupport #Add switch for SupervisoryReviewPolicyMailbox, once they are actually discoverable via Get-Mailbox! - # adding timer to calculate execution time - $global:timer = [diagnostics.stopwatch]::StartNew() - #Include these folder types by default - $includedfolders = @("Root", "Inbox", "Calendar", "Contacts", "DeletedItems", "Drafts", "JunkEmail", "Journal", "Notes", "Outbox", "SentItems", "Tasks", "CommunicatorHistory", "Clutter", "Archive") + $includedfolders = @("Root","Inbox","Calendar", "Contacts", "DeletedItems", "Drafts", "JunkEmail", "Journal", "Notes", "Outbox", "SentItems", "Tasks", "CommunicatorHistory", "Clutter", "Archive") #$includedfolders = @("Root","Inbox","Calendar", "Contacts", "DeletedItems", "SentItems", "Tasks") #Trimmed down list of default folders #Non-default folders created by Outlook or other mail programs. Folder NAMES, not types! #Exclude SearchDiscoveryHoldsFolder and SearchDiscoveryHoldsUnindexedItemFolder as they're not marked as default folders - $excludedfolders = @("News Feed", "Quick Step Settings", "Social Activity Notifications", "Suggested Contacts", "SearchDiscoveryHoldsUnindexedItemFolder", "SearchDiscoveryHoldsFolder", "Calendar Logging") #Exclude "Calendar Logging" on older Exchange versions + $excludedfolders = @("News Feed","Quick Step Settings","Social Activity Notifications","Suggested Contacts", "SearchDiscoveryHoldsUnindexedItemFolder", "SearchDiscoveryHoldsFolder","Calendar Logging") #Exclude "Calendar Logging" on older Exchange versions #Initialize the variable used to designate mailbox types, based on the input parameters $included = @() - if ($IncludeSharedMailboxes) { $included += "SharedMailbox" } - if ($IncludeRoomMailboxes) { $included += "RoomMailbox"; $included += "EquipmentMailbox" } + if($IncludeSharedMailboxes) { $included += "SharedMailbox"} + if($IncludeRoomMailboxes) { $included += "RoomMailbox"; $included += "EquipmentMailbox"} #if no parameters specified, return only User mailboxes - if ($IncludeUserMailboxes -or !$included) { $included += "UserMailbox" } + if($IncludeUserMailboxes -or !$included) { $included += "UserMailbox"} #Confirm connectivity to Exchange Online - try { $session = Get-PSSession -InstanceId (Get-OrganizationConfig).RunspaceId.Guid -ErrorAction Stop } + try { $session = Get-PSSession -InstanceId (Get-OrganizationConfig).RunspaceId.Guid -ErrorAction Stop } catch { Write-Error "No active Exchange Online session detected, please connect to ExO first: https://technet.microsoft.com/en-us/library/jj984289(v=exchg.160).aspx" -ErrorAction Stop } #Get the list of mailboxes, depending on the parameters specified when invoking the script if ($IncludeAll) { - #$MBList = Invoke-Command -Session $session -ScriptBlock { Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox, SharedMailbox, RoomMailbox, EquipmentMailbox | Select-Object -Property Displayname, Identity, PrimarySMTPAddress, RecipientTypeDetails } -HideComputerName - $MBList = Get-EXOMailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox, SharedMailbox, RoomMailbox, EquipmentMailbox -Properties Displayname, Identity, PrimarySMTPAddress, RecipientTypeDetails + $MBList = Invoke-Command -Session $session -ScriptBlock { Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox,SharedMailbox,RoomMailbox,EquipmentMailbox | Select-Object -Property Displayname,Identity,PrimarySMTPAddress,RecipientTypeDetails } -HideComputerName } else { - #$MBList = Invoke-Command -Session $session -ScriptBlock { Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails $Using:included | Select-Object -Property Displayname, Identity, PrimarySMTPAddress, RecipientTypeDetails } -HideComputerName - $MBList = Get-EXOMailbox -ResultSize Unlimited -RecipientTypeDetails $included -Properties Displayname, Identity, PrimarySMTPAddress, RecipientTypeDetails + $MBList = Invoke-Command -Session $session -ScriptBlock { Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails $Using:included | Select-Object -Property Displayname,Identity,PrimarySMTPAddress,RecipientTypeDetails } -HideComputerName } #If no mailboxes are returned from the above cmdlet, stop the script and inform the user - if (!$MBList) { Write-Error "No mailboxes of the specifyied types were found, specify different criteria." -ErrorAction Stop } + if (!$MBList) { Write-Error "No mailboxes of the specifyied types were found, specify different criteria." -ErrorAction Stop} #Once we have the mailbox list, cycle over each mailbox to gather folder permissions inventory $arrPermissions = @() @@ -108,51 +92,50 @@ function Get-MailboxFolderPermissionInventory { $count++ #Get the folder statistics for each mailbox and use them to filter out folders we are not interested in - #$MBSMTP = $MB.PrimarySmtpAddress.ToString() - $MBSMTP = $MB.PrimarySmtpAddress - #$MBfolders = Invoke-Command -Session $session -ScriptBlock { Get-MailboxFolderStatistics $using:MBSMTP | Select-Object Name, FolderType, Identity } -HideComputerName - $MBfolders = Get-EXOMailboxFolderStatistics $MBSMTP | Select-Object Name, FolderType, Identity - $MBfolders = $MBfolders | Where-Object { ($_.FolderType -eq "User created" -or $_.FolderType -in $includedfolders) -and ($_.Name -notin $excludedfolders) } + $MBSMTP = $MB.PrimarySmtpAddress.ToString() + $MBfolders = Invoke-Command -Session $session -ScriptBlock { Get-MailboxFolderStatistics $using:MBSMTP | Select-Object Name,FolderType,Identity } -HideComputerName + $MBfolders = $MBfolders | ? {($_.FolderType -eq "User created" -or $_.FolderType -in $includedfolders) -and ($_.Name -notin $excludedfolders)} #If no folders left after applying the filters, move to next mailbox - if (-not($MBfolders)) { continue } + if (!$MBfolders) { continue } #Cycle over each folder we are interested in. Start-Sleep -Milliseconds 800 #Add some delay to avoid throttling... foreach ($folder in $MBfolders) { #"Fix" for folders with "/" characters - $foldername = $folder.Identity.ToString().Replace([char]63743, "/").Replace($MBSMTP, $MBSMTP + ":") + $foldername = $folder.Identity.ToString().Replace([char]63743,"/").Replace($MBSMTP,$MBSMTP + ":") #Get the folder permissions - #if ($folder.FolderType -eq "Root") { $MBrights = Invoke-Command -Session $session -ScriptBlock { Get-MailboxFolderPermission -Identity $using:MBSMTP } -HideComputerName } - if ($folder.FolderType -eq "Root") { $MBrights = Get-EXOMailboxFolderPermission -Identity $MBSMTP } - #else { $MBrights = Invoke-Command -Session $session -ScriptBlock { Get-MailboxFolderPermission -Identity $using:foldername } -HideComputerName } - else { $MBrights = Get-EXOMailboxFolderPermission -Identity $foldername } + if ($folder.FolderType -eq "Root") { $MBrights = Invoke-Command -Session $session -ScriptBlock { Get-MailboxFolderPermission -Identity $using:MBSMTP } -HideComputerName } + else { $MBrights = Invoke-Command -Session $session -ScriptBlock { Get-MailboxFolderPermission -Identity $using:foldername } -HideComputerName } #Exclude default folders and users as per the parameters passed to the script - if (-not($IncludeDefaultPermissions)) { $MBrights = $MBrights | Where-Object { $_.User.DisplayName -notin @("Default", "Anonymous", "Owner@local", "Member@local") } } - #if ($ExcludeUsers) { $MBrights = $MBrights | Where-Object { $_.User.ADRecipient.PrimarySmtpAddress.ToString() -notin $ExcludeUsers } } - if ($ExcludeUsers) { $MBrights = $MBrights | Where-Object { $_.User -notin $ExcludeUsers } } - + if (!$IncludeDefaultPermissions) { $MBrights = $MBrights | ? {$_.User.DisplayName -notin @("Default","Anonymous","Owner@local","Member@local")}} + if ($ExcludeUsers) { $MBrights = $MBrights | ? {$_.User.ADRecipient.PrimarySmtpAddress.ToString() -notin $ExcludeUsers}} #No non-default permissions found, continue to next folder - if (-not($MBrights)) { continue } + if (!$MBrights) { continue } if ($condensedoutput) { #Prepare the output object $objPermissions = New-Object PSObject - $i++; Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "Number" -Value $i + $i++;Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "Number" -Value $i Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "Mailbox address" -Value $MBSMTP Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "Mailbox type" -Value $MB.RecipientTypeDetails Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "Folder identity" -Value $foldername - if ($IncludeDefaultPermissions) { Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "Default level" -Value $(($MBrights | Where-Object { $_.User.DisplayName -eq "Default" }).AccessRights -join ";") } + if ($IncludeDefaultPermissions) { Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "Default level" -Value $(($MBrights | ? {$_.User.DisplayName -eq "Default"}).AccessRights -join ";") } #Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "Anonymous level" -Value $(($MBrights | ? {$_.User.DisplayName -eq "Anonymous"}).AccessRights -join ";") - $internal = ""; $external = ""; $orphaned = "" + $internal = "";$external = "";$orphaned = "" foreach ($entry in $MBrights) { - switch ($entry.User.UserType) { - Internal { $internal = ("$($entry.User.UserPrincipalName.ToString()):$($entry.AccessRights)" + ";" + $internal) } - External { $external = ("$($entry.User.UserPrincipalName.Replace("ExchangePublishedUser.",$null)):$($entry.AccessRights)" + ";" + $external) } - Unknown { $orphaned = ("$($entry.User.DisplayName):$($entry.AccessRights)" + ";" + $orphaned) } + if ($entry.User.UserType.ToString() -eq "Internal") { + $internal = ("$($entry.User.RecipientPrincipal.PrimarySmtpAddress.ToString()):$($entry.AccessRights)" + ";" + $internal) } + elseif ($entry.User.UserType.ToString() -eq "External") { + $external = ("$($entry.User.RecipientPrincipal.PrimarySmtpAddress.Replace("ExchangePublishedUser.",$null)):$($entry.AccessRights)" + ";" + $external) + } + elseif ($entry.User.UserType.ToString() -eq "Unknown") { + $orphaned = ("$($entry.User.DisplayName):$($entry.AccessRights)" + ";" + $orphaned) + } + else { continue } } Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "Internal levels" -Value $internal.Trim(";") Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "External levels" -Value $external.Trim(";") @@ -167,18 +150,17 @@ function Get-MailboxFolderPermissionInventory { foreach ($entry in $MBrights) { #Prepare the output object $objPermissions = New-Object PSObject - $i++; Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "Number" -Value $i + $i++;Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "Number" -Value $i Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "Mailbox address" -Value $MBSMTP Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "Mailbox type" -Value $MB.RecipientTypeDetails Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "Folder identity" -Value $foldername - $varUser = ""; $varType = ""; - switch ( $entry.User.UserType ) { - Internal { $varUser = $entry.User.UserPrincipalName.ToString(); $varType = "Internal" } - External { $varUser = $entry.User.UserPrincipalName.Replace("ExchangePublishedUser.", $null); $varType = "External" } - Unknown { $varUser = $entry.User.DisplayName; $varType = "Orphaned" } - 'Default' { $varUser = $entry.User.DisplayName; $varType = "Default" } - } + $varUser = "";$varType = ""; + if ($entry.User.UserType.ToString() -eq "Internal") { $varUser = $entry.User.RecipientPrincipal.PrimarySmtpAddress.ToString(); $varType = "Internal" } + elseif ($entry.User.UserType.ToString() -eq "Default") { $varUser = $entry.User.DisplayName; $varType = "Default" } + elseif ($entry.User.UserType.ToString() -eq "External") { $varUser = $entry.User.RecipientPrincipal.PrimarySmtpAddress.Replace("ExchangePublishedUser.",$null); $varType = "External" } + elseif ($entry.User.UserType.ToString() -eq "Unknown") { $varUser = $entry.User.DisplayName; $varType = "Orphaned" } + else { continue } Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "User" -Value $varUser Add-Member -InputObject $objPermissions -MemberType NoteProperty -Name "Permissions" -Value $($entry.AccessRights -join ";") @@ -187,17 +169,12 @@ function Get-MailboxFolderPermissionInventory { $arrPermissions += $objPermissions #Uncomment if the script is failing due to connectivity issues, the line below will write the output to a CSV file for each individual permissions entry #$objPermissions | Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd'))_MailboxFolderPermissions.csv" -Append -NoTypeInformation -Encoding UTF8 -UseCulture - } + }} } - } - } + } #Output the result to the console host. Rearrange/sort as needed. - $timer.Stop() - - Write-Host "Script finished. Execution time: $($timer.Elapsed)" -ForegroundColor Green - $arrPermissions | Select-Object * -ExcludeProperty Number, PSComputerName, RunspaceId, PSShowComputerName + $arrPermissions | select * -ExcludeProperty Number,PSComputerName,RunspaceId,PSShowComputerName } #Invoke the Get-MailboxFolderPermissionInventory function and pass the command line parameters. Make sure the output is stored in a variable for reuse, even if not specified in the input! -Get-MailboxFolderPermissionInventory @PSBoundParameters -OutVariable global:varPermissions | Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_MailboxFolderPermissions.csv" -NoTypeInformation -Encoding UTF8 -UseCulture -Write-Host "Script finished. Execution time: $($timer.Elapsed)" -ForegroundColor Green \ No newline at end of file +Get-MailboxFolderPermissionInventory @PSBoundParameters -OutVariable global:varPermissions #| Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_MailboxFolderPermissions.csv" -NoTypeInformation -Encoding UTF8 -UseCulture \ No newline at end of file diff --git a/Mailbox_Folder_Permissions_inventoryV2.ps1 b/Mailbox_Folder_Permissions_inventoryV2.ps1 index 095453e..524dacd 100644 --- a/Mailbox_Folder_Permissions_inventoryV2.ps1 +++ b/Mailbox_Folder_Permissions_inventoryV2.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$IncludeDefaultPermissions,[string[]]$ExcludeUsers) #For details on what the script does and how to run it, check: https://www.michev.info/blog/post/4095/updated-version-of-the-mailbox-folder-permissions-inventory-script diff --git a/Mailbox_Forwarding_inventory.ps1 b/Mailbox_Forwarding_inventory.ps1 index 569d62b..cac39b7 100644 --- a/Mailbox_Forwarding_inventory.ps1 +++ b/Mailbox_Forwarding_inventory.ps1 @@ -1,4 +1,4 @@ -param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$IncludeDiscoveryMailboxes,[switch]$IncludeTeamMailboxes,[switch]$CheckInboxRules,[switch]$CheckCalendarDelegates,[switch]$CheckTransportRules) +param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$IncludeDiscoveryMailboxes,[switch]$IncludeTeamMailboxes,[switch]$CheckInboxRules,[switch]$CheckCalendarDelegates,[switch]$CheckTransportRules) function Get-MailboxForwardingInventory { <# diff --git a/Mailbox_Forwarding_inventoryV2.ps1 b/Mailbox_Forwarding_inventoryV2.ps1 index ed08701..0086511 100644 --- a/Mailbox_Forwarding_inventoryV2.ps1 +++ b/Mailbox_Forwarding_inventoryV2.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Requires -Modules @{ ModuleName="ExchangeOnlineManagement"; ModuleVersion="3.0.0" } [CmdletBinding()] param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$CheckInboxRules,[switch]$CheckCalendarDelegates,[switch]$CheckTransportRules,[switch]$CheckTenantControls) diff --git a/Mailbox_Permissions_inventory.ps1 b/Mailbox_Permissions_inventory.ps1 index 32ca2bf..7e8e7b7 100644 --- a/Mailbox_Permissions_inventory.ps1 +++ b/Mailbox_Permissions_inventory.ps1 @@ -1,4 +1,4 @@ -param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$IncludeDiscoveryMailboxes,[switch]$IncludeTeamMailboxes) +param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$IncludeDiscoveryMailboxes,[switch]$IncludeTeamMailboxes) function Get-MailboxPermissionInventory { <# @@ -64,7 +64,7 @@ function Get-MailboxPermissionInventory { } #If no mailboxes are returned from the above cmdlet, stop the script and inform the user - if (!$MBList) { Write-Error "No mailboxes of the specifyied types were found, specify different criteria." -ErrorAction Stop} + if (!$MBList) { Write-Error "No mailboxes of the specified types were found, specify different criteria." -ErrorAction Stop} #Once we have the mailbox list, cycle over each mailbox to gather permissions inventory $arrPermissions = @() diff --git a/Mailbox_Permissions_inventoryV2.ps1 b/Mailbox_Permissions_inventoryV2.ps1 index e67a341..e17266a 100644 --- a/Mailbox_Permissions_inventoryV2.ps1 +++ b/Mailbox_Permissions_inventoryV2.ps1 @@ -1,4 +1,4 @@ -param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$IncludeSoftDeleted) +param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$IncludeSoftDeleted) #For details on what the script does and how to run it, check: https://www.michev.info/blog/post/4021/updated-version-of-the-mailbox-permissions-inventory-script diff --git a/Mailbox_Permissions_inventory_SOB.ps1 b/Mailbox_Permissions_inventory_SOB.ps1 index 5f54e6a..a93df18 100644 --- a/Mailbox_Permissions_inventory_SOB.ps1 +++ b/Mailbox_Permissions_inventory_SOB.ps1 @@ -1,4 +1,4 @@ -param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$IncludeDiscoveryMailboxes,[switch]$IncludeGroupMailboxes,[switch]$IncludeTeamMailboxes,[switch]$IncludeDGs) +param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$IncludeDiscoveryMailboxes,[switch]$IncludeGroupMailboxes,[switch]$IncludeTeamMailboxes,[switch]$IncludeDGs) function Get-SOBPermissionInventory { <# diff --git a/Mailbox_Permissions_inventory_SOB_V2.ps1 b/Mailbox_Permissions_inventory_SOB_V2.ps1 index c44a611..c73b534 100644 --- a/Mailbox_Permissions_inventory_SOB_V2.ps1 +++ b/Mailbox_Permissions_inventory_SOB_V2.ps1 @@ -1,4 +1,4 @@ -param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$IncludeGroupMailboxes,[switch]$IncludeDGs) +param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$IncludeGroupMailboxes,[switch]$IncludeDGs) #For details on what the script does and how to run it, check: https://www.michev.info/blog/post/5576/script-send-on-behalf-of-permissions-microsoft-365 diff --git a/Mobile_devices_inventory.ps1 b/Mobile_devices_inventory.ps1 index 991ea95..2290267 100644 --- a/Mobile_devices_inventory.ps1 +++ b/Mobile_devices_inventory.ps1 @@ -1,4 +1,4 @@ -#Helper function for loading the mailbox data. If no existing CSV file is found or it is outdated, the function will generate a new file (might take some time)... +#Helper function for loading the mailbox data. If no existing CSV file is found or it is outdated, the function will generate a new file (might take some time)... function Load-MailboxMatchInputFile { $importCSV = Get-ChildItem -Path $PSScriptRoot -Filter "*MailboxReport.csv" | sort LastWriteTime -Descending | select -First 1 #| select -ExpandProperty FullName @@ -97,4 +97,4 @@ foreach ($device in $MobileDevices) { } #Export the output to a CSV file -$MobileDevices | Export-Csv -Path "$PSScriptRoot\$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_MobileDeviceReport.csv" -NoTypeInformation -Encoding UTF8 -UseCulture \ No newline at end of file +$MobileDevices #| Export-Csv -Path "$PSScriptRoot\$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_MobileDeviceReport.csv" -NoTypeInformation -Encoding UTF8 -UseCulture \ No newline at end of file diff --git a/Mobile_devices_inventoryV2.ps1 b/Mobile_devices_inventoryV2.ps1 index 36b5d58..478baab 100644 --- a/Mobile_devices_inventoryV2.ps1 +++ b/Mobile_devices_inventoryV2.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Requires -Modules @{ ModuleName="ExchangeOnlineManagement"; ModuleVersion="3.0.0" } #For details on what the script does and how to run it, check: https://www.michev.info/blog/post/5639/mobile-device-inventory-and-statistics-report-2023-updated-version diff --git a/O365_Groups_links_report.ps1 b/O365_Groups_links_report.ps1 index 6c723d5..b6591e5 100644 --- a/O365_Groups_links_report.ps1 +++ b/O365_Groups_links_report.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 param([switch]$CondensedOutput) #Helper function for fetching data from Exchange Online diff --git a/O365_Groups_links_reportV2.ps1 b/O365_Groups_links_reportV2.ps1 index 8402da0..94e2bc4 100644 --- a/O365_Groups_links_reportV2.ps1 +++ b/O365_Groups_links_reportV2.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Requires -Modules @{ ModuleName="ExchangeOnlineManagement"; ModuleVersion="3.0.0" } #For details on what the script does and how to run it, check: https://www.michev.info/blog/post/5704/reporting-on-microsoft-365-groups-links-2023-updated-version param([switch]$CondensedOutput) diff --git a/O365_aliases_inventory.ps1 b/O365_aliases_inventory.ps1 index bd73e07..e8d7ed3 100644 --- a/O365_aliases_inventory.ps1 +++ b/O365_aliases_inventory.ps1 @@ -1,4 +1,4 @@ -param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$IncludeGroupMailboxes,[switch]$IncludeDGs,[switch]$IncludeMailUsers,[switch]$IncludeMailContacts,[switch]$CondensedOutput,[switch]$IncludeSIPAliases,[switch]$IncludeSPOAliases) +param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$IncludeGroupMailboxes,[switch]$IncludeDGs,[switch]$IncludeMailUsers,[switch]$IncludeMailContacts,[switch]$CondensedOutput,[switch]$IncludeSIPAliases,[switch]$IncludeSPOAliases) function Get-EmailAddressesInventory { <# diff --git a/O365_aliases_inventoryV2.ps1 b/O365_aliases_inventoryV2.ps1 index 44afdd2..b21d7e5 100644 --- a/O365_aliases_inventoryV2.ps1 +++ b/O365_aliases_inventoryV2.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Requires -Modules @{ ModuleName="ExchangeOnlineManagement"; ModuleVersion="3.0.0" } #For details on what the script does and how to run it, check: https://www.michev.info/blog/post/5711/report-on-all-microsoft-365-email-addresses param([switch]$IncludeAll,[switch]$IncludeUserMailboxes,[switch]$IncludeSharedMailboxes,[switch]$IncludeRoomMailboxes,[switch]$IncludeGroupMailboxes,[switch]$IncludeDGs,[switch]$IncludeMailUsers,[switch]$IncludeMailContacts,[switch]$CondensedOutput,[switch]$IncludeSIPAliases,[switch]$IncludeSPOAliases) diff --git a/OU_report.ps1 b/OU_report.ps1 index fec5ac3..69e310d 100644 --- a/OU_report.ps1 +++ b/OU_report.ps1 @@ -1,4 +1,4 @@ -if (!(Get-Module AzureAD -ListAvailable | ? {($_.Version.Major -eq 2 -and $_.Version.Build -eq 0 -and $_.Version.Revision -ge 55) -or ($_.Version.Major -eq 2 -and $_.Version.Build -ge 1)})) { Write-Host -BackgroundColor Red "This script requires a recent version of the AzureAD PowerShell module. Download it here: https://www.powershellgallery.com/packages/AzureAD/"; return} +if (!(Get-Module AzureAD -ListAvailable | ? {($_.Version.Major -eq 2 -and $_.Version.Build -eq 0 -and $_.Version.Revision -ge 55) -or ($_.Version.Major -eq 2 -and $_.Version.Build -ge 1)})) { Write-Host -BackgroundColor Red "This script requires a recent version of the AzureAD PowerShell module. Download it here: https://www.powershellgallery.com/packages/AzureAD/"; return} try { Get-AzureADTenantDetail | Out-Null } catch { Connect-AzureAD | Out-Null } diff --git a/OU_reportV2.ps1 b/OU_reportV2.ps1 index 8ac0944..faa36da 100644 --- a/OU_reportV2.ps1 +++ b/OU_reportV2.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Requires -Modules @{ ModuleName="Microsoft.Graph.Users"; ModuleVersion="1.19.0" } #For details on what the script does and how to run it, check: https://www.michev.info/blog/post/5716/reporting-on-synchronized-users-ou-via-the-graph-sdk-for-powershell diff --git a/OwnerlessGroupPolicy.ps1 b/OwnerlessGroupPolicy.ps1 index 533a781..db0b02f 100644 --- a/OwnerlessGroupPolicy.ps1 +++ b/OwnerlessGroupPolicy.ps1 @@ -1,4 +1,4 @@ -######################################################################################################## +######################################################################################################## # For details on what the script does and how to run it, check: # # https://www.michev.info/blog/post/4148/ownerless-group-policy-cmdlets-replacement # ######################################################################################################## diff --git a/Remove_Folder_Permissions_recursive_BULK.ps1 b/Remove_Folder_Permissions_recursive_BULK.ps1 index f74f2bc..3a37197 100644 --- a/Remove_Folder_Permissions_recursive_BULK.ps1 +++ b/Remove_Folder_Permissions_recursive_BULK.ps1 @@ -1,198 +1,198 @@ -#Requires -Version 3.0 -[CmdletBinding(SupportsShouldProcess)] #Make sure we can use -WhatIf and -Verbose -Param([switch]$Quiet,[ValidateNotNullOrEmpty()][Alias("Identity")][String[]]$Mailbox,[ValidateNotNullOrEmpty()][Alias("Delegate")][String[]]$User,[Parameter(Mandatory=$false)][String]$ParentFolderPath) - -#Include these folder types by default -$includedfolders = @("Root","Inbox","Calendar", "Contacts", "DeletedItems", "Drafts", "JunkEmail", "Journal", "Notes", "Outbox", "SentItems", "Tasks", "CommunicatorHistory", "Clutter", "Archive") -#$includedfolders = @("Root","Inbox","Calendar", "Contacts", "DeletedItems", "SentItems", "Tasks") #Trimmed down list of default folders - -#Exclude additional Non-default folders created by Outlook or other mail programs. Folder NAMES, not types! So make sure to include translations too! -#Exclude SearchDiscoveryHoldsFolder and SearchDiscoveryHoldsUnindexedItemFolder as they're not marked as default folders #Exclude "Calendar Logging" on older Exchange versions -$excludedfolders = @("News Feed","Quick Step Settings","Social Activity Notifications","Suggested Contacts", "SearchDiscoveryHoldsUnindexedItemFolder", "SearchDiscoveryHoldsFolder","Calendar Logging") - -try { $script:session = Get-PSSession -InstanceId (Get-AcceptedDomain | select -First 1).RunspaceId.Guid -ErrorAction Stop } -catch { Write-Error "No active Exchange Remote PowerShell session detected, please connect first. To connect to ExO: https://technet.microsoft.com/en-us/library/jj984289(v=exchg.160).aspx" -ErrorAction Stop } - -function ReturnFolderList { -<# -.Synopsis - Enumerates all user-accessible folders for the mailbox -.DESCRIPTION - The ReturnFolderList cmdlet enumerates the folders for the given mailbox. To adjust the list of folders, add to the $includedfolders or $excludedfolders array, respectively. -.PARAMETER SMTPAddress - Use the -SMTPAddress parameter to designate the mailbox where the desired folders reside -.PARAMETER ParentFolderPath - Use the -ParentFolderPath to designate a starting point for listing folders. For instance, use "/Inbox/From Accounting/" to get all subfolders of the 'From Accounting folder in your Inbox. -.EXAMPLE - ReturnFolderList user@domain.com - - This command will return a list of all user-accessible folders for the user@domain.com mailbox. -.INPUTS - SMTP address of the mailbox, with optional parent folder (full path). -.OUTPUTS - Array with information about the mailbox folders. -#> - - param([Parameter(Mandatory=$true, ValueFromPipeline=$true)]$SMTPAddress,[Parameter(Mandatory=$false)][String]$ParentFolderPath) - - if (!$session -or ($session.State -ne "Opened")) { Write-Error "No active Exchange Remote PowerShell session detected, please connect first. To connect to ExO: https://technet.microsoft.com/en-us/library/jj984289(v=exchg.160).aspx" -ErrorAction Stop } - - $MBfolders = Invoke-Command -Session $session -ScriptBlock { Get-MailboxFolderStatistics $using:SMTPAddress | Select-Object Name,FolderType,Identity,FolderPath } -HideComputerName -ErrorAction Stop - if($PSBoundParameters.ContainsKey('ParentFolderPath')) { - $MBfolders = $MBfolders | ? {($_.FolderType -eq "User created" -or $_.FolderType -in $includedfolders) -and ($_.Name -notin $excludedfolders) -and ($_.FolderPath -match $ParentFolderPath+"*")} - } - else { - $MBfolders = $MBfolders | ? {($_.FolderType -eq "User created" -or $_.FolderType -in $includedfolders) -and ($_.Name -notin $excludedfolders)} - } - - if (!$MBfolders) { return } - else { return ($MBfolders | select Name,FolderType,Identity) } -} - - -function Remove-MailboxFolderPermissionsRecursive { -<# -.Synopsis - Removes permissions for all user-accessible folders for a given mailbox. -.DESCRIPTION - The Remove-MailboxFolderPermissionsRecursive cmdlet removes permissions for all user-accessible folders for the given mailbox(es), specified via the -Mailbox parameter. The list of folders is generated via the ReturnFolderList function. Configure the $includedfolders and $excludedfolders variables to granularly control the folder list. -.PARAMETER Mailbox - Use the -Mailbox parameter to designate the mailbox. Any valid Exchange mailbox identifier can be specified. Multiple mailboxes can be specified in a comma-separated list or array, see examples below. -.PARAMETER User - Use the -User parameter to designate the delegate. Any valid Exchange security principal identifier can be specified. Multiple delegates can be specified in a comma-separated list or array, see examples below. -.PARAMETER ParentFolderPath - Use the -ParentFolderPath to designate a starting point for listing folders. For instance, use "/Inbox/From Accounting/" to get all subfolders of the 'From Accounting folder in your Inbox. -.PARAMETER Quiet - Use the -Quiet switch if you want to suppress output to the console. -.PARAMETER WhatIf - The -WhatIf switch simulates the actions of the command. You can use this switch to view the changes that would occur without actually applying those changes. -.PARAMETER Verbose - The -Verbose switch provides additional details on the cmdlet progress, it can be useful when troubleshooting issues. -.EXAMPLE - Remove-MailboxFolderPermissionsRecursive -Mailbox user@domain.com -User delegate@domain.com - - This command removes permissions on all user-accessible folders in the user@domain.com mailbox for the delegate@domain.com delegate. -.EXAMPLE - Remove-MailboxFolderPermissionsRecursive -Mailbox shared@domain.com,room@domain.com -User delegate@domain.com - - This command removes permissions on all user-accessible folders in BOTH the room@domain.com and shared@domain.com mailboxes for the delegate@domain.com delegate. -.EXAMPLE - Remove-MailboxFolderPermissionsRecursive -Mailbox (Get-Mailbox -RecipientTypeDetails RoomMailbox) -User delegate -Verbose - - This command removes permissions on all user-accessible folders in ALL Room mailboxes in the organization for the delegate. -.INPUTS - A mailbox identifier, permissions level and delegate identifier. -.OUTPUTS - Array of Mailbox address, Folder name and User. -#> - - [cmdletbinding(SupportsShouldProcess)] - - Param( - [Parameter(Mandatory=$true,ValueFromPipeline=$false)][ValidateNotNullOrEmpty()][Alias("Identity")][String[]]$Mailbox, - [Parameter(Mandatory=$true,ValueFromPipeline=$false)][ValidateNotNullOrEmpty()][Alias("Delegate")][String[]]$User, - [Parameter(Mandatory=$false)]$ParentFolderPath, - [switch]$Quiet) - - -#region BEGIN - #Make sure we are connected to Exchange Remote PowerShell - Write-Verbose "Checking connectivity to Exchange Remote PowerShell..." - if (!$session -or ($session.State -ne "Opened")) { - try { $script:session = Get-PSSession -InstanceId (Get-AcceptedDomain | select -First 1).RunspaceId.Guid -ErrorAction Stop } - catch { Write-Error "No active Exchange Remote PowerShell session detected, please connect first. To connect to ExO: https://technet.microsoft.com/en-us/library/jj984289(v=exchg.160).aspx" -ErrorAction Stop } - } - - #Prepare the list of mailboxes - Write-Verbose "Parsing the Mailbox parameter..." - $SMTPAddresses = @{} - foreach ($mb in $Mailbox) { - Start-Sleep -Milliseconds 80 #Add some delay to avoid throttling... - #Make sure a matching mailbox is found and return its Primary SMTP Address - $SMTPAddress = (Invoke-Command -Session $session -ScriptBlock { Get-Mailbox $using:mb | Select-Object -ExpandProperty PrimarySmtpAddress } -ErrorAction SilentlyContinue).Address - if (!$SMTPAddress) { if (!$Quiet) { Write-Warning "Mailbox with identifier $mb not found, skipping..." }; continue } - elseif (($SMTPAddress.count -gt 1) -or ($SMTPAddresses[$mb]) -or ($SMTPAddresses.ContainsValue($SMTPAddress))) { Write-Warning "Multiple mailboxes matching the identifier $mb found, skipping..."; continue } - else { $SMTPAddresses[$mb] = $SMTPAddress } - } - if (!$SMTPAddresses -or ($SMTPAddresses.Count -eq 0)) { Throw "No matching mailboxes found, check the parameter values." } - Write-Verbose "The following list of mailboxes will be used: ""$($SMTPAddresses.Values -join ", ")""" - - #Prepare the list of users (security principals) - Write-Verbose "Parsing the User parameter..." - $GUIDs = @{} - foreach ($us in $User) { - if ($us -match "^(Default|Anonymous|Owner@local|Member@local)$") { continue } #Cannot remove default permissions - - Start-Sleep -Milliseconds 80 #Add some delay to avoid throttling... - #Make sure a matching security principal object is found and return its GUID - $GUID = (Invoke-Command -Session $session -ScriptBlock { Get-SecurityPrincipal $using:us | Select-Object -ExpandProperty Guid } -ErrorAction SilentlyContinue).Guid - if (!$GUID) { if (!$Quiet) { Write-Warning "Security principal with identifier $us not found, skipping..." }; continue } - elseif (($GUID.count -gt 1) -or ($GUIDs[$us]) -or ($GUIDs.ContainsValue($GUID))) { Write-Warning "Multiple principals matching the identifier $us found, skipping..."; continue } - else { $GUIDs[$us] = $GUID } - } - if (!$GUIDs -or ($GUIDs.Count -eq 0)) { Throw "No matching security principals found, check the parameter values." } - Write-Verbose "The following list of security principals will be used: ""$($GUIDs.Values -join ", ")""" - Write-Verbose "List of default folder TYPES that will be used: ""$($includedfolders -join ", ")""" - Write-Verbose "List of folder NAMES that will be excluded: ""$($excludedfolders -join ", ")""" -#endregion - -#region PROCESS - $out = @() - foreach ($smtp in $SMTPAddresses.Values) {#should be unique, if needed select/sort - Write-Verbose "Processing mailbox ""$smtp""..." - Start-Sleep -Milliseconds 800 #Add some delay to avoid throttling... - Write-Verbose "Obtaining folder list for mailbox ""$smtp""..." - if($PSBoundParameters.ContainsKey('ParentFolderPath')) {$folders = ReturnFolderList $smtp $ParentFolderPath} - else { $folders = ReturnFolderList $smtp } - Write-Verbose "A total of $($folders.count) folders found for $($smtp)." - - if (!$folders) { Write-Verbose "No matching folders found for $($smtp), skipping..." ; continue } - - #Cycle over each folder we are interested in - foreach ($folder in $folders) { - #"Fix" for folders with "/" characters, treat the Root folder separately - if ($folder.FolderType -eq "Root") { $foldername = $smtp } - else { $foldername = $folder.Identity.ToString().Replace([char]63743,"/").Replace($smtp,$smtp + ":") } - - #Add/Set the folder permissions for each delegate - Write-Verbose "Processing folder ""$foldername""..." - foreach ($u in $GUIDs.Clone().GetEnumerator()) {#Use .Clone() in order to be able to dynamically remove entries if needed... - try { - Write-Verbose "Removing permissions on ""$foldername"" for principal ""$($u.Name)""." - Invoke-Command -Session $session -ScriptBlock { Remove-MailboxFolderPermission -Identity $Using:foldername -User $Using:u.Value -WhatIf:$using:WhatIfPreference -Confirm:$false } -ErrorAction Stop -HideComputerName - $outtemp = New-Object psobject -Property ([ordered]@{"Mailbox" = $smtp;"FolderName" = $folder.name;"User" = $u.Name}) - $out += $outtemp; if (!$Quiet -and !$WhatIfPreference) { $outtemp } #Write output to the console unless the -Quiet parameter is used - } - catch [System.Management.Automation.RemoteException] { - if ($_.CategoryInfo.Reason -eq "UserNotFoundInPermissionEntryException") { - if (!$Quiet) { Write-Host "WARNING: No existing permissions entry found on ""$foldername"" for principal ""$($u.Name)""" -ForegroundColor Yellow } - } - elseif ($_.CategoryInfo.Reason -eq "CannotChangePermissionsOnFolderException") { Write-Host "ERROR: Folder permissions for ""$foldername"" CANNOT be changed!" -ForegroundColor Red } - elseif ($_.CategoryInfo.Reason -eq "CannotRemoveSpecialUserException") { Write-Host "ERROR: Folder permissions for ""$($u.Name)"" CANNOT be changed!" -ForegroundColor Red } - elseif ($_.CategoryInfo.Reason -eq "ManagementObjectNotFoundException") { Write-Host "ERROR: Folder ""$foldername"" not found, this should not happen..." -ForegroundColor Red } - elseif ($_.CategoryInfo.Reason -eq "InvalidInternalUserIdException") { - Write-Host "ERROR: ""$($u.Name)"" is not a valid security principal for folder-level permissions, removing from list..." -ForegroundColor Red - $GUIDs.Remove($u.Name) - if ($GUIDs.Count) { continue } else { Write-Verbose "No valid security principals for folder-level permissions remaining, exiting the script..." ; return $out | Out-Default } - } - else {$_ | fl * -Force; continue} #catch-all for any unhandled errors - } - catch {$_ | fl * -Force; continue} #catch-all for any unhandled errors - } - - }} -#endregion - if ($out) { - Write-Verbose "Exporting results to the CSV file..." - $out | Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_MailboxFolderPermissionsRemoved.csv" -NoTypeInformation -Encoding UTF8 -UseCulture - if (!$Quiet -and !$WhatIfPreference) { return $out | Out-Default } #Write output to the console unless the -Quiet parameter is used - } - else { Write-Verbose "Output is empty, skipping the export to CSV file..." } - Write-Verbose "Finish..." -} - -#Invoke the Remove-MailboxFolderPermissionsRecursive function and pass the command line parameters. Make sure the output is stored in a variable for reuse, even if not specified in the input! -if ($PSBoundParameters.Count -and $PSBoundParameters.Keys -notmatch "WhatIf|Verbose|ErrorAction|ErrorVariable|Confirm|Debug|WarningAction|WarningVariable|InformationAction|InformationVariable|OutVariable|OutBuffer|PipelineVariable") { - Remove-MailboxFolderPermissionsRecursive @PSBoundParameters -OutVariable global:varFolderPermissionsRemoved -} -else { Write-Host "INFO: The script was run without parameters, consider dot-sourcing it instead." -ForegroundColor Cyan } +#Requires -Version 3.0 +[CmdletBinding(SupportsShouldProcess)] #Make sure we can use -WhatIf and -Verbose +Param([switch]$Quiet,[ValidateNotNullOrEmpty()][Alias("Identity")][String[]]$Mailbox,[ValidateNotNullOrEmpty()][Alias("Delegate")][String[]]$User,[Parameter(Mandatory=$false)][String]$ParentFolderPath) + +#Include these folder types by default +$includedfolders = @("Root","Inbox","Calendar", "Contacts", "DeletedItems", "Drafts", "JunkEmail", "Journal", "Notes", "Outbox", "SentItems", "Tasks", "CommunicatorHistory", "Clutter", "Archive") +#$includedfolders = @("Root","Inbox","Calendar", "Contacts", "DeletedItems", "SentItems", "Tasks") #Trimmed down list of default folders + +#Exclude additional Non-default folders created by Outlook or other mail programs. Folder NAMES, not types! So make sure to include translations too! +#Exclude SearchDiscoveryHoldsFolder and SearchDiscoveryHoldsUnindexedItemFolder as they're not marked as default folders #Exclude "Calendar Logging" on older Exchange versions +$excludedfolders = @("News Feed","Quick Step Settings","Social Activity Notifications","Suggested Contacts", "SearchDiscoveryHoldsUnindexedItemFolder", "SearchDiscoveryHoldsFolder","Calendar Logging") + +try { $script:session = Get-PSSession -InstanceId (Get-AcceptedDomain | select -First 1).RunspaceId.Guid -ErrorAction Stop } +catch { Write-Error "No active Exchange Remote PowerShell session detected, please connect first. To connect to ExO: https://technet.microsoft.com/en-us/library/jj984289(v=exchg.160).aspx" -ErrorAction Stop } + +function ReturnFolderList { +<# +.Synopsis + Enumerates all user-accessible folders for the mailbox +.DESCRIPTION + The ReturnFolderList cmdlet enumerates the folders for the given mailbox. To adjust the list of folders, add to the $includedfolders or $excludedfolders array, respectively. +.PARAMETER SMTPAddress + Use the -SMTPAddress parameter to designate the mailbox where the desired folders reside +.PARAMETER ParentFolderPath + Use the -ParentFolderPath to designate a starting point for listing folders. For instance, use "/Inbox/From Accounting/" to get all subfolders of the 'From Accounting folder in your Inbox. +.EXAMPLE + ReturnFolderList user@domain.com + + This command will return a list of all user-accessible folders for the user@domain.com mailbox. +.INPUTS + SMTP address of the mailbox, with optional parent folder (full path). +.OUTPUTS + Array with information about the mailbox folders. +#> + + param([Parameter(Mandatory=$true, ValueFromPipeline=$true)]$SMTPAddress,[Parameter(Mandatory=$false)][String]$ParentFolderPath) + + if (!$session -or ($session.State -ne "Opened")) { Write-Error "No active Exchange Remote PowerShell session detected, please connect first. To connect to ExO: https://technet.microsoft.com/en-us/library/jj984289(v=exchg.160).aspx" -ErrorAction Stop } + + $MBfolders = Invoke-Command -Session $session -ScriptBlock { Get-MailboxFolderStatistics $using:SMTPAddress | Select-Object Name,FolderType,Identity,FolderPath } -HideComputerName -ErrorAction Stop + if($PSBoundParameters.ContainsKey('ParentFolderPath')) { + $MBfolders = $MBfolders | ? {($_.FolderType -eq "User created" -or $_.FolderType -in $includedfolders) -and ($_.Name -notin $excludedfolders) -and ($_.FolderPath -match $ParentFolderPath+"*")} + } + else { + $MBfolders = $MBfolders | ? {($_.FolderType -eq "User created" -or $_.FolderType -in $includedfolders) -and ($_.Name -notin $excludedfolders)} + } + + if (!$MBfolders) { return } + else { return ($MBfolders | select Name,FolderType,Identity) } +} + + +function Remove-MailboxFolderPermissionsRecursive { +<# +.Synopsis + Removes permissions for all user-accessible folders for a given mailbox. +.DESCRIPTION + The Remove-MailboxFolderPermissionsRecursive cmdlet removes permissions for all user-accessible folders for the given mailbox(es), specified via the -Mailbox parameter. The list of folders is generated via the ReturnFolderList function. Configure the $includedfolders and $excludedfolders variables to granularly control the folder list. +.PARAMETER Mailbox + Use the -Mailbox parameter to designate the mailbox. Any valid Exchange mailbox identifier can be specified. Multiple mailboxes can be specified in a comma-separated list or array, see examples below. +.PARAMETER User + Use the -User parameter to designate the delegate. Any valid Exchange security principal identifier can be specified. Multiple delegates can be specified in a comma-separated list or array, see examples below. +.PARAMETER ParentFolderPath + Use the -ParentFolderPath to designate a starting point for listing folders. For instance, use "/Inbox/From Accounting/" to get all subfolders of the 'From Accounting folder in your Inbox. +.PARAMETER Quiet + Use the -Quiet switch if you want to suppress output to the console. +.PARAMETER WhatIf + The -WhatIf switch simulates the actions of the command. You can use this switch to view the changes that would occur without actually applying those changes. +.PARAMETER Verbose + The -Verbose switch provides additional details on the cmdlet progress, it can be useful when troubleshooting issues. +.EXAMPLE + Remove-MailboxFolderPermissionsRecursive -Mailbox user@domain.com -User delegate@domain.com + + This command removes permissions on all user-accessible folders in the user@domain.com mailbox for the delegate@domain.com delegate. +.EXAMPLE + Remove-MailboxFolderPermissionsRecursive -Mailbox shared@domain.com,room@domain.com -User delegate@domain.com + + This command removes permissions on all user-accessible folders in BOTH the room@domain.com and shared@domain.com mailboxes for the delegate@domain.com delegate. +.EXAMPLE + Remove-MailboxFolderPermissionsRecursive -Mailbox (Get-Mailbox -RecipientTypeDetails RoomMailbox) -User delegate -Verbose + + This command removes permissions on all user-accessible folders in ALL Room mailboxes in the organization for the delegate. +.INPUTS + A mailbox identifier, permissions level and delegate identifier. +.OUTPUTS + Array of Mailbox address, Folder name and User. +#> + + [cmdletbinding(SupportsShouldProcess)] + + Param( + [Parameter(Mandatory=$true,ValueFromPipeline=$false)][ValidateNotNullOrEmpty()][Alias("Identity")][String[]]$Mailbox, + [Parameter(Mandatory=$true,ValueFromPipeline=$false)][ValidateNotNullOrEmpty()][Alias("Delegate")][String[]]$User, + [Parameter(Mandatory=$false)]$ParentFolderPath, + [switch]$Quiet) + + +#region BEGIN + #Make sure we are connected to Exchange Remote PowerShell + Write-Verbose "Checking connectivity to Exchange Remote PowerShell..." + if (!$session -or ($session.State -ne "Opened")) { + try { $script:session = Get-PSSession -InstanceId (Get-AcceptedDomain | select -First 1).RunspaceId.Guid -ErrorAction Stop } + catch { Write-Error "No active Exchange Remote PowerShell session detected, please connect first. To connect to ExO: https://technet.microsoft.com/en-us/library/jj984289(v=exchg.160).aspx" -ErrorAction Stop } + } + + #Prepare the list of mailboxes + Write-Verbose "Parsing the Mailbox parameter..." + $SMTPAddresses = @{} + foreach ($mb in $Mailbox) { + Start-Sleep -Milliseconds 80 #Add some delay to avoid throttling... + #Make sure a matching mailbox is found and return its Primary SMTP Address + $SMTPAddress = (Invoke-Command -Session $session -ScriptBlock { Get-Mailbox $using:mb | Select-Object -ExpandProperty PrimarySmtpAddress } -ErrorAction SilentlyContinue).Address + if (!$SMTPAddress) { if (!$Quiet) { Write-Warning "Mailbox with identifier $mb not found, skipping..." }; continue } + elseif (($SMTPAddress.count -gt 1) -or ($SMTPAddresses[$mb]) -or ($SMTPAddresses.ContainsValue($SMTPAddress))) { Write-Warning "Multiple mailboxes matching the identifier $mb found, skipping..."; continue } + else { $SMTPAddresses[$mb] = $SMTPAddress } + } + if (!$SMTPAddresses -or ($SMTPAddresses.Count -eq 0)) { Throw "No matching mailboxes found, check the parameter values." } + Write-Verbose "The following list of mailboxes will be used: ""$($SMTPAddresses.Values -join ", ")""" + + #Prepare the list of users (security principals) + Write-Verbose "Parsing the User parameter..." + $GUIDs = @{} + foreach ($us in $User) { + if ($us -match "^(Default|Anonymous|Owner@local|Member@local)$") { continue } #Cannot remove default permissions + + Start-Sleep -Milliseconds 80 #Add some delay to avoid throttling... + #Make sure a matching security principal object is found and return its GUID + $GUID = (Invoke-Command -Session $session -ScriptBlock { Get-SecurityPrincipal $using:us | Select-Object -ExpandProperty Guid } -ErrorAction SilentlyContinue).Guid + if (!$GUID) { if (!$Quiet) { Write-Warning "Security principal with identifier $us not found, skipping..." }; continue } + elseif (($GUID.count -gt 1) -or ($GUIDs[$us]) -or ($GUIDs.ContainsValue($GUID))) { Write-Warning "Multiple principals matching the identifier $us found, skipping..."; continue } + else { $GUIDs[$us] = $GUID } + } + if (!$GUIDs -or ($GUIDs.Count -eq 0)) { Throw "No matching security principals found, check the parameter values." } + Write-Verbose "The following list of security principals will be used: ""$($GUIDs.Values -join ", ")""" + Write-Verbose "List of default folder TYPES that will be used: ""$($includedfolders -join ", ")""" + Write-Verbose "List of folder NAMES that will be excluded: ""$($excludedfolders -join ", ")""" +#endregion + +#region PROCESS + $out = @() + foreach ($smtp in $SMTPAddresses.Values) {#should be unique, if needed select/sort + Write-Verbose "Processing mailbox ""$smtp""..." + Start-Sleep -Milliseconds 800 #Add some delay to avoid throttling... + Write-Verbose "Obtaining folder list for mailbox ""$smtp""..." + if($PSBoundParameters.ContainsKey('ParentFolderPath')) {$folders = ReturnFolderList $smtp $ParentFolderPath} + else { $folders = ReturnFolderList $smtp } + Write-Verbose "A total of $($folders.count) folders found for $($smtp)." + + if (!$folders) { Write-Verbose "No matching folders found for $($smtp), skipping..." ; continue } + + #Cycle over each folder we are interested in + foreach ($folder in $folders) { + #"Fix" for folders with "/" characters, treat the Root folder separately + if ($folder.FolderType -eq "Root") { $foldername = $smtp } + else { $foldername = $folder.Identity.ToString().Replace([char]63743,"/").Replace($smtp,$smtp + ":") } + + #Add/Set the folder permissions for each delegate + Write-Verbose "Processing folder ""$foldername""..." + foreach ($u in $GUIDs.Clone().GetEnumerator()) {#Use .Clone() in order to be able to dynamically remove entries if needed... + try { + Write-Verbose "Removing permissions on ""$foldername"" for principal ""$($u.Name)""." + Invoke-Command -Session $session -ScriptBlock { Remove-MailboxFolderPermission -Identity $Using:foldername -User $Using:u.Value -WhatIf:$using:WhatIfPreference -Confirm:$false } -ErrorAction Stop -HideComputerName + $outtemp = New-Object psobject -Property ([ordered]@{"Mailbox" = $smtp;"FolderName" = $folder.name;"User" = $u.Name}) + $out += $outtemp; if (!$Quiet -and !$WhatIfPreference) { $outtemp } #Write output to the console unless the -Quiet parameter is used + } + catch [System.Management.Automation.RemoteException] { + if ($_.CategoryInfo.Reason -eq "UserNotFoundInPermissionEntryException") { + if (!$Quiet) { Write-Host "WARNING: No existing permissions entry found on ""$foldername"" for principal ""$($u.Name)""" -ForegroundColor Yellow } + } + elseif ($_.CategoryInfo.Reason -eq "CannotChangePermissionsOnFolderException") { Write-Host "ERROR: Folder permissions for ""$foldername"" CANNOT be changed!" -ForegroundColor Red } + elseif ($_.CategoryInfo.Reason -eq "CannotRemoveSpecialUserException") { Write-Host "ERROR: Folder permissions for ""$($u.Name)"" CANNOT be changed!" -ForegroundColor Red } + elseif ($_.CategoryInfo.Reason -eq "ManagementObjectNotFoundException") { Write-Host "ERROR: Folder ""$foldername"" not found, this should not happen..." -ForegroundColor Red } + elseif ($_.CategoryInfo.Reason -eq "InvalidInternalUserIdException") { + Write-Host "ERROR: ""$($u.Name)"" is not a valid security principal for folder-level permissions, removing from list..." -ForegroundColor Red + $GUIDs.Remove($u.Name) + if ($GUIDs.Count) { continue } else { Write-Verbose "No valid security principals for folder-level permissions remaining, exiting the script..." ; return $out | Out-Default } + } + else {$_ | fl * -Force; continue} #catch-all for any unhandled errors + } + catch {$_ | fl * -Force; continue} #catch-all for any unhandled errors + } + + }} +#endregion + if ($out) { + Write-Verbose "Exporting results to the CSV file..." + $out | Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_MailboxFolderPermissionsRemoved.csv" -NoTypeInformation -Encoding UTF8 -UseCulture + if (!$Quiet -and !$WhatIfPreference) { return $out | Out-Default } #Write output to the console unless the -Quiet parameter is used + } + else { Write-Verbose "Output is empty, skipping the export to CSV file..." } + Write-Verbose "Finish..." +} + +#Invoke the Remove-MailboxFolderPermissionsRecursive function and pass the command line parameters. Make sure the output is stored in a variable for reuse, even if not specified in the input! +if ($PSBoundParameters.Count -and $PSBoundParameters.Keys -notmatch "WhatIf|Verbose|ErrorAction|ErrorVariable|Confirm|Debug|WarningAction|WarningVariable|InformationAction|InformationVariable|OutVariable|OutBuffer|PipelineVariable") { + Remove-MailboxFolderPermissionsRecursive @PSBoundParameters -OutVariable global:varFolderPermissionsRemoved +} +else { Write-Host "INFO: The script was run without parameters, consider dot-sourcing it instead." -ForegroundColor Cyan } \ No newline at end of file diff --git a/Remove_User_All_Groups.ps1 b/Remove_User_All_Groups.ps1 index 07fa248..4341332 100644 --- a/Remove_User_All_Groups.ps1 +++ b/Remove_User_All_Groups.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Add switch to handle situations where the user is the only owner of a Group? [CmdletBinding(SupportsShouldProcess)] #Make sure we can use -WhatIf and -Verbose Param([ValidateNotNullOrEmpty()][Alias("UserToRemove")][String[]]$Identity,[switch]$IncludeAADSecurityGroups,[switch]$IncludeOffice365Groups) @@ -24,7 +24,7 @@ function Check-Connectivity { #IF using the SG parameter if ($IncludeAADSecurityGroups) { Write-Verbose "Checking connectivity to Azure AD..." - if (!(Get-Module AzureAD -ListAvailable -Verbose:$false | ? {($_.Version.Major -eq 2 -and $_.Version.Build -eq 2 -and $_.Version.Revision -gt 55) -or ($_.Version.Major -eq 2 -and $_.Version.Build -eq 1)})) { Write-Host -BackgroundColor Red "This script requires a recent version of the AzureAD PowerShell module. Download it here: https://www.powershellgallery.com/packages/AzureAD/"; return} + if (!(Get-Module AzureAD -ListAvailable -Verbose:$false | ? {($_.Version.Major -eq 2 -and $_.Version.Build -eq 0 -and $_.Version.Revision -gt 55) -or ($_.Version.Major -eq 2 -and $_.Version.Build -eq 1)})) { Write-Host -BackgroundColor Red "This script requires a recent version of the AzureAD PowerShell module. Download it here: https://www.powershellgallery.com/packages/AzureAD/"; return} try { Get-AzureADCurrentSessionInfo -ErrorAction Stop -WhatIf:$false -Verbose:$false | Out-Null } catch { try { Connect-AzureAD -WhatIf:$false -Verbose:$false -ErrorAction Stop | Out-Null } catch { return $false } } } @@ -183,5 +183,5 @@ This parameter accepts the following values: #Invoke the Remove-MailboxFolderPermissionsRecursive function and pass the command line parameters. Make sure the output is stored in a variable for reuse, even if not specified in the input! -if (($PSBoundParameters | measure).count) { Remove-UserFromAllGroups @PSBoundParameters } -else { Write-Host "INFO: The script was run without parameters, consider dot-sourcing it instead." -ForegroundColor Cyan } +if ($PSBoundParameters.Count -ne 0) { Remove-UserFromAllGroups @PSBoundParameters } +else { Write-Host "INFO: The script was run without parameters, consider dot-sourcing it instead." -ForegroundColor Cyan ; return } \ No newline at end of file diff --git a/Remove_User_All_GroupsV2.ps1 b/Remove_User_All_GroupsV2.ps1 index c8a7cd7..7214e95 100644 --- a/Remove_User_All_GroupsV2.ps1 +++ b/Remove_User_All_GroupsV2.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Requires -Modules @{ ModuleName="ExchangeOnlineManagement"; ModuleVersion="3.0.0" } #Requires -Modules @{ ModuleName="Microsoft.Graph.Groups"; ModuleVersion="1.19.0" } #Requires -Modules @{ ModuleName="Microsoft.Graph.Users"; ModuleVersion="1.19.0" } @@ -121,7 +121,8 @@ This parameter accepts the following values: foreach ($us in $Identity) { Start-Sleep -Milliseconds 80 #Add some delay to avoid throttling... #Make sure a matching user object is found and return its DN. While we can handle other object type easily on Exchange side, on AAD side we need additional cmdlets, checks, etc... - $GUID = Get-User $us -Filter {RecipientType -eq 'User' -or RecipientType -eq 'UserMailbox' -or RecipientType -eq 'MailUser'} | Select-Object DistinguishedName,ExternalDirectoryObjectId #silence these errors or? + #$GUID = Get-User $us -Filter {RecipientType -eq 'User' -or RecipientType -eq 'UserMailbox' -or RecipientType -eq 'MailUser'} | Select-Object DistinguishedName,ExternalDirectoryObjectId #silence these errors or? + $GUID = Get-User $us | Select-Object DistinguishedName,ExternalDirectoryObjectId #silence these errors or? if (!$GUID) { Write-Verbose "Security principal with identifier $us not found, skipping..."; continue } elseif (($GUID.count -gt 1) -or ($GUIDs[$us]) -or ($GUIDs.ContainsValue($GUID))) { Write-Verbose "Multiple users matching the identifier $us found, skipping..."; continue } else { $GUIDs[$us] = $GUID | Select-Object DistinguishedName,ExternalDirectoryObjectId } @@ -184,7 +185,7 @@ This parameter accepts the following values: } #Handle Azure AD security groups - if ($IncludeAADSecurityGroups) { + if ($IncludeAADSecurityGroups -and $user.value.ExternalDirectoryObjectId) { #Some Exchange recipients will have empty ExternalDirectoryObjectId value, skip them Write-Verbose "Obtaining security group list for user ""$($user.Name)""..." $GroupsAD = Get-MgUserMemberOf -UserId $($user.value.ExternalDirectoryObjectId) -All -Filter {securityEnabled eq true and mailEnabled eq false} -ConsistencyLevel eventual -CountVariable count -Property id,displayName,mailEnabled,securityEnabled,membershipRule,mail,isAssignableToRole,groupTypes diff --git a/Remove_User_MBpermissions.ps1 b/Remove_User_MBpermissions.ps1 index e3b49e2..aa324fa 100644 --- a/Remove_User_MBpermissions.ps1 +++ b/Remove_User_MBpermissions.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 [CmdletBinding(SupportsShouldProcess)] #Make sure we can use -WhatIf and -Verbose Param([ValidateNotNullOrEmpty()][Alias("UserToRemove")][String[]]$Identity,[switch]$IncludeSharedMailboxes,[switch]$IncludeResourceMailboxes) diff --git a/Report_Team_Sites.ps1 b/Report_Team_Sites.ps1 index 1acc9bc..a547ed2 100644 --- a/Report_Team_Sites.ps1 +++ b/Report_Team_Sites.ps1 @@ -1,4 +1,4 @@ -$AppId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" +$AppId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" $client_secret = Get-Content .\ReportingAPIsecret.txt | ConvertTo-SecureString $app_cred = New-Object System.Management.Automation.PsCredential($AppId, $client_secret) $TenantId = "tenant.onmicrosoft.com" diff --git a/Report_Teams_Apps.ps1 b/Report_Teams_Apps.ps1 index 07d8fc6..bed127d 100644 --- a/Report_Teams_Apps.ps1 +++ b/Report_Teams_Apps.ps1 @@ -1,6 +1,6 @@ -#Variables to configure +#Variables to configure $tenantID = "tenant.onmicrosoft.com" #your tenantID or tenant root domain -$appID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" #the GUID of your app. For best result, use app with Team.ReadBasic.All, TeamsAppInstallation.ReadForTeam.All and TeamsTab.Read.All scopes granted. +$appID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" #the GUID of your app. For best result, use app with TeamsAppInstallation.ReadForTeam.All and TeamsTab.Read.All scopes granted. $client_secret = "verylongsecurestring" #client secret for the app #Prepare token request @@ -100,4 +100,4 @@ foreach ($team in $Teams) { #Export the result $ReportApps | select * -ExcludeProperty Number | Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_TeamsAppsReport.csv" -NoTypeInformation -Encoding UTF8 -UseCulture -$ReportTabs | select * -ExcludeProperty Number | Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_TeamsTabsReport.csv" -NoTypeInformation -Encoding UTF8 -UseCulture +$ReportTabs | select * -ExcludeProperty Number | Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_TeamsTabsReport.csv" -NoTypeInformation -Encoding UTF8 -UseCulture \ No newline at end of file diff --git a/Reset_Folder_Permissions_recursive_BULK.ps1 b/Reset_Folder_Permissions_recursive_BULK.ps1 index 277a80e..d8dd32d 100644 --- a/Reset_Folder_Permissions_recursive_BULK.ps1 +++ b/Reset_Folder_Permissions_recursive_BULK.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 [CmdletBinding(SupportsShouldProcess)] #Make sure we can use -WhatIf and -Verbose Param([switch]$Quiet,[ValidateNotNullOrEmpty()][Alias("Identity")][String[]]$Mailbox,[switch]$ResetDefaultLevel) diff --git a/Role_assignments_Inventory.ps1 b/Role_assignments_Inventory.ps1 index f94722f..d33558f 100644 --- a/Role_assignments_Inventory.ps1 +++ b/Role_assignments_Inventory.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 [CmdletBinding()] #Make sure we can use -Verbose Param([switch]$IncludeRoleGroups,[switch]$IncludeUnassignedRoleGroups,[switch]$IncludeDelegatingAssingments) @@ -155,7 +155,7 @@ if ($IncludeRoleGroups -and $IncludeUnassignedRoleGroups) { } #Dump the raw output to a CSV file -$output | Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_RoleAssignments.csv" -NoTypeInformation -Encoding UTF8 -UseCulture +$output #| Export-Csv -Path "$((Get-Date).ToString('yyyy-MM-dd_HH-mm-ss'))_RoleAssignments.csv" -NoTypeInformation -Encoding UTF8 -UseCulture #Transform the output and return it to the console. Group assignments by individual user/group $global:varRoleAssignments = $output | group Assignee | select @{n="DisplayName";e={($_.Group.AssigneeName | sort -Unique)}},@{n="Identifier";e={$_.Name}},@{n="ObjectType";e={($_.Group.AssigneeType | sort -Unique) -join ","}},@{n="AssignmentType";e={($_.Group.AssignmentType | sort -Unique) -join ","}},@{n="Roles";e={($_.Group.AssignedRoles | sort -Unique) -join ","}} | sort DisplayName diff --git a/Set_Folder_Permissions_recursive_BULK.ps1 b/Set_Folder_Permissions_recursive_BULK.ps1 index d113a81..8d2e145 100644 --- a/Set_Folder_Permissions_recursive_BULK.ps1 +++ b/Set_Folder_Permissions_recursive_BULK.ps1 @@ -1,7 +1,9 @@ #Requires -Version 3.0 +#Update to V3 +#Merge changes from GitHub! [CmdletBinding(SupportsShouldProcess)] #Make sure we can use -WhatIf and -Verbose Param( -[switch]$Quiet,[ValidateNotNullOrEmpty()][Alias("Identity")][String[]]$Mailbox,[ValidateNotNullOrEmpty()][Alias("Delegate")][String[]]$User,[Parameter(Mandatory=$false)][String]$ParentFolderPath, +[switch]$Quiet,[ValidateNotNullOrEmpty()][Alias("Identity")][String[]]$Mailbox,[ValidateNotNullOrEmpty()][Alias("Delegate")][String[]]$User, [ValidateSet("None","Owner","PublishingEditor","Editor","PublishingAuthor","Author","NoneditingAuthor","Reviewer","Contributor","FreeBusyTimeOnly","FreeBusyTimeAndSubjectAndLocation", "Custom","CreateItems","CreateSubfolders","DeleteAllItems","DeleteOwnedItems","EditAllItems","EditOwnedItems","FolderContact","FolderOwner","FolderVisible","ReadItems")] [ValidateNotNullOrEmpty()][String[]]$AccessRights) @@ -23,32 +25,22 @@ function ReturnFolderList { Enumerates all user-accessible folders for the mailbox .DESCRIPTION The ReturnFolderList cmdlet enumerates the folders for the given mailbox. To adjust the list of folders, add to the $includedfolders or $excludedfolders array, respectively. -.PARAMETER SMTPAddress - Use the -SMTPAddress parameter to designate the mailbox where the desired folders reside -.PARAMETER ParentFolderPath - Use the -ParentFolderPath to designate a starting point for listing folders. For instance, use "/Inbox/From Accounting/" to get all subfolders of the 'From Accounting folder in your Inbox. .EXAMPLE ReturnFolderList user@domain.com + This command will return a list of all user-accessible folders for the user@domain.com mailbox. .INPUTS - SMTP address of the mailbox, with optional parent folder (full path). + SMTP address of the mailbox. .OUTPUTS Array with information about the mailbox folders. #> - param( - [Parameter(Mandatory=$true, ValueFromPipeline=$true)]$SMTPAddress, - [Parameter(Mandatory=$false)]$ParentFolderPath) + param([Parameter(Mandatory=$true, ValueFromPipeline=$true)]$SMTPAddress) if (!$session -or ($session.State -ne "Opened")) { Write-Error "No active Exchange Remote PowerShell session detected, please connect first. To connect to ExO: https://technet.microsoft.com/en-us/library/jj984289(v=exchg.160).aspx" -ErrorAction Stop } - $MBfolders = Invoke-Command -Session $session -ScriptBlock { Get-MailboxFolderStatistics $using:SMTPAddress | Select-Object Name,FolderType,FolderPath,Identity } -HideComputerName -ErrorAction Stop - if($PSBoundParameters.ContainsKey('ParentFolderPath')) { - $MBfolders = $MBfolders | ? {($_.FolderType -eq "User created" -or $_.FolderType -in $includedfolders) -and ($_.Name -notin $excludedfolders) -and ($_.FolderPath -match $ParentFolderPath+"*")} - } - else { - $MBfolders = $MBfolders | ? {($_.FolderType -eq "User created" -or $_.FolderType -in $includedfolders) -and ($_.Name -notin $excludedfolders)} - } + $MBfolders = Invoke-Command -Session $session -ScriptBlock { Get-MailboxFolderStatistics $using:SMTPAddress | Select-Object Name,FolderType,Identity } -HideComputerName -ErrorAction Stop + $MBfolders = $MBfolders | ? {($_.FolderType -eq "User created" -or $_.FolderType -in $includedfolders) -and ($_.Name -notin $excludedfolders)} if (!$MBfolders) { return } else { return ($MBfolders | select Name,FolderType,Identity) } @@ -65,8 +57,6 @@ function Set-MailboxFolderPermissionsRecursive { Use the -Mailbox parameter to designate the mailbox. Any valid Exchange mailbox identifier can be specified. Multiple mailboxes can be specified in a comma-separated list or array, see examples below. .PARAMETER User Use the -User parameter to designate the delegate. Any valid Exchange security principal identifier can be specified. Multiple delegates can be specified in a comma-separated list or array, see examples below. -.PARAMETER ParentFolderPath - Use the -ParentFolderPath to designate a starting point for listing folders. For instance, use "/Inbox/From Accounting/" to get all subfolders of the 'From Accounting folder in your Inbox. .PARAMETER AccessRights Use the -AccessRights parameter to specify the permission level to be granted. For list of accepted permissions see for example: https://docs.microsoft.com/en-us/powershell/module/exchange/mailboxes/add-mailboxfolderpermission?view=exchange-ps Roles have precedence over individual permissions entries. If an existing permission entry for the same User is detected, it will be updated to match the newly provided value. @@ -78,12 +68,15 @@ function Set-MailboxFolderPermissionsRecursive { The -Verbose switch provides additional details on the cmdlet progress, it can be useful when troubleshooting issues. .EXAMPLE Set-MailboxFolderPermissionsRecursive -Mailbox user@domain.com -User delegate@domain.com -AccessRights Editor + This command add Editor level permissions on all user-accessible folders in the user@domain.com mailbox for the delegate@domain.com delegate. .EXAMPLE Set-MailboxFolderPermissionsRecursive -Mailbox shared@domain.com,room@domain.com -User delegate@domain.com -AccessRights Owner + This command add Owner level permissions on all user-accessible folders in BOTH the room@domain.com and shared@domain.com mailboxes for the delegate@domain.com delegate. .EXAMPLE Set-MailboxFolderPermissionsRecursive -Mailbox (Get-Mailbox -RecipientTypeDetails RoomMailbox) -User delegate -AccessRights Owner -Verbose + This command add Owner level permissions on all user-accessible folders in ALL Room mailboxes in the organization for the delegate. .INPUTS A mailbox identifier, permissions level and delegate identifier. @@ -96,7 +89,6 @@ function Set-MailboxFolderPermissionsRecursive { Param( [Parameter(Mandatory=$true,ValueFromPipeline=$false)][ValidateNotNullOrEmpty()][Alias("Identity")][String[]]$Mailbox, [Parameter(Mandatory=$true,ValueFromPipeline=$false)][ValidateNotNullOrEmpty()][Alias("Delegate")][String[]]$User, - [Parameter(Mandatory=$false)]$ParentFolderPath, [Parameter(Mandatory=$true)][ValidateSet("None","Owner","PublishingEditor","Editor","PublishingAuthor","Author","NoneditingAuthor","Reviewer","Contributor","FreeBusyTimeOnly","FreeBusyTimeAndSubjectAndLocation", "Custom","CreateItems","CreateSubfolders","DeleteAllItems","DeleteOwnedItems","EditAllItems","EditOwnedItems","FolderContact","FolderOwner","FolderVisible","ReadItems")] [ValidateNotNullOrEmpty()][String[]]$AccessRights, @@ -161,8 +153,7 @@ function Set-MailboxFolderPermissionsRecursive { Write-Verbose "Processing mailbox ""$smtp""..." Start-Sleep -Milliseconds 800 #Add some delay to avoid throttling... Write-Verbose "Obtaining folder list for mailbox ""$smtp""..." - if($PSBoundParameters.ContainsKey('ParentFolderPath')) {$folders = ReturnFolderList $smtp $ParentFolderPath} - else { $folders = ReturnFolderList $smtp } + $folders = ReturnFolderList $smtp Write-Verbose "A total of $($folders.count) folders found for $($smtp)." if (!$folders) { Write-Verbose "No matching folders found for $($smtp), skipping..." ; continue } @@ -213,7 +204,7 @@ function Set-MailboxFolderPermissionsRecursive { } #Invoke the Set-MailboxFolderPermissionsRecursive function and pass the command line parameters. Make sure the output is stored in a variable for reuse, even if not specified in the input! -if ($PSBoundParameters.Count -and $PSBoundParameters.Keys -notmatch "WhatIf|Verbose|ErrorAction|ErrorVariable|Confirm|Debug|WarningAction|WarningVariable|InformationAction|InformationVariable|OutVariable|OutBuffer|PipelineVariable") { - Set-MailboxFolderPermissionsRecursive @PSBoundParameters -OutVariable global:varFolderPermissionsAdded -} +if ($PSBoundParameters.Count) { Set-MailboxFolderPermissionsRecursive @PSBoundParameters -OutVariable global:varFolderPermissionsAdded } else { Write-Host "INFO: The script was run without parameters, consider dot-sourcing it instead." -ForegroundColor Cyan } + +#Invoke-Command -Session $session -ScriptBlock { Remove-MailboxFolderPermission -Identity $Using:foldername -User $Using:u.Value -Confirm:$false } \ No newline at end of file diff --git a/app_Permissions_inventory_GraphAPI.ps1 b/app_Permissions_inventory_GraphAPI.ps1 index 468ddc4..25fc8e8 100644 --- a/app_Permissions_inventory_GraphAPI.ps1 +++ b/app_Permissions_inventory_GraphAPI.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Make sure to fill in all the required variables before running the script #Also make sure the AppID used corresponds to an app with sufficient permissions, as follows: # Directory.Read.All (hard-requirement for oauth2PermissionGrants, covers everything else needed) diff --git a/app_reg_Permissions_inventory_GraphAPI.ps1 b/app_reg_Permissions_inventory_GraphAPI.ps1 index 6f541ef..463d2d4 100644 --- a/app_reg_Permissions_inventory_GraphAPI.ps1 +++ b/app_reg_Permissions_inventory_GraphAPI.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 3.0 +#Requires -Version 3.0 #Make sure to fill in all the required variables before running the script #Also make sure the AppID used corresponds to an app with sufficient permissions, as follows: # Directory.Read.All