I work for an MSP and am trying to use PowerShell version 5 to make some changes to our clients' Microsoft 365 tenants. I've set up an app registration for this purpose, assigned it the permissions needed, and had the client tenants provide consent for it.
The script I am trying to run now is supposed to cycle through each tenant, get a list of its domains, then create a new anti-phishing policy and rule.
The script works until it gets to the $organizationDomains variable, which gives me the error "The remote server returned an error: (401) Unauthorized."
Here is the code:
########## Microsoft 365 login ##########
Connect-MsolService
Connect-ExchangeOnline
Connect-MgGraph
########## Secure app authentication info ##########
$AppId = 'omitted'
$AppSecret = 'omitted'
$consentscope = 'https://graph.microsoft.com/.default'
$AppCredential = (New-Object System.Management.Automation.PSCredential ($AppId, (ConvertTo-SecureString $AppSecret -AsPlainText -Force)))
$RefreshToken = 'omitted'
$PartnerTenantid = 'omitted'
$AppDisplayName = 'Graph Connection App'
########## Get client tenants ##########
$customers = Get-MsolPartnerContract -All
Write-Host "Found $($customers.Count) customers for $((Get-MsolCompanyInformation).displayname)."
foreach ($customer in $customers) {
########## Generate access token ##########
$CustomerTenant = $customer.defaultdomainname
$CustomerName = $customer.defaultdomainname
Write-Host "Preparing to process $($customername)."
Write-Host ""
########## Generate Tokens ##########
$token = New-PartnerAccessToken -ApplicationId $AppId -Scopes 'https://outlook.office365.com/.default' -ServicePrincipal -Credential $appcredential -Tenant $CustomerTenant -RefreshToken $RefreshToken
$graphToken = New-PartnerAccessToken -ApplicationId $AppId -Credential $appcredential -RefreshToken $RefreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $Customer.TenantId
########## Connect to Services ##########
Connect-ExchangeOnline -ShowBanner:$false -DelegatedOrganization $customertenant -AccessToken $token.AccessToken
Connect-MgGraph -AccessToken ($graphtoken.accesstoken |ConvertTo-SecureString -AsPlainText -Force)
########## Get all client domains so rule can be applied to them ##########
$organizationDomains = Invoke-RestMethod -Uri 'https://graph.microsoft.com/v1.0/domains?$select=id' -Method Get
########## Create new policy and rule ##########
New-AntiPhishPolicy -Name "Brand New Policy" -AdminDisplayName "Brand New Policy" -EnableOrganizationDomainsProtection $true -Confirm:$false
New-AntiPhishRule -Name "Brand New Rule" -AntiPhishPolicy "Brand New Rule" -Enabled $false -RecipientDomainIs $organizationDomains -Confirm:$false
}
I used Microsoft's Graph Explorer to find out what permissions the API I'm trying to call for getting the domains needs, and it said that my app needed one of the following: Domain.Read.All, Directory.Read.All, or Domain.ReadWrite.All. Giving it these permissions did not change the error.
I also tried calling other endpoints besides Domains (like Users), and I got the same errors for those.
This makes me think that I have a wrong or missing token somewhere.
I tried doing this without Graph, using $organizationDomains = Get-Msoldomain -TenantID $customer.tenantid | Select-Object -expand Name
, but that gives me an error telling me I don't have permission to call the cmdlet. This also sounds like a wrong or missing token.
Please let me know if you can help, and thank you!
I was able to get this to work by substituting this line:
$organizationDomains = Invoke-RestMethod -Uri 'https://graph.microsoft.com/v1.0/domains/?$select=id' -Method Get
with this:
$organizationDomains = Get-MgDomain -Property id,isVerified | Where-Object { $_.IsVerified -eq $true }
That returns the verified domains.