UcLobbyTeams.psm1

<#
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
#>


<#
.SYNOPSIS
Funcion to get the Architecture from .exe file
 
.DESCRIPTION
Based on PowerShell script Get-ExecutableType.ps1 by David Wyatt, please check the complete script in:
 
Identify 16-bit, 32-bit and 64-bit executables with PowerShell
https://gallery.technet.microsoft.com/scriptcenter/Identify-16-bit-32-bit-and-522eae75
 
.PARAMETER FilePath
Specifies the executable full file path.
 
.EXAMPLE
PS> Get-UcArch -FilePath C:\temp\example.exe
#>

Function Get-UcArch([string]$FilePath) {
try
    {
        $stream = New-Object System.IO.FileStream(
        $FilePath,
        [System.IO.FileMode]::Open,
        [System.IO.FileAccess]::Read,
        [System.IO.FileShare]::Read )
        $exeType = 'Unknown'
        $bytes = New-Object byte[](4)
        if ($stream.Seek(0x3C, [System.IO.SeekOrigin]::Begin) -eq 0x3C -and $stream.Read($bytes, 0, 4) -eq 4)
        {
            if (-not [System.BitConverter]::IsLittleEndian) { [Array]::Reverse($bytes, 0, 4) }
            $peHeaderOffset = [System.BitConverter]::ToUInt32($bytes, 0)

            if ($stream.Length -ge $peHeaderOffset + 6 -and
                $stream.Seek($peHeaderOffset, [System.IO.SeekOrigin]::Begin) -eq $peHeaderOffset -and
                $stream.Read($bytes, 0, 4) -eq 4 -and
                $bytes[0] -eq 0x50 -and $bytes[1] -eq 0x45 -and $bytes[2] -eq 0 -and $bytes[3] -eq 0)
            {
                $exeType = 'Unknown'
                if ($stream.Read($bytes, 0, 2) -eq 2)
                {
                    if (-not [System.BitConverter]::IsLittleEndian) { [Array]::Reverse($bytes, 0, 2) }
                    $machineType = [System.BitConverter]::ToUInt16($bytes, 0)
                    switch ($machineType)
                    {
                        0x014C { $exeType = 'x86' }
                        0x8664 { $exeType = 'x64' }
                    }
                }
            }
        }
        return $exeType
    }
    catch
    {
        return "Unknown"
    }
    finally
    {
        if ($null -ne $stream) { $stream.Dispose() }
    }
}

<#
.SYNOPSIS
Get Microsoft Teams Desktop Version
 
.DESCRIPTION
This function returns the installed Microsoft Teams desktop version for each user profile.
 
.EXAMPLE
PS> Get-UcTeamsVersion
#>

Function Get-UcTeamsVersion {
    $regexVersion = '("version":")([0-9.]*)'
    $regexRing = '("ring":")(\w*)'
    $regexEnv = '("environment":")(\w*)'
    $regexCloudEnv = '("cloudEnvironment":")(\w*)'
    $regexRegion = '("region":")([a-zA-Z0-9._-]*)'
    
    $outTeamsVersion = [System.Collections.ArrayList]::new()
    
    $currentDateFormat = [cultureinfo]::CurrentCulture.DateTimeFormat.ShortDatePattern
    $Profiles = Get-childItem 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' | ForEach-Object {Get-ItemProperty $_.pspath } | Where-Object {$_.fullprofile -eq 1}
    foreach($Profile in $Profiles){
        $TeamsSettingPath = $Profile.ProfileImagePath + "\AppData\Roaming\Microsoft\Teams\settings.json"
        if(Test-Path $TeamsSettingPath -ErrorAction SilentlyContinue) {
            $TeamsSettings = Get-Content -Path $TeamsSettingPath
            $Version = ""
            $Ring = ""
            $Env = ""
            $CloudEnv = ""
            $Region = ""
            try {
                $VersionTemp = [regex]::Match($TeamsSettings,$regexVersion).captures.groups
                if($VersionTemp.Count -ge 2){
                    $Version = $VersionTemp[2].value
                }
                $RingTemp = [regex]::Match($TeamsSettings,$regexRing).captures.groups
                if($RingTemp.Count -ge 2){
                    $Ring = $RingTemp[2].value
                }
                $EnvTemp = [regex]::Match($TeamsSettings,$regexEnv).captures.groups
                if($EnvTemp.Count -ge 2){
                    $Env = $EnvTemp[2].value
                }
                $CloudEnvTemp = [regex]::Match($TeamsSettings,$regexCloudEnv).captures.groups
                if($CloudEnvTemp.Count -ge 2){
                    $CloudEnv = $CloudEnvTemp[2].value
                }
                $RegionTemp = [regex]::Match($TeamsSettings,$regexRegion).captures.groups
                if($RegionTemp.Count -ge 2){
                    $Region = $RegionTemp[2].value
                }
            } catch { }
            $TeamsApp = $Profile.ProfileImagePath + "\AppData\Local\Microsoft\Teams\current\Teams.exe"
            $InstallDateStr = Get-Content ($Profile.ProfileImagePath + "\AppData\Roaming\Microsoft\Teams\installTime.txt")
            $TeamsVersion = New-Object –TypeName PSObject -Property @{
                Profile = (New-Object System.Security.Principal.SecurityIdentifier($Profile.PSChildName)).Translate( [System.Security.Principal.NTAccount]).Value
                ProfilePath = $Profile.ProfileImagePath
                Version = $Version
                Ring = $Ring
                Environment = $Env
                CloudEnvironment = $CloudEnv
                Region = $Region
                Arch = Get-UcArch $TeamsApp
                InstallDate = [Datetime]::ParseExact($InstallDateStr, 'M/d/yyyy', $null) | Get-Date -Format $currentDateFormat
            }
            
            $TeamsVersion.PSObject.TypeNAmes.Insert(0,'TeamsVersion')
            $outTeamsVersion.Add($TeamsVersion) | Out-Null
        }
    }
    return $outTeamsVersion
}

<#
.SYNOPSIS
Get Microsoft 365 Tenant Id
 
.DESCRIPTION
This function returns the Tenant ID associated with a domain that is part of a Microsoft 365 Tenant.
 
.PARAMETER Domain
Specifies a domain registered with Microsoft 365
 
.EXAMPLE
PS> Get-UcM365TenantId -Domain uclobby.com
#>

Function Get-UcM365TenantId{
Param(
 [Parameter(Mandatory=$true)]
 [string]$Domain
)
    $regex = "^(.*@)(\w{8}-\w{4}-\w{4}-\w{4}-\w{12})$"
    try{
    $AllowedAudiences = Invoke-WebRequest -Uri ("https://accounts.accesscontrol.windows.net/"+$Domain+"/metadata/json/1") | ConvertFrom-Json | Select-Object -ExpandProperty allowedAudiences
    } catch [System.Net.WebException]{
        if($PSItem.Exception.Message -eq "The remote server returned an error: (400) Bad Request."){
            Write-Warning "The domain $Domain is not part of a Microsoft 365 Tenant."
        } else {
            Write-Warning $PSItem.Exception.Message
        }
    } catch {
        Write-Warning "Unknown error while checking domain: $Domain"
    }

    foreach($AllowedAudience in $AllowedAudiences){
        $temp = [regex]::Match($AllowedAudience ,$regex).captures.groups
        if($temp.count -ge 2) {
            return   New-Object –TypeName PSObject -Property @{ TenantID = $temp[2].value}
        }
    }
}

<#
.SYNOPSIS
Get Teams Forest
 
.DESCRIPTION
This function returns the forest for a SIP enabled domain.
 
.PARAMETER Domain
Specifies a domain registered with Microsoft 365
 
.EXAMPLE
PS> Get-UcTeamsForest -Domain uclobby.com
#>

Function Get-UcTeamsForest{
Param(
 [Parameter(Mandatory=$true)]
 [string]$Domain
)
    $regex = "^.*[redirect].*(webdir)(\w*)(.online.lync.com).*$"
    try{
        $WebRequest = Invoke-WebRequest -Uri ("https://webdir.online.lync.com/AutoDiscover/AutoDiscoverservice.svc/root?originalDomain="+$Domain)
        $temp = [regex]::Match($WebRequest,$regex).captures.groups
        $result =  New-Object –TypeName PSObject -Property @{
                
                Domain = $Domain
                Forest = $temp[2].Value
                MigrationURL = "https://admin" + $temp[2].Value + ".online.lync.com/HostedMigration/hostedmigrationService.svc"
            }
        return $result
    } catch {
 
        if ($Error[0].Exception.Message -like "*404*"){
             Write-Warning ($Domain + " is not enabled for SIP." )
        }
    }
}

<#
.SYNOPSIS
Get Microsoft 365 Domains from a Tenant
 
.DESCRIPTION
This function returns a list of domains that are associated with a Microsoft 365 Tenant.
 
.PARAMETER Domain
Specifies a domain registered with Microsoft 365
 
.EXAMPLE
PS> Get-UcM365Domains -Domain uclobby.com
#>

Function Get-UcM365Domains{
Param(
 [Parameter(Mandatory=$true)]
 [string]$Domain
)
    $regex = "^(.*@)(.*[.].*)$"
    $outDomains = [System.Collections.ArrayList]::new()

    try{
        $AllowedAudiences = Invoke-WebRequest -Uri ("https://accounts.accesscontrol.windows.net/"+$Domain+"/metadata/json/1") | ConvertFrom-Json | Select-Object -ExpandProperty allowedAudiences
        foreach($AllowedAudience in $AllowedAudiences){
            $temp = [regex]::Match($AllowedAudience ,$regex).captures.groups
            if($temp.count -ge 2) {
                $tempObj =  New-Object –TypeName PSObject -Property @{
                    Name = $temp[2].value
                }
                $outDomains.Add($tempObj) | Out-Null
            }
        }
    } catch [System.Net.WebException]{
        if($PSItem.Exception.Message -eq "The remote server returned an error: (400) Bad Request."){
            Write-Warning "The domain $Domain is not part of a Microsoft 365 Tenant."
        } else {
            Write-Warning $PSItem.Exception.Message
        }
    } catch {
        Write-Warning "Unknown error while checking domain: $Domain"
    }
    return $outDomains
}

<#
.SYNOPSIS
Check if a Tenant can be changed to TeamsOnly
 
.DESCRIPTION
This function will check if there is a lyncdiscover DNS Record that prevents a tenant to be switched to TeamsOnly.
 
.PARAMETER Domain
Specifies a domain registered with Microsoft 365
 
.EXAMPLE
PS> Test-UcTeamsOnlyModeReadiness
 
.EXAMPLE
PS> Test-UcTeamsOnlyModeReadiness -Domain uclobby.com
#>

Function Test-UcTeamsOnlyModeReadiness {
Param(
 [Parameter(Mandatory=$false)]
 [string]$Domain
)
    $outTeamsOnly = [System.Collections.ArrayList]::new()
    $connectedMSTeams = $false
    if($Domain){
        $365Domains = Get-UcM365Domains -Domain $Domain
    } else {
        try{
            $365Domains =  Get-CsOnlineSipDomain
            $connectedMSTeams = $true
        } catch {
            Write-Error "Please Connect to before running this cmdlet with Connect-MicrosoftTeams"
        }
    }
    $DomainCount = ($365Domains.Count)
    $i= 1
    foreach($365Domain in $365Domains) {
        $tmpDomain = $365Domain.Name
        Write-Progress -Activity "Teams Only Mode Readiness" -Status "Checking: $tmpDomain - $i of $DomainCount"  -PercentComplete (($i / $DomainCount) * 100)
        $i++
        $status = "Not Ready"
        $DNSRecord = ""
        $hasARecord = $false
        $enabledSIP = $false
        
        # 20220522 - Skipping if the domain is not SIP Enabled.
        if(!($connectedMSTeams)) {
            try{
                Invoke-WebRequest -Uri ("https://webdir.online.lync.com/AutoDiscover/AutoDiscoverservice.svc/root?originalDomain="+$tmpDomain) | Out-Null
                $enabledSIP = $true
            } catch {
 
                if ($Error[0].Exception.Message -like "*404*"){
                    $enabledSIP = $false
                }
            }
        } else {
            if($365Domain.Status -eq "Enabled"){
                $enabledSIP = $true
            }
        }
        if($enabledSIP){
            $DiscoverFQDN = "lyncdiscover." + $365Domain.Name
            $FederationFQDN = "_sipfederationtls._tcp." + $365Domain.Name
            $DNSResultA = (Resolve-DnsName $DiscoverFQDN -ErrorAction Ignore -Type A)
            $DNSResultSRV = (Resolve-DnsName $FederationFQDN -ErrorAction Ignore -Type SRV).NameTarget
            foreach ($tmpRecord in $DNSResultA){
                if(($tmpRecord.NameHost -eq "webdir.online.lync.com")-and ($DNSResultSRV -eq "sipfed.online.lync.com")) {
                    break
                }
        
                if($tmpRecord.Type -eq "A"){
                    $hasARecord = $true
                    $DNSRecord = $tmpRecord.IPAddress
                }
            }
            if(!($hasARecord)){
                $DNSResultCNAME = (Resolve-DnsName $DiscoverFQDN -ErrorAction Ignore -Type CNAME)
                if($DNSResultCNAME.count -eq 0){
                    $status = "Ready"
                }
                if(($DNSResultCNAME.NameHost -eq "webdir.online.lync.com") -and ($DNSResultSRV -eq "sipfed.online.lync.com")) {
                    $status = "Ready"
                    $DNSRecord = $DNSResultCNAME.NameHost
                } else {
                    $DNSRecord = $DNSResultCNAME.NameHost
                }
                if($DNSResultCNAME.Type -eq "SOA"){
                    $status = "Ready"
                }
            }
            $Validation =  New-Object –TypeName PSObject -Property @{
                DiscoverRecord = $DNSRecord
                FederationRecord = $DNSResultSRV
                Status = $status
                Domain = $365Domain.Name
            }

        } else {
            $Validation =  New-Object –TypeName PSObject -Property @{
                DiscoverRecord = ""
                FederationRecord = ""
                Status = "Not SIP Enabled"
                Domain = $365Domain.Name
            }
        }
        $Validation.PSObject.TypeNAmes.Insert(0,'TeamsOnlyModeReadiness')
        $outTeamsOnly.Add($Validation) | Out-Null
    }
    return $outTeamsOnly
}

<#
.SYNOPSIS
Get Users Email Address that are in a Team
 
.DESCRIPTION
This function returns a list of users email address that are part of a Team.
 
.PARAMETER TeamName
Specifies Team Name
 
.PARAMETER Role
Specifies which roles to filter (Owner, User, Guest)
 
.EXAMPLE
PS> Get-UcTeamUsersEmail
 
.EXAMPLE
PS> Get-UcTeamUsersEmail -TeamName "Marketing"
 
.EXAMPLE
PS> Get-UcTeamUsersEmail -Role "Guest"
 
.EXAMPLE
PS> Get-UcTeamUsersEmail -TeamName "Marketing" -Role "Guest"
#>

Function Get-UcTeamUsersEmail{
Param(
 [Parameter(Mandatory=$false)]
 [string]$TeamName,
 [Parameter(Mandatory=$false)]
 [ValidateSet("Owner", "User", "Guest")] 
 [string]$Role
)
    $output = [System.Collections.ArrayList]::new()
    if($TeamName){
        $Teams = Get-Team -DisplayName $TeamName
    } else {
        if($ConfirmPreference){
            $title    = 'Confirm'
            $question = 'Are you sure that you want to list all Teams?'
            $choices  = '&Yes', '&No'
            $decision = $Host.UI.PromptForChoice($title, $question, $choices, 1)
        } else {
            $decision = 0
        }
        if ($decision -eq 0) {
            $Teams = Get-Team
        } else {
            return
        }
    }
    foreach($Team in $Teams) { 
        if($Role){
            $TeamMembers = Get-TeamUser -GroupId $Team.GroupID -Role $Role
        } else {
            $TeamMembers = Get-TeamUser -GroupId $Team.GroupID 
        }
        foreach ($TeamMember in $TeamMembers){
            $Email =( Get-csOnlineUser $TeamMember.User |Select-Object @{Name='PrimarySMTPAddress';Expression={$_.ProxyAddresses -cmatch '^SMTP:' -creplace 'SMTP:'}}).PrimarySMTPAddress
            $Member =  New-Object –TypeName PSObject -Property @{
                    TeamGroupID = $Team.GroupID
                    TeamDisplayName = $Team.DisplayName
                    TeamVisibility = $Team.Visibility
                    UPN = $TeamMember.User
                    Role = $TeamMember.Role
                    Email = $Email
            }
            $Member.PSObject.TypeNAmes.Insert(0,'TeamUsersEmail')
            $output.Add($Member) | Out-Null
        }
    }
    return $output
}

<#
.SYNOPSIS
Get Teams that have a single owner
 
.DESCRIPTION
This function returns a list of Teams that only have a single owner.
 
.EXAMPLE
PS> Get-UcTeamsWithSingleOwner
#>

Function Get-UcTeamsWithSingleOwner{
    Get-UcTeamUsersEmail -Role Owner -Confirm:$false | Group-Object -Property TeamDisplayName | Where-Object {$_.Count -lt 2} | Select-Object -ExpandProperty Group
}

<#
.SYNOPSIS
Get a list of all Microsoft Teams Devices
 
.DESCRIPTION
This function get all Teams Devices provisioned in a M365 Tenant.
  
 
Authors: David Paulino, Silvio Schanz
 
Requirements: Microsoft Graph PowerShell Module (Install-Module Microsoft.Graph)
                Microsoft Graph Scopes:
                        "TeamworkDevice.Read.All"
                        "User.Read.All"
 
.EXAMPLE
PS> Get-UcTeamsDeviceList
 
#>


Function Get-UcTeamsDeviceList{
    $GraphURI_TeamsDevices = "https://graph.microsoft.com/beta/teamwork/devices/"
    $GraphURI_Users= "https://graph.microsoft.com/v1.0/users/"
    
    
    #Checking if we have the required scopes.
    $scopes = (Get-MgContext).Scopes
    if(!($scopes) -or !(( "TeamworkDevice.Read.All" -in $scopes ) -and ("User.Read.All" -in $scopes))){
            Connect-MgGraph -Scopes "TeamworkDevice.Read.All","User.Read.All"
    }
    
    $TeamsDeviceList = (Invoke-MgGraphRequest -Uri $GraphURI_TeamsDevices  -Method GET).Value
    $outTeamsDevices = [System.Collections.ArrayList]::new()
    
    
    $TeamsDeviceCount = ($TeamsDeviceList.Count)
    $i = 1
    foreach($TeamsDevice in $TeamsDeviceList){
        Write-Progress -Activity "Teams Device List" -Status "Getting Teams Device info $i of $TeamsDeviceCount"  -PercentComplete (($i / $TeamsDeviceCount) * 100)
        $i++
        if($TeamsDevice.currentuser.id){
            $userUPN =  (Invoke-MgGraphRequest -Uri ($GraphURI_Users + $TeamsDevice.currentuser.id ) -Method GET).userPrincipalName
        } else {
            $userUPN = ""
        }
        try{
            $TDConfig =  (Invoke-MgGraphRequest -Uri ($GraphURI_TeamsDevices + $TeamsDevice.id + "/configuration") -Method GET) 
        } catch {
            $TDConfig = ""
        }
    
    
        $TDObj =  New-Object –TypeName PSObject -Property @{
                        UserDisplayName = $TeamsDevice.currentuser.displayName
                        UserUPN = $userUPN 
    
                        DeviceType = $TeamsDevice.deviceType
                        Manufacturer = $TeamsDevice.hardwaredetail.manufacturer
                        Model = $TeamsDevice.hardwaredetail.model
                        SerialNumber = $TeamsDevice.hardwaredetail.serialNumber 
                        MacAddresses = $TeamsDevice.hardwaredetail.macAddresses
                        
                        DeviceHealth = $TeamsDevice.healthStatus
                        TeamsAdminAgent = $TDConfig.softwareVersions.adminAgentSoftwareVersion
                        Firmware = $TDConfig.softwareVersions.firmwareSoftwareVersion
                        OEMAgentApp = $TDConfig.softwareVersions.partnerAgentSoftwareVersion
                        TeamsApp = $TDConfig.softwareVersions.teamsClientSoftwareVersion
                }
        $TDObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceList')
        $outTeamsDevices.Add($TDObj) | Out-Null
     
    }
    
    $outTeamsDevices
}


<#
.SYNOPSIS
Validate which Conditional Access policies are supported by Microsoft Teams Android Devices
 
.DESCRIPTION
This function will validate each setting in a Conditional Access Policy to make sure they are in line with the supported settings:
 
    https://docs.microsoft.com/microsoftteams/rooms/supported-ca-and-compliance-policies?tabs=phones#supported-device-compliance-policies
 
Authors: Traci Herr, David Paulino
 
Requirements: Microsoft Graph PowerShell Module (Install-Module Microsoft.Graph)
 
.PARAMETER Detailed
Displays test results for all settings in each Conditional Access Policy
 
.EXAMPLE
PS> Test-UcTeamsDevicesConditionalAccessPolicy
 
.EXAMPLE
PS> Test-UcTeamsDevicesConditionalAccessPolicy -Detailed
 
#>


Function Test-UcTeamsDevicesConditionalAccessPolicy{

Param(
 [Parameter(Mandatory=$false)]
 [switch]$Detailed
)

    $connectedMSGraph = $false
    $ConditionalAccessPolicies = $null
    $URLTeamsDevicesCA = "aka.ms/TeamsDevicesAndroidPolicies#supported-conditional-access-policies"
    $URLTeamsDevicesKnownIssues = "https://docs.microsoft.com/microsoftteams/troubleshoot/teams-rooms-and-devices/rooms-known-issues#teams-phone-devices"

    $scopes = (Get-MgContext).Scopes

    if(!($scopes) -or !( "Policy.Read.All" -in $scopes )){
        Connect-MgGraph -Scopes "Policy.Read.All"
    }

    try {
        $ConditionalAccessPolicies = (Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" -Method GET).Value
        $connectedMSGraph = $true
    } catch {
        Write-Error 'Please connect to MS Graph with Connect-MgGraph -Scopes "Policy.Read.All" before running this script'
    }

    if($connectedMSGraph) {
        $output = [System.Collections.ArrayList]::new()
        $outputSum = [System.Collections.ArrayList]::new()
        foreach($ConditionalAccessPolicy in $ConditionalAccessPolicies){

            $CAPolicyState = $ConditionalAccessPolicy.State

            if($CAPolicyState -eq "enabledForReportingButNotEnforced"){
                $CAPolicyState = "ReportOnly"
            }

            $PolicyErrors = 0
            $PolicyWarnings = 0

            #Cloud Apps
            #Exchange 00000002-0000-0ff1-ce00-000000000000
            #SharePoint 00000003-0000-0ff1-ce00-000000000000
            #Teams cc15fd57-2c6c-4117-a88c-83b1d56b4bbe
            $hasExchange = $false
            $hasSharePoint = $false
            $hasTeams =$false
            $hasOffice365 = $false
            $CloudAppValue = ""
            foreach($Application in $ConditionalAccessPolicy.Conditions.Applications.IncludeApplications){

                switch($Application){
                    "All" {$hasOffice365 = $true; $CloudAppValue = "All"}
                    "Office365" {$hasOffice365 = $true; $CloudAppValue = "Office 365"}
                    "00000002-0000-0ff1-ce00-000000000000" { $hasExchange = $true; $CloudAppValue += "Exchange, " }
                    "00000003-0000-0ff1-ce00-000000000000" { $hasSharePoint = $true; $CloudAppValue += "SharePoint, "}
                    "cc15fd57-2c6c-4117-a88c-83b1d56b4bbe" { $hasTeams = $true; $CloudAppValue += "Teams, " }
                    "None" {$CloudAppValue = "None"}
                }
            }
            if($CloudAppValue.EndsWith(", ")){
                $CloudAppValue = $CloudAppValue.Substring(0,$CloudAppValue.Length-2)
            }

            if(($hasExchange -and $hasSharePoint -and $hasTeams) -or ($hasOffice365)){
                $Status = "Supported"
                $Comment = ""
            } else {
                $Status = "Unsupported"
                $Comment = "Teams Devices needs to access: Office 365 or Exchange Online, SharePoint Online, and Microsoft Teams"
                $PolicyErrors++
            }
            
            $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                CAPolicyID = $ConditionalAccessPolicy.id
                                CAPolicyName = $ConditionalAccessPolicy.displayName
                                CAPolicyState = $CAPolicyState
                                Setting = "Cloud Apps or actions"
                                Value = $CloudAppValue
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
            }
            $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceConditionalAccessPolicy')
            $output.Add($SettingPSObj) | Out-Null

            #Conditions - ClientAppTypes
            foreach($ClientAppType in $ConditionalAccessPolicy.Conditions.ClientAppTypes){
                if($ClientAppType -eq "All"){
                    $Status = "Supported"
                    $Comment = ""
                } else {
                    $PolicyErrors++
                    $Status = "Unsupported"
                    $Comment = $URLTeamsDevicesCA
                }

                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                    CAPolicyID = $ConditionalAccessPolicy.id
                                    CAPolicyName = $ConditionalAccessPolicy.displayName
                                    CAPolicyState = $CAPolicyState
                                    Setting = "Conditions - ClientAppTypes"
                                    Value = $ClientAppType
                                    TeamsDevicesStatus = $Status 
                                    Comment = $Comment
                }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceConditionalAccessPolicy')
                $output.Add($SettingPSObj) | Out-Null
            }

            #Device

            if($ConditionalAccessPolicy.conditions.devices){
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                    CAPolicyID = $ConditionalAccessPolicy.id
                                    CAPolicyName = $ConditionalAccessPolicy.displayName
                                    CAPolicyState = $CAPolicyState
                                    Setting = "Device Filter"
                                    Value = "Configured"
                                    TeamsDevicesStatus = "Supported"
                                    Comment = $ConditionalAccessPolicy.conditions.devices.deviceFilter.mode + ": "+ $ConditionalAccessPolicy.conditions.devices.deviceFilter.rule
                }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceConditionalAccessPolicy')
                $output.Add($SettingPSObj) | Out-Null
            } else {
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                    CAPolicyID = $ConditionalAccessPolicy.id
                                    CAPolicyName = $ConditionalAccessPolicy.displayName
                                    CAPolicyState = $CAPolicyState
                                    Setting = "Device Filter"
                                    Value = "Missing"
                                    TeamsDevicesStatus = "Warning"
                                    Comment = "Device Filter is required when multiple Conditional Access policies exist."
                }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceConditionalAccessPolicy')
                $output.Add($SettingPSObj) | Out-Null
            }



            #Grant Controls

            $Setting = "GrantControls"
            foreach($BuiltInControl in $ConditionalAccessPolicy.GrantControls.BuiltInControls){
                $Comment = "" 
                if ($BuiltInControl -in 'DomainJoinedDevice','ApprovedApplication','CompliantApplication','PasswordChange'){
                    $PolicyErrors++
                    $Status = "Unsupported"
                    $Comment = $URLTeamsDevicesCA
                } else {
                    $Status = "Supported"
                }

                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                    CAPolicyID = $ConditionalAccessPolicy.id
                                    CAPolicyName = $ConditionalAccessPolicy.displayName
                                    CAPolicyState = $CAPolicyState
                                    Setting = $Setting 
                                    Value = $BuiltInControl 
                                    TeamsDevicesStatus = $Status 
                                    Comment = $Comment
                }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceConditionalAccessPolicy')
                $output.Add($SettingPSObj) | Out-Null
            }

            
            if($ConditionalAccessPolicy.GrantControls.CustomAuthenticationFactors){
                $PolicyWarnings++
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                    CAPolicyID = $ConditionalAccessPolicy.id
                                    CAPolicyName = $ConditionalAccessPolicy.displayName
                                    CAPolicyState = $CAPolicyState
                                    Setting = $Setting 
                                    Value = "CustomAuthenticationFactors"
                                    TeamsDevicesStatus = "Unsupported"
                                    Comment = $URLTeamsDevicesCA
                }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceConditionalAccessPolicy')
                $output.Add($SettingPSObj) | Out-Null
            }

            if($ConditionalAccessPolicy.GrantControls.TermsOfUse){
                $PolicyWarnings++
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                    CAPolicyID = $ConditionalAccessPolicy.id
                                    CAPolicyName = $ConditionalAccessPolicy.displayName
                                    CAPolicyState = $CAPolicyState
                                    Setting = $Setting 
                                    Value = "Terms of Use"
                                    TeamsDevicesStatus = "Warning"
                                    Comment = $URLTeamsDevicesKnownIssues
                }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceConditionalAccessPolicy')
                $output.Add($SettingPSObj) | Out-Null
            }

            $Setting = "SessionControls"
            $Comment = "" 
            if($ConditionalAccessPolicy.SessionControls.ApplicationEnforcedRestrictions){
                $PolicyErrors++
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                    CAPolicyID = $ConditionalAccessPolicy.id
                                    CAPolicyName = $ConditionalAccessPolicy.displayName
                                    CAPolicyState = $CAPolicyState
                                    Setting = $Setting 
                                    Value = "ApplicationEnforcedRestrictions"
                                    TeamsDevicesStatus = "Unsupported" 
                                    Comment = $Comment
                }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceConditionalAccessPolicy')
                $output.Add($SettingPSObj) | Out-Null
            }
            if($ConditionalAccessPolicy.SessionControls.CloudAppSecurity){
                $PolicyErrors++
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                    CAPolicyID = $ConditionalAccessPolicy.id
                                    CAPolicyName = $ConditionalAccessPolicy.displayName
                                    CAPolicyState = $CAPolicyState
                                    Setting = $Setting 
                                    Value = "CloudAppSecurity"
                                    TeamsDevicesStatus = "Unsupported" 
                                    Comment = $URLTeamsDevicesCA
                }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceConditionalAccessPolicy')
                $output.Add($SettingPSObj) | Out-Null
            }
            if($ConditionalAccessPolicy.SessionControls.SignInFrequency){
                $PolicyWarnings++
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                    CAPolicyID = $ConditionalAccessPolicy.id
                                    CAPolicyName = $ConditionalAccessPolicy.displayName
                                    CAPolicyState = $CAPolicyState
                                    Setting = $Setting 
                                    Value = "SignInFrequency"
                                    TeamsDevicesStatus = "Warning" 
                                    Comment = "Users will be signout from Teams Device every " + $ConditionalAccessPolicy.SessionControls.SignInFrequency.Value + " " + $ConditionalAccessPolicy.SessionControls.SignInFrequency.Type
                }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceConditionalAccessPolicy')
                $output.Add($SettingPSObj) | Out-Null
            }
            if($ConditionalAccessPolicy.SessionControls.PersistentBrowser){
                $PolicyErrors++
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                    CAPolicyID = $ConditionalAccessPolicy.id

                                    CAPolicyName = $ConditionalAccessPolicy.displayName
                                    CAPolicyState = $CAPolicyState
                                    Setting = $Setting 
                                    Value = "PersistentBrowser"
                                    TeamsDevicesStatus = "Unsupported" 
                                    Comment = $URLTeamsDevicesCA
                }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceConditionalAccessPolicy')
                $output.Add($SettingPSObj) | Out-Null
            }

            if($PolicyErrors -gt 0){
                $StatusSum = "Unsupported"
            } elseif ($PolicyWarnings -gt 0){
                $StatusSum = "Warning"
            } else {
                $StatusSum = "Supported"
            }

            $PolicySum =  New-Object –TypeName PSObject -Property @{
                            CAPolicyID = $ConditionalAccessPolicy.id
                            CAPolicyName = $ConditionalAccessPolicy.DisplayName
                            CAPolicyState = $CAPolicyState
                            TeamsDevicesStatus = $StatusSum
                        }
            $PolicySum.PSObject.TypeNAmes.Insert(0,'TeamsDeviceConditionalAccessPolicySummary')
            $outputSum.Add($PolicySum) | Out-Null
        }
        if($Detailed) {
            $output | Sort-Object CAPolicyName,Setting
        } else {
            $outputSum 
        }
    }
}

<#
.SYNOPSIS
Validate which Intune Compliance policies are supported by Microsoft Teams Android Devices
 
.DESCRIPTION
This function will validate each setting in the Intune Compliance Policy to make sure they are in line with the supported settings:
 
    https://docs.microsoft.com/en-us/microsoftteams/rooms/supported-ca-and-compliance-policies?tabs=phones#supported-device-compliance-policies
 
Authors: Traci Herr, David Paulino
 
Requirements: Microsoft Graph PowerShell Module (Install-Module Microsoft.Graph)
 
.PARAMETER Detailed
Displays test results for all settings in each Intune Compliance Policy
 
.EXAMPLE
PS> Test-UcTeamsDevicesCompliancePolicy
 
.EXAMPLE
PS> Test-UcTeamsDevicesCompliancePolicy -Detailed
 
#>

Function Test-UcTeamsDevicesCompliancePolicy{

Param(
 [Parameter(Mandatory=$false)]
 [switch]$Detailed,
 [Parameter(Mandatory=$false)]
 [string]$PolicyID,
 [Parameter(Mandatory=$false)]
 [string]$PolicyName
)

    $connectedMSGraph = $false
    $CompliancePolicies = $null

    $scopes = (Get-MgContext).Scopes

    if(!($scopes) -or !( "DeviceManagementConfiguration.Read.All" -in $scopes )){
        Connect-MgGraph -Scopes "DeviceManagementConfiguration.Read.All"
    }

    try {
        $CompliancePolicies =  (Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/v1.0/deviceManagement/deviceCompliancePolicies" -Method GET).value
        $connectedMSGraph = $true
    } catch {
        Write-Error 'Please connect to MS Graph with Connect-MgGraph -Scopes "DeviceManagementConfiguration.Read.All" before running this script'
    }

    if($connectedMSGraph) {
        $output = [System.Collections.ArrayList]::new()
        $outputSum = [System.Collections.ArrayList]::new()
        foreach($CompliancePolicy in $CompliancePolicies){
            if((($PolicyID -eq $CompliancePolicy.id) -or ($PolicyName -eq $CompliancePolicy.displayName)  -or (!$PolicyID -and !$PolicyName)) -and ($CompliancePolicy."@odata.type" -eq "#microsoft.graph.androidCompliancePolicy")){
                $PolicyErrors = 0
                $PolicyWarnings = 0

                $ID = 1
                $Setting = "deviceThreatProtectionEnabled"
                $Comment = ""
                if($CompliancePolicy.deviceThreatProtectionEnabled){
                    $Status = "Unsupported"
                    $PolicyErrors++
                } else {
                    $Status = "Supported"
                }

                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.deviceThreatProtectionEnabled
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null


                $ID = 3
                $Setting = "securityBlockJailbrokenDevices"
                $Comment = ""
                if($CompliancePolicy.securityBlockJailbrokenDevices){
                    $Status = "Warning"
                    $Comment =  "This setting can cause sign in issues."
                    $PolicyWarnings++
                } else {
                    $Status = "Supported"
                }
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.securityBlockJailbrokenDevices
                                TeamsDevicesStatus = $Status
                                Comment = $Comment 
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null  


                $ID = 4
                $Setting = "deviceThreatProtectionRequiredSecurityLevel"
                $Comment = ""
                if($CompliancePolicy.deviceThreatProtectionRequiredSecurityLevel -ne "unavailable"){
                    $Status = "Unsupported"
                    $PolicyErrors++
                } else {
                    $Status = "Supported"
                }

                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.deviceThreatProtectionRequiredSecurityLevel
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null


                $ID = 5
                $Setting = "securityRequireGooglePlayServices"
                $Comment = ""
                if($CompliancePolicy.securityRequireGooglePlayServices){
                    $Status = "Unsupported"
                    $PolicyErrors++
                } else {
                    $Status = "Supported"
                }

                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $SettingPSObj
                                Value = $CompliancePolicy.securityRequireGooglePlayServices
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')                            
                $output.Add($SettingPSO) | Out-Null
        

                $ID = 6
                $Setting = "securityRequireUpToDateSecurityProviders"
                $Comment = ""
                if($CompliancePolicy.securityRequireUpToDateSecurityProviders){
                    $Status = "Unsupported"
                    $Comment = "Google play isn't installed on Teams Android devices."
                    $PolicyErrors++
                } else {
                    $Status = "Supported"
                }

                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.securityRequireUpToDateSecurityProviders
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null

        
                $ID = 7
                $Setting = "securityRequireVerifyApps"
                $Comment = ""
                if($CompliancePolicy.securityRequireVerifyApps){
                    $Status = "Unsupported"
                    $PolicyErrors++
                } else {
                    $Status = "Supported"
                }

                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.securityRequireVerifyApps
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null


                $ID = 8.1
                $Setting = "securityRequireSafetyNetAttestationBasicIntegrity"
                $Comment = ""
                if($CompliancePolicy.securityRequireSafetyNetAttestationBasicIntegrity){
                    $Status = "Unsupported"
                    $PolicyErrors++
                } else {
                    $Status = "Supported"
                }

                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.securityRequireSafetyNetAttestationBasicIntegrity
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')                            
                $output.Add($SettingPSObj) | Out-Null


                $ID = 8.2
                $Setting = "securityRequireSafetyNetAttestationCertifiedDevice"
                $Comment = ""    
                if($CompliancePolicy.securityRequireSafetyNetAttestationCertifiedDevice){
                    $Status = "Unsupported"
                    $PolicyErrors++
                } else {
                    $Status = "Supported"
                }

                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.securityRequireSafetyNetAttestationCertifiedDevice
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null


                $ID = 9.1
                $Setting = "osMinimumVersion"
                $Comment = ""
                if($CompliancePolicy.osMinimumVersion){
                    $Status = "Warning"
                    $Comment =  "This setting can cause sign in issues."
                    $PolicyWarnings++
                } else {
                    $Status = "Supported"
                }
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.osMinimumVersion
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null  

        
                $ID = 9.2
                $Setting = "osMaximumVersion"
                $Comment = ""
                if($CompliancePolicy.osMaximumVersion){
                    $Status = "Warning"
                    $Comment =  "This setting can cause sign in issues."
                    $PolicyWarnings++
                } else {
                    $Status = "Supported"
                }
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.osMaximumVersion
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null  


                $ID = 10
                $Setting = "storageRequireEncryption"
                $Comment = ""
                if($CompliancePolicy.storageRequireEncryption){
                    $Status = "Warning"
                    $Comment = "https://docs.microsoft.com/en-us/microsoftteams/rooms/supported-ca-and-compliance-policies?tabs=phones#supported-device-compliance-policies"
                    $PolicyWarnings++
                } else {
                    $Status = "Supported"
                }

                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.storageRequireEncryption
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null


                $ID = 11
                $Setting = "securityPreventInstallAppsFromUnknownSources"
                $Comment = ""
                if($CompliancePolicy.securityPreventInstallAppsFromUnknownSources){
                    $Status = "Unsupported"
                    $PolicyErrors++
                } else {
                    $Status = "Supported"
                }

                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.securityPreventInstallAppsFromUnknownSources
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null    



                $ID = 15
                $Setting = "passwordMinutesOfInactivityBeforeLock"
                $Comment = ""
                if($null -ne $CompliancePolicy.passwordMinutesOfInactivityBeforeLock){
                    $Status = "Unsupported"
                    $PolicyErrors++
                } else {
                    $Status = "Supported"
                }
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.passwordMinutesOfInactivityBeforeLock
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null  


                $ID = 16
                $Setting = "passwordRequired"
                $Comment = ""
                if($CompliancePolicy.passwordRequired){
                    $Status = "Unsupported"
                    $PolicyErrors++
                } else {
                    $Status = "Supported"
                }
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.passwordRequired
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null  


                $ID = 17.1
                $Setting = "passwordRequiredType"
                $Comment = ""
                if($CompliancePolicy.passwordRequiredType -ne 'deviceDefault'){
                    $Status = "Unsupported"
                    $PolicyErrors++
                } else {
                    $Status = "Supported"
                }
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.passwordRequiredType
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null  


                $ID = 17.2
                $Setting = "passwordMinimumLength"
                $Comment = ""
                if($null -ne $CompliancePolicy.passwordMinimumLength){
                    $Status = "Unsupported"
                    $PolicyErrors++
                } else {
                    $Status = "Supported"
                }
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.passwordMinimumLength
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null  

        
                $ID = 17.3
                $Setting = "passwordExpirationDays"
                $Comment = ""
                if($null -ne $CompliancePolicy.passwordExpirationDays){
                    $Status = "Unsupported"
                    $PolicyErrors++
                } else {
                    $Status = "Supported"
                }
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.passwordExpirationDays 
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null  


                $ID = 17.4
                $Setting = "passwordPreviousPasswordBlockCount"
                $Comment = ""
                if($null -ne $CompliancePolicy.passwordPreviousPasswordBlockCount){
                    $Status = "Unsupported"
                    $PolicyErrors++
                } else {
                    $Status = "Supported"
                }
                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.passwordPreviousPasswordBlockCount
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null  


                $ID = 18
                $Setting = "minAndroidSecurityPatchLevel"
                $Comment = ""
                if($CompliancePolicy.minAndroidSecurityPatchLevel -ne ""){
                    $Status = "Warning"
                    $Comment =  "This setting can cause sign in issues."
                    $PolicyWarnings++
                } else {
                    $Status = "Supported"
                }

                $SettingPSObj =  New-Object –TypeName PSObject -Property @{
                                ID = $ID
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                Setting = $Setting
                                Value = $CompliancePolicy.minAndroidSecurityPatchLevel
                                TeamsDevicesStatus = $Status 
                                Comment = $Comment
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicy')
                $output.Add($SettingPSObj) | Out-Null

                if($PolicyErrors -gt 0){
                    $StatusSum = "Unsupported"
                } elseif ($PolicyWarnings -gt 0){
                    $StatusSum = "Warning"
                } else {
                    $StatusSum = "Supported"
                }

                $PolicySum =  New-Object –TypeName PSObject -Property @{
                                PolicyID = $CompliancePolicy.id
                                PolicyName = $CompliancePolicy.displayName
                                TeamsDevicesStatus = $StatusSum
                            }
                $SettingPSObj.PSObject.TypeNAmes.Insert(0,'TeamsDeviceCompliancePolicySumary')
                $outputSum.Add($PolicySum) | Out-Null
            }
        }
        if($Detailed) {
            $output | Sort-Object PolicyName,ID 
        } else {
            $outputSum 
        }
    }
}