Applications.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
<#
    The Get-GraphServicePrincipal function reworks work on service principals which was published by Justin Grote at
        https://github.com/JustinGrote/JustinGrote.Microsoft.Graph.Extensions/blob/main/src/Public/Get-MgO365ServicePrincipal.ps1
        https://github.com/JustinGrote/JustinGrote.Microsoft.Graph.Extensions/blob/main/src/Public/Get-MgManagedIdentity.ps1 and
        https://github.com/JustinGrote/JustinGrote.Microsoft.Graph.Extensions/blob/main/src/Public/Get-MgAppRole.ps1

    and licensed by him under the same MIT terms which apply to this module (see the LICENSE file for details)

    Portions of this file are Copyright 2021 Justin Grote @justinwgrote

    The remainder is Copyright 2018-2021 James O'Neill
#>

using namespace  Microsoft.Graph.PowerShell.Models
function Get-GraphServicePrincipal {
    <#
      .Synopsis
        Returns information about Service Principals
      .Description
        A replacement for the SDK's Get-MgServicePrincipal
        That has orderby which doesn't work - it's in the Docs but the API errors if you try
        It doesn't have find by name, or select Application or Managed IDs
      .Example
        PS > Get-GraphServicePrincipal "Microsoft graph*"

        Id DisplayName AppId SignInAudience
        -- ----------- ----- --------------
        25b13fbf-2f44-457a-9e68-d3414fc97915 Microsoft Graph 00000003-0000-0000-c000-000000000000 AzureADMultipleOrgs
        4e71d88a-0a46-4274-85b8-82ad86877010 Microsoft Graph Change Tracking 0bf30f3b-4a52-48df-9a82-234910c4a086 AzureADMultipleOrgs
        ...

        Run with a name the command returns service principals with matching names.
        .Example
        PS >Get-GraphServicePrincipal 25b13fbf-2f44-457a-9e68-d3414fc97915 -ExpandAppRoles

        Value DisplayName Enabled Id
        ----- ----------- ------- --
        AccessReview.Read.All Read all access reviews True d07a8cc0-3d51-4b77-b3b0-32704d1f69fa
        AccessReview.ReadWrite.All Manage all access reviews True ef5f7d5c-338f-44b0-86c3-351f46c8bb5f
        ...
        In this example GUID for Microsoft Graph was used from the previous example, and the command has listed the roles available to applications
    #>


    [CmdletBinding(DefaultParameterSetName='List1')]
    [OutputType([Microsoft.Graph.PowerShell.Models.IMicrosoftGraphAppRole],ParameterSetName=('AllRoles','FilteredRoles'))]
    [OutputType([Microsoft.Graph.PowerShell.Models.IMicrosoftGraphPermissionScope],ParameterSetName=('AllScopes','FilteredScopes'))]
    [OutputType([Microsoft.Graph.PowerShell.Models.IMicrosoftGraphServicePrincipal],ParameterSetName=('Get2','List1','List2','List3','List4'))]
    param   (
        [Parameter(ParameterSetName='AllRoles',       Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [Parameter(ParameterSetName='FilteredRoles',  Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [Parameter(ParameterSetName='AllScopes',      Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [Parameter(ParameterSetName='FilteredScopes', Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [Parameter(ParameterSetName='Get2',           Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        #The GUID(s) for ServicePrincipal(s). Or SP objects. If a name is given instead, the command will try to resolve matching Service principals
        $ServicePrincipalId,

        [Parameter(ParameterSetName='List5')]
        [string]$AppId,

        #Produces a list filtered to only managed identities
        [Parameter(ParameterSetName='List2')]
        [switch]$ManagedIdentity,

        #Produces a list filtered to only applications
        [Parameter(ParameterSetName='List3')]
        [switch]$Application,

        #Produces a convenience list of office 365 security principals
        [Parameter(ParameterSetName='List4')]
        [switch]$O365ServicePrincipals,

        #Select properties to be returned
        [Alias('Select')]
        [String[]]$Property,

        #Filters items by property values
        [Parameter(ParameterSetName='List1')]
        [String]$Filter,

        #Returns the list of application roles to those the role name, displayname or ID match the parameter value. Wildcards are supported
        [Parameter(ParameterSetName='AllRoles', Mandatory=$true)]
        [switch]$ExpandAppRoles,

        #Filters the list of application roles available within a SP
        [Parameter(ParameterSetName='FilteredRoles', Mandatory=$true)]
        [string]$AppRoleFilter,

        #Returns the list of (user) oauth scopes available within a SP
        [Parameter(ParameterSetName='AllScopes', Mandatory=$true)]
        [switch]$ExpandScopes,

        #Filters the list of oauth scopes to those where the scope name, displayname or ID match the parameter value. Wildcards are supported
        [Parameter(ParameterSetName='FilteredScopes', Mandatory=$true)]
        [string]$ScopeFilter
    )
    begin   {
        [String]$managedIdentityFilter = @(
            '00000001-0000-0000-c000-000000000000' #Azure ESTS Service
            '00000007-0000-0000-c000-000000000000' #Common Data Service
            '0000000c-0000-0000-c000-000000000000' #Microsoft App Access Panel'
            '00000007-0000-0ff1-ce00-000000000000' #Microsoft Exchange Online Protection
            '00000003-0000-0000-c000-000000000000' #Microsoft Graph
            '00000006-0000-0ff1-ce00-000000000000' #Microsoft Office 365 Portal
            '00000012-0000-0000-c000-000000000000' #Microsoft Rights Management Services
            '00000008-0000-0000-c000-000000000000' #Microsoft.Azure.DataMarket
            '00000002-0000-0ff1-ce00-000000000000' #Office 365 Exchange Online
            '00000003-0000-0ff1-ce00-000000000000' #Office 365 SharePoint Online
            '00000009-0000-0000-c000-000000000000' #Power BI Service
            '00000004-0000-0ff1-ce00-000000000000' #Skype for Business Online
            '00000002-0000-0000-c000-000000000000' #Windows Azure Active Directory
        ).foreach{"appId eq '$PSItem'"} -join ' or '

        if ($ExpandScopes)   {$ScopeFilter   = '*'}
        if ($ExpandAppRoles) {$AppRoleFilter = '*'}

        $webparams = @{
                    AsType          =  ([MicrosoftGraphServicePrincipal])
                    ExcludeProperty = @('@odata.context','createdDateTime','disabledByMicrosoftStatus',
                                        'keyCredentials','resourceSpecificApplicationPermissions','verifiedPublisher')
                    Headers         = @{'ConsistencyLevel'= 'Eventual'}
        }
    }
    process {
        if ( -not    $ServicePrincipalId)    {
            if      ($ManagedIdentity)             {$filter  = "?`$filter=servicePrincipaltype eq 'ManagedIdentity'"}
            elseif  ($Application)                 {$filter  = "?`$filter=servicePrincipaltype eq 'Application'"}
            elseif  ($AppId)                       {$filter  = "?`$filter=appid eq '$AppId'" }
            elseif  ($PSBoundParameters['Filter'] -and
                     $O365ServicePrincipal )       {$filter  = "?`$filter=( $($PSBoundParameters['Filter']) ) and $managedIdentityFilter"}
            elseif  ($PSBoundParameters['Filter']) {$filter  = "?`$filter=$($PSBoundParameters['Filter'])"}
            elseif  ($O365ServicePrincipals)       {$filter  = "?`$filter=$managedIdentityFilter"}

            if      ($Property -and $filter)       {$filter += '&$select=' +($property -join ',')}
            elseif  ($Property)                    {$filter  = '?$select=' +($property -join ',')}
            Invoke-GraphRequest "$GraphUri/servicePrincipals$filter" -ValueOnly @webparams | Sort-Object displayname
        }
        else {
            foreach ($sp in $ServicePrincipalId) {
                $result = $null
                if     ($sp -match $GUIDRegex)      {
                    $webparams['uri'] = "$GraphUri/servicePrincipals/$sp"
                    if ($Property) {$webparams['uri'] += '?$select=' +($property -join ',')}
                    try {$result = Invoke-GraphRequest @webparams}
                    catch {
                        if ($_.Exception.Response.StatusCode.value__  -eq 404) {
                            Write-Warning "$sp was not found as a service principal ID. It may be an App ID.";  continue
                        }
                        else {throw $_.Exception }
                    }
                }
                else   {
                    $webparams['uri'] = "$GraphUri/servicePrincipals?`$filter=" + (FilterString $sp)
                    if ($Property) {$webparams['uri'] += '&$select=' +($property -join ',')}
                    $result = Invoke-GraphRequest  -ValueOnly  @webparams
                }
                if     ($AppRoleFilter) {
                    $(foreach ($r in $result) {$r.approles |
                            Where-Object {$_.id -like $AppRoleFilter  -or $_.DisplayName -like $AppRoleFilter -or $_.value -like $AppRoleFilter } |
                            Add-Member -PassThru -NotePropertyName ServicePrincipal -NotePropertyValue $r.Id} ) |
                                Sort-Object -Property Value
                }
                elseif ($ScopeFilter)    {
                    $(foreach ($r in $result) {$r.Oauth2PermissionScopes |
                        Where-Object {$_.id -like $ScopeFilter  -or $_.AdminConsentDisplayName -like $ScopeFilter -or $_.value -like $ScopeFilter } |
                            Add-Member -PassThru -NotePropertyName ServicePrincipal -NotePropertyValue $r.Id} ) |
                                Sort-Object -Property Value
                }
                else {$result | Sort-Object -Property displayname}
            }
        }
    }
}

function Get-GraphApplication {
    <#
      .Synopsis
        Returns information about Applications
    #>


    [CmdletBinding(DefaultParameterSetName='List1')]
    [OutputType([Microsoft.Graph.PowerShell.Models.MicrosoftGraphApplication])]
    param   (
        [Parameter(ParameterSetName='List3',Position=0)]
        [string]$Id,

        #The GUID(s) for Apps(s). Or App objects. If a name is given instead, the command will try to resolve matching App principals
        [Parameter(ParameterSetName='List2',ValueFromPipelineByPropertyName=$true)]
        [string]$AppId,

        #Select properties to be returned
        [Alias('Select')]
        [String[]]$Property,

        #Filters items by property values
        [Parameter(ParameterSetName='List1')]
        [String]$Filter
    )
    process {
        $result = @()
        $webparams = @{
                    ExcludeProperty = @('verifiedPublisher', 'applicationTemplateId','addins','@odata.context')
                    Headers         = @{'ConsistencyLevel'= 'Eventual'}
        }
        if ( -not    $Id)    {
            if      ($PSBoundParameters['Filter']) {$filter  = "?`$filter=$($PSBoundParameters['Filter'])"}
            elseif  ($AppId)                       {$filter  = "?`$filter=AppID eq '$AppId'"}
            if      ($Property -and $filter)       {$filter +=  '&$select=' +($property -join ',')}
            elseif  ($Property)                    {$filter  =  '?$select=' +($property -join ',')}

            $result += Invoke-GraphRequest "$GraphUri/Applications$filter" -ValueOnly @webparams
        }
        else {
            foreach ($app in $Id) {
                if  ($app -match $GUIDRegex)      {
                    $webparams['uri'] = "$GraphUri/applications/$app"
                    if ($Property) {$webparams['uri'] += '?$select=' +($property -join ',')}
                    try   { $result += Invoke-GraphRequest @webparams}
                    catch {
                            if ($_.Exception.Response.StatusCode.value__  -eq 404) {
                                Write-Warning "$sp was not found as an ID It may be an APPID.";  continue
                            }
                            else {throw $_.Exception }
                    }
                }
                else   {
                        $filter =  '?$filter=' + (FilterString $app)
                        if ($Property) {$filter += '&$select=' +($property -join ',')}
                        $result += Invoke-GraphRequest "$GraphUri/applications$filter" -ValueOnly  @webparams
                }
            }
        }
        foreach ($r in $result) {
            foreach ($p in $r.passwordCredentials) {
                $p.customKeyIdentifier = [byte[]][char[]]$p.customKeyIdentifier
            }
            foreach ($k in $r.keyCredentials) {
                $k.customKeyIdentifier = [byte[]][char[]]$k.customKeyIdentifier
            }
            New-Object -TypeName MicrosoftGraphApplication -Property $r
        }
    }
}