SharePoint Online: Get Site Owners list from all Sites

I have been asked to get list of all explicit user accounts  and group with site owner permissions for all sites. I wrote a script using Get-SPOSite, Get-SPOUsers and Get-SPOGroup commands.

To make it easier I wrote the script requires the mandatory parameter of Office 365 Tenant name. The script will create a CSV file on the script working (current) directory.


  • Install SharePoint Online Management Shell (Download it from
  • Copy or Create the script to the desired location (e.g., C:\Scripts).
  • Open PowerShell and change the working directory to the location where script is located
  • Run the script with parameter TenantName
  • When asked provide the SharePoint Administrator credentials

e.g.,  if the sharepoint admin URL is, then the tenant name is contoso.

.\SiteOwnersList.ps1 -TenantName contoso

Download the script from HERE.

You may also copy/paste the script in PowerShell ISE and save as SiteOwnersList.ps1.

***    Script Name: SiteOwnersList.ps1
***    Purpose: List all SharePoint Online sites and it’s Owners from the site permissions list (Users and Groups) and create the report to a CSV file.
***             The generated CSV file stored at PowerShell script running location (local directory)
***    Parameters: <TenantName> – provide your SharePoint Online (Office 365) Tenant Name (usually your domain name)
***    Written By: Anand, the awesome, Venkatachalapathy

param (  [Parameter(Mandatory=$True)]
[string]$TenantName )

#Form a SharePoint Admin URl
$AdminURL = “https://$tenantName” + “”

#Add SharePoint PowerShell Snap-in and Importing the SharePoint Online module
Add-PSSnapin microsoft.sharepoint.powershell -ErrorAction SilentlyContinue
Import-Module ‘C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell’ -DisableNameChecking

#Connect to SharePoint Online
Connect-SPOService -Url $AdminURL -Credential (Get-Credential)

#Headers for the data
“Site URL`tOwner`tUsers`tGroup`tGroup Members” | Out-File -FilePath .\SharePointSiteOwners.csv

#Get all Sites (Root sites only)
$sites = Get-SPOSite -Limit All

#Process all sites
foreach($site in $sites)
$siteURL = $site.Url
$siteOwner = $site.Owner

    Write-Host $siteURL -ForegroundColor Cyan
Write-Host $siteOwner -ForegroundColor Cyan

#Get all users with Site Owner permissions
$siteAdmins = Get-SPOUser -Site $siteURL -Limit All | select LoginName,IsSiteAdmin | ? { $_.ISSiteAdmin }

    #Collect all site owners (user accounts) to a variable $siteUsers
$siteUsers = “”
foreach($siteAdmin in $siteAdmins) { $siteUsers += $siteAdmin.LoginName + ” , ” }

    Write-Host $siteUsers -ForegroundColor Cyan

#Get all Groups from the site permissions
$sitegroups = Get-SPOSiteGroup -Site $siteURL

#Get Group info and members that have site owners permissions
foreach ($sitegroup in $sitegroups)
$i = 0
foreach($role in $sitegroup.Roles)
if ( $role.Contains(“Site Owner”) -or $role.Contains(“Full Control”) )
$i = $i + 1
Write-Host $sitegroup.Title -ForegroundColor “Yellow”
Write-Host $sitegroup.Users -ForegroundColor “Blue”

                if ($i -gt 1)
“`t`t`t” + $sitegroup.Title + “`t” + $sitegroup.Users | Out-File -FilePath .\SharePointSiteOwners.csv -Append
“$siteURL`t$siteOwner`t$siteUsers`t” + $sitegroup.Title + “`t” + $sitegroup.Users | Out-File -FilePath .\SharePointSiteOwners.csv -Append

***                                                                            The END


Search-ADAccount for disabled, expired, inactive accounts

What would be the easiest way to list disabled accounts, inactive accounts or expired accounts from AD. You could use Get-ADUser or Get-ADObject, but they are more complicated & dealing with User attributes.

I found Search-ADAccount, it’s been much easier and generating reports from AD on the fly pretty much. Search-ADAccount description and help is at HERE.

Here is the sample commands. Note the number of days is set to 90 days in these commands. Change the day from 90 to your suitable number. You can remove Export-Csv command to show the results in the PowerShell window.

  • Search AD for Inactive Computer Accounts for more than 90 days.

Search-ADAccount -ComputersOnly -AccountInactive | ? { $_.LastLogonDate -lt (get-date).AddDays(-90) } | Select-Object Name,LastLogonDate,DistinguishedName | Export-Csv -Path .\Inactive-Computers-morethan-90days.csv –NoTypeInformation

  • Search AD for Inactive User accounts for more than 90 days

Search-ADAccount -AccountInactive -UsersOnly | ? { $_.LastLogonDate -lt (get-date).AddDays(-90) } | Select-Object Name,SAMAccountName,LastLogonDate,Enabled,LockedOut,PasswordExpired | Export-Csv -Path .\Inactive-Users-morethan-90days.csv –NoTypeInformation

  • Search AD for Expired User accounts for more than 90 days

Search-ADAccount -AccountExpired -UsersOnly | Select-Object Name,SAMAccountName,AccountExpirationDate,LastLogonDate,DistinguishedName | Export-Csv -Path .\Expired-UserAccounts.csv –NoTypeInformation

I believe you get the idea. Tweak the cmdlet or filter to get more combination of reports.

Outlook removes line breaks, but Why?

When we type beautiful emails with some (apparently) extra lines (line breaks) to make the message more readable sometimes. And when it reaches the user, Outlook removes the extra lines and make the email real ugly. Then Outlook displays this message on top of the message window: We removed extra line breaks from this message.


You can restore the extra lines by clicking on that message and choose Restore line breaks.


To permanently disable Outlook to remove the line breaks, you have to go to Outlook Options in File/Outlook Options, under Mail section.  Scroll down and find Remove extra line breaks in plain text messages option under Message Format section.


Machine generated alternative text:

Exchange: Members can’t remove themselves from security groups. Please set the group to Closed…

It was interesting to see when I was trying to add a member to a “mail enabled” security group in Exchange Admin Center, I get this:


Oh! I was freaking add a member…what the?

Well, we have two options.

One: Add the member using Active Directory Users and Computer console. It is easy, but we are not fixing the under laying issue.  So the option two is necessary.

Two: Make the group closed so members can’t leave themselves (even freaking though nobody is trying to leave the group) so we don’t get above message. Open PowerShell and connect to your Exchange Server and use the following cmdlet to close the group.

Set-DistributionGroup <Group Name or Alias>  -MemberDepartRestriction Closed

Did it help? Leave me a reply.

List all authorized DHCP servers from Active Directory

Here is PowerShell command to list all authorized DHCP servers from Active Directory. Replace the DOMAIN and COM with your domain name in the command below.

Get-ADObject -SearchBase “cn=configuration,dc=DOMAIN,dc=COM” -Filter { ObjectClass -eq ‘dhcpclass’ } | Select-Object Name  | Format-Table –Wrap

I used format-table with wrap option to display full DHCP server name if it is long name.

If you browser the same location (in SearchBase in Get-ADObject cmdlet) in AD Sites and Services (with services option enabled), you will see the DHCP servers. This command list those DHCP servers, that’s all.

How to install unsigned driver (if you have to) in Windows 10?

If you tried to install a unsigned driver in Windows 10, you would hit the wall. There is no settings to allow unsigned drivers like in old Microsoft Operating Systems. This is the guide to show you how to enable unsigned drivers (& risk making Windows 10 unstable).

Follow the stops to enable the Unsigned Drivers in Startup Options:

1. Reboot the computer with these command

SHUTDOWN.exe /R /O /F /T 00

/R is for Reboot

/O is to reboot to options menu

/F is force the reboot

/T is timer – we set to reboot right away


2. After reboot to Options screen, Choose Troubleshoot.

3. In Troubleshoot screen, Choose Advanced Options

Image result for windows 10 troubleshoot screen -8

4. in Advanced Options screen, choose Startup Settings

5. In Startup Settings, Click Restart.

Image result for windows 10 Startup Settings -8

6. After reboot, click 7 or F7 to disable driver signature enforcement.

7. Selecting option results a reboot  one last time.

Now try installing that unsigned drivers.

Active Directory: Why the protected account permissions cannot be changed? what is AdminSDHolder?

If try anyone of the things below on accounts that is member of Domain Admins or Account Operators or any other protected groups, you know it can’t be done.

  • Changing permissions (add/remove/modify perms in security tab of the account properties window)
  • Enabling Permission Inheritance (to activate a ActiveSync account on the Administrator’s device)
  • Low-level admins (Account Operators) try to modify high-level admin accounts (e.g, Domain Admins, Enterprise Admins)

If you do any one of those actions above, it will be reset in 60 minutes automatically. The third action will be denied right away. Why is that? it’s because to protect the protected accounts from hacked. This feature first introduced in Active Directory in Windows 2000 Server. Here is detailed explanation from Microsoft.

Active Directory Domain Services uses AdminSDHolder, protected groups and Security Descriptor propagator (SD propagator or SDPROP for short) to secure privileged users and groups from unintentional modification. This functionality was introduced in the inaugural release of Active Directory in Windows 2000 Server and it’s fairly well known. However, virtually all IT administrators have been negatively impacted by this functionality, and that will to continue unless they fully understand how AdminSDHolder, protected groups and SDPROP work.
Each Active Directory domain has an object called AdminSDHolder, which resides in the System container of the domain. The AdminSDHolder object has a unique Access Control List (ACL), which is used to control the permissions of security principals that are members of built-in privileged Active Directory groups (what I like to call “protected” groups). Every hour, a background process runs on the domain controller that holds the PDC Emulator operations master role. It compares the ACL on all security principals (users, groups and computer accounts) that belong to protected groups against the ACL on the AdminSDHolder object. If the size or the binary string is different, the security descriptor on the object is overwritten by the security descriptor from the AdminSDHolder object..
As you can see, multiple layers of security are incorporated into this functionality. First, the permissions applied to users belonging to protected groups are more stringent than the default permissions applied onto other user accounts. Next, the default behaviour is that inheritance is disabled on these privileged accounts, ensuring that permissions applied at the parent level aren’t inherited by the protected objects, regardless of where they reside. Finally, the background process running every 60 minutes identifies manual modifications to an ACL and overwrites them so that the ACL matches the ACL on the AdminSDHolder object.

For more information check HERE.