Microsoft.Entra.Users.psm1
# ------------------------------------------------------------------------------ # Copyright (c) Microsoft Corporation. All Rights Reserved. # Licensed under the MIT License. See License in the project root for license information. # ------------------------------------------------------------------------------ Set-StrictMode -Version 5 function Get-EntraDeletedUser { [CmdletBinding(DefaultParameterSetName = 'GetQuery')] param ( [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Filter to apply to the query.")] [System.String] $Filter, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Retrieve all deleted users.")] [switch] $All, [Parameter(ParameterSetName = "GetVague", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Search string to use for vague queries.")] [System.String] $SearchString, [Parameter(ParameterSetName = "GetById", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "ID of the user to retrieve.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName', 'Id')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Alias('Limit')] [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Maximum number of results to return.")] [System.Nullable`1[System.Int32]] $Top, [Alias('Select')] [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")] [System.String[]] $Property ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand $keysChanged = @{SearchString = "Filter" } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["ProgressAction"]) { $params["ProgressAction"] = $PSBoundParameters["ProgressAction"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["Filter"]) { $TmpValue = $PSBoundParameters["Filter"] foreach ($i in $keysChanged.GetEnumerator()) { $TmpValue = $TmpValue.Replace($i.Key, $i.Value) } $Value = $TmpValue $params["Filter"] = $Value } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["All"]) { if ($PSBoundParameters["All"]) { $params["All"] = $PSBoundParameters["All"] } } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["SearchString"]) { $TmpValue = $PSBoundParameters["SearchString"] $Value = "mailNickName eq '$TmpValue' or (mail eq '$TmpValue' or (displayName eq '$TmpValue' or startswith(displayName,'$TmpValue')))" $params["Filter"] = $Value } if ($null -ne $PSBoundParameters["UserId"]) { $params["DirectoryObjectId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($PSBoundParameters.ContainsKey("Top")) { $params["Top"] = $PSBoundParameters["Top"] } if ($null -ne $PSBoundParameters["Property"]) { $params["Property"] = $PSBoundParameters["Property"] } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") # Make the API call try { # Make the API call with -PageSize 999 if -All is used if ($PSBoundParameters.ContainsKey("All") -and $All) { $response = Get-MgDirectoryDeletedItemAsUser @params -PageSize 999 -Headers $customHeaders } else { $response = Get-MgDirectoryDeletedItemAsUser @params -Headers $customHeaders } $response | ForEach-Object { if ($null -ne $_) { if ($null -ne $_.DeletedDateTime) { # Add DeletionAgeInDays property $deletionAgeInDays = (Get-Date) - ($_.DeletedDateTime) Add-Member -InputObject $_ -MemberType NoteProperty -Name DeletionAgeInDays -Value ($deletionAgeInDays.Days) -Force } } } return $response } catch { # Handle any errors that occur during the API call Write-Error "An error occurred while retrieving deleted users: $_" } } } function Get-EntraInactiveSignInUser { [CmdletBinding()] [OutputType([string])] param ( # User Last Sign In Activity is before Days ago [Parameter(ValueFromPipeline = $true, Position = 1)] [Alias("BeforeDaysAgo")] [ValidateRange(0,30)] [int] $LastSignInBeforeDaysAgo = 30, # Return results for All, Member, or Guest userTypes [ValidateSet("All", "Member", "Guest")] [string] $UserType = "All" ) process { $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand $queryDate = (Get-Date).AddDays(-$LastSignInBeforeDaysAgo).ToString("yyyy-MM-ddTHH:mm:ssZ") $inactiveFilter = "(signInActivity/lastSignInDateTime le $queryDate)" $uri = "/v1.0/users?`$filter=$inactiveFilter&`$select=signInActivity,UserPrincipalName,Id,DisplayName,mail,userType,createdDateTime,accountEnabled" Write-Debug ("Retrieving Users with Filter {0}" -f $inactiveFilter) $queryUsers = (Invoke-GraphRequest -Method GET -Uri $uri -Headers $customHeaders).value switch ($UserType) { "Member" { $users = $queryUsers | Where-Object { $_.userType -eq 'Member' } } "Guest" { $users = $queryUsers | Where-Object { $_.userType -eq 'Guest' } } "All" { $users = $queryUsers } } $users.Count | Write-Debug foreach ($userObject in $users) { # Some objects only have the id and signInActivity properties, # so we need to check for the existence of UserPrincipalName and ignore them in the response # { # "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users(id,signInActivity)/$entity", # "id": "740d59d4-057f-4a6d-838b-a30bf3e31ec4", # "signInActivity": { # "lastSignInDateTime": "2024-08-22T04:13:19Z", # "lastSignInRequestId": "bcbac647-1e81-45cb-9e45-c670173e1700", # "lastNonInteractiveSignInDateTime": null, # "lastNonInteractiveSignInRequestId": null, # "lastSuccessfulSignInDateTime": "2024-08-22T04:13:19Z", # "lastSuccessfulSignInRequestId": "bcbac647-1e81-45cb-9e45-c670173e1700" # } # } # If you run GET https://graph.microsoft.com/v1.0/users/740d59d4-057f-4a6d-838b-a30bf3e31ec4 # you will get ResourceNotFound error. # If you run GET https://graph.microsoft.com/v1.0/users/740d59d4-057f-4a6d-838b-a30bf3e31ec4?$select=id,signInActivity # you will get the response above. if (-not($userObject.ContainsKey("UserPrincipalName"))) { continue } $checkedUser = [ordered] @{ UserID = $userObject.Id DisplayName = $userObject.DisplayName UserPrincipalName = $userObject.UserPrincipalName Mail = $userObject.Mail UserType = $userObject.UserType AccountEnabled = $userObject.AccountEnabled } If ($null -eq $userObject.signInActivity.LastSignInDateTime) { $checkedUser["LastSignInDateTime"] = "Unknown" $checkedUser["LastSigninDaysAgo"] = "Unknown" $checkedUser["lastNonInteractiveSignInDateTime"] = "Unknown" } else { $checkedUser["LastSignInDateTime"] = $userObject.signInActivity.LastSignInDateTime $checkedUser["LastSigninDaysAgo"] = (New-TimeSpan -Start $checkedUser.LastSignInDateTime -End (Get-Date)).Days $checkedUser["lastSignInRequestId"] = $userObject.signInActivity.lastSignInRequestId If ($null -eq $userObject.signInActivity.lastNonInteractiveSignInDateTime) { $checkedUser["lastNonInteractiveSignInDateTime"] = "Unknown" $checkedUser["LastNonInteractiveSigninDaysAgo"] = "Unknown" } else { $checkedUser["lastNonInteractiveSignInDateTime"] = $userObject.signInActivity.lastNonInteractiveSignInDateTime $checkedUser["LastNonInteractiveSigninDaysAgo"] = (New-TimeSpan -Start $checkedUser.lastNonInteractiveSignInDateTime -End (Get-Date)).Days $checkedUser["lastNonInteractiveSignInRequestId"] = $userObject.signInActivity.lastNonInteractiveSignInRequestId } } If ($null -eq $userObject.CreatedDateTime) { $checkedUser["CreatedDateTime"] = "Unknown" $checkedUser["CreatedDaysAgo"] = "Unknown" } else { $checkedUser["CreatedDateTime"] = $userObject.CreatedDateTime $checkedUser["CreatedDaysAgo"] = (New-TimeSpan -Start $userObject.CreatedDateTime -End (Get-Date)).Days } Write-Output ([PSCustomObject]$checkedUser) } } } function Get-EntraUnsupportedCommand { Throw [System.NotSupportedException] "This command is not supported by Microsoft Entra PowerShell." } function Get-EntraUser { [CmdletBinding(DefaultParameterSetName = 'GetQuery')] [Alias("Get-AzureADUser")] param ( [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Maximum number of results to return.")] [Alias("Limit")] [System.Nullable`1[System.Int32]] $Top, [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [Parameter(ParameterSetName = "GetById", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [System.String] $UserId, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Return all users.")] [switch] $All, [Parameter(ParameterSetName = "GetVague", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Search for users using a search string from different properties e.g. DisplayName, Job Title, UPN etc.")] [System.String] $SearchString, [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Filter to apply to the query.")] [System.String] $Filter, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")] [Alias("Select")] [System.String[]] $Property ) PROCESS { $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand $params = @{} $topCount = $null $upnPresent = $false $baseUri = '/v1.0/users' $properties = '$select=Id,AccountEnabled,AgeGroup,OfficeLocation,AssignedLicenses,AssignedPlans,City,CompanyName,ConsentProvidedForMinor,Country,CreationType,Department,DisplayName,GivenName,OnPremisesImmutableId,JobTitle,LegalAgeGroupClassification,Mail,MailNickName,MobilePhone,OnPremisesSecurityIdentifier,OtherMails,PasswordPolicies,PasswordProfile,PostalCode,PreferredLanguage,ProvisionedPlans,OnPremisesProvisioningErrors,ProxyAddresses,RefreshTokensValidFromDateTime,ShowInAddressList,State,StreetAddress,Surname,BusinessPhones,UsageLocation,UserPrincipalName,ExternalUserState,ExternalUserStateChangeDateTime,UserType,OnPremisesLastSyncDateTime,ImAddresses,SecurityIdentifier,OnPremisesUserPrincipalName,ServiceProvisioningErrors,IsResourceAccount,OnPremisesExtensionAttributes,DeletedDateTime,OnPremisesSyncEnabled,EmployeeType,EmployeeHireDate,CreatedDateTime,EmployeeOrgData,preferredDataLocation,Identities,onPremisesSamAccountName,EmployeeId,EmployeeLeaveDateTime,AuthorizationInfo,FaxNumber,OnPremisesDistinguishedName,OnPremisesDomainName,IsLicenseReconciliationNeeded,signInSessionsValidFromDateTime' $params["Method"] = "GET" $params["Uri"] = "$baseUri/?$properties" if ($null -ne $PSBoundParameters["Property"]) { $selectProperties = $PSBoundParameters["Property"] $selectProperties = $selectProperties -Join ',' $properties = "`$select=$($selectProperties)" $params["Uri"] = "$baseUri/?$properties" } if ($PSBoundParameters.ContainsKey("Top")) { $topCount = $PSBoundParameters["Top"] if ($topCount -gt 999) { $params["Uri"] += "&`$top=999" } else { $params["Uri"] += "&`$top=$topCount" } } if ($null -ne $PSBoundParameters["SearchString"]) { $TmpValue = $PSBoundParameters["SearchString"] $SearchString = "`$search=`"userprincipalname:$TmpValue`" OR `"state:$TmpValue`" OR `"mailNickName:$TmpValue`" OR `"mail:$TmpValue`" OR `"jobTitle:$TmpValue`" OR `"displayName:$TmpValue`" OR `"department:$TmpValue`" OR `"country:$TmpValue`" OR `"city:$TmpValue`"" $params["Uri"] += "&$SearchString" $customHeaders['ConsistencyLevel'] = 'eventual' } if ($null -ne $PSBoundParameters["UserId"]) { $UserId = $PSBoundParameters["UserId"] if ($UserId -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$') { $f = '$' + 'Filter' $Filter = "UserPrincipalName eq '$UserId'" $params["Uri"] += "&$f=$Filter" $upnPresent = $true } else { $params["Uri"] = "$baseUri/$($UserId)?$properties" } } if ($null -ne $PSBoundParameters["Filter"]) { $Filter = $PSBoundParameters["Filter"] $f = '$' + 'Filter' $params["Uri"] += "&$f=$Filter" } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Invoke-GraphRequest @params -Headers $customHeaders if ($upnPresent -and ($null -eq $response.value -or $response.value.Count -eq 0)) { Write-Error "Resource '$UserId' does not exist or one of its queried reference-property objects are not present. Status: 404 (NotFound) ErrorCode: Request_ResourceNotFound" } $data = $response | ConvertTo-Json -Depth 10 | ConvertFrom-Json try { $data = $response.value | ConvertTo-Json -Depth 10 | ConvertFrom-Json $all = $All.IsPresent $increment = $topCount - $data.Count while (($response.'@odata.nextLink' -and (($all -and ($increment -lt 0)) -or $increment -gt 0))) { $params["Uri"] = $response.'@odata.nextLink' if ($increment -gt 0) { $topValue = [Math]::Min($increment, 999) $params["Uri"] = $params["Uri"].Replace('$top=999', "`$top=$topValue") $increment -= $topValue } $response = Invoke-GraphRequest @params $data += $response.value | ConvertTo-Json -Depth 10 | ConvertFrom-Json } } catch {} $data | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id Add-Member -InputObject $_ -MemberType AliasProperty -Name UserState -Value ExternalUserState Add-Member -InputObject $_ -MemberType AliasProperty -Name UserStateChangedOn -Value ExternalUserStateChangeDateTime Add-Member -InputObject $_ -MemberType AliasProperty -Name Mobile -Value mobilePhone Add-Member -InputObject $_ -MemberType AliasProperty -Name DeletionTimestamp -Value DeletedDateTime Add-Member -InputObject $_ -MemberType AliasProperty -Name DirSyncEnabled -Value OnPremisesSyncEnabled Add-Member -InputObject $_ -MemberType AliasProperty -Name ImmutableId -Value onPremisesImmutableId Add-Member -InputObject $_ -MemberType AliasProperty -Name LastDirSyncTime -Value OnPremisesLastSyncDateTime Add-Member -InputObject $_ -MemberType AliasProperty -Name ProvisioningErrors -Value onPremisesProvisioningErrors Add-Member -InputObject $_ -MemberType AliasProperty -Name TelephoneNumber -Value BusinessPhones } } if ($data) { $userList = @() foreach ($response in $data) { $userType = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphUser $response.PSObject.Properties | ForEach-Object { $propertyName = $_.Name $propertyValue = $_.Value $userType | Add-Member -MemberType NoteProperty -Name $propertyName -Value $propertyValue -Force } $userList += $userType } $userList } } } function Get-EntraUserAdministrativeUnit { [CmdletBinding(DefaultParameterSetName = 'GetQuery')] param ( [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Filter to apply to the query.")] [System.String] $Filter, [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Retrieve all user's administrative units.")] [switch] $All, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Alias('DirectoryObjectId')] [Parameter(ParameterSetName = "GetById", Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Administrative Unit ID to retrieve.")] [System.String] $AdministrativeUnitId, [Alias('Limit')] [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Maximum number of results to return.")] [System.Nullable`1[System.Int32]] $Top, [Alias('Select')] [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")] [System.String[]] $Property ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes AdministrativeUnit.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand $keysChanged = @{ SearchString = "Filter" } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["AdministrativeUnitId"]) { $params["DirectoryObjectId"] = $PSBoundParameters["AdministrativeUnitId"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["SearchString"]) { $TmpValue = $PSBoundParameters["SearchString"] $Value = "displayName eq '$TmpValue' or startsWith(displayName,'$TmpValue')" $params["Filter"] = $Value } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["Top"]) { $params["Top"] = $PSBoundParameters["Top"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["All"]) { if ($PSBoundParameters["All"]) { $params["All"] = $PSBoundParameters["All"] } } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["Property"]) { $params["Property"] = $PSBoundParameters["Property"] } # Debug logging for transformations Write-Debug "============================ TRANSFORMATIONS ============================" $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug "=========================================================================`n" try { # Make the API call with -PageSize 999 if -All is used if ($PSBoundParameters.ContainsKey("All") -and $All) { $response = Get-MgUserMemberOfAsAdministrativeUnit @params -PageSize 999 -Headers $customHeaders } else { $response = Get-MgUserMemberOfAsAdministrativeUnit @params -Headers $customHeaders } return $response } catch { # Handle any errors that occur during the API call Write-Error "An error occurred while retrieving the user's administrative units: $_" } } } function Get-EntraUserAppRoleAssignment { [CmdletBinding(DefaultParameterSetName = 'GetQuery')] param ( [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Maximum number of results to return.")] [Alias("Limit")] [System.Nullable`1[System.Int32]] $Top, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Return all items.")] [switch] $All, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")] [Alias("Select")] [System.String[]] $Property ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes AppRoleAssignment.ReadWrite.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($PSBoundParameters.ContainsKey("Top")) { $params["Top"] = $PSBoundParameters["Top"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["All"]) { if ($PSBoundParameters["All"]) { $params["All"] = $PSBoundParameters["All"] } } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["ProgressAction"]) { $params["ProgressAction"] = $PSBoundParameters["ProgressAction"] } if ($null -ne $PSBoundParameters["Property"]) { $params["Property"] = $PSBoundParameters["Property"] } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Get-MgUserAppRoleAssignment @params -Headers $customHeaders $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id } } $response } } function Get-EntraUserCreatedObject { [CmdletBinding(DefaultParameterSetName = 'GetQuery')] param ( [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The maximum number of items to return.")] [Alias("Limit")] [System.Nullable`1[System.Int32]] $Top, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The unique identifier for the user (User Principal Name or UserId).")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Return all items.")] [switch] $All, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "The properties to include in the response.")] [Alias("Select")] [System.String[]] $Property ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["All"]) { if ($PSBoundParameters["All"]) { $params["All"] = $PSBoundParameters["All"] } } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($PSBoundParameters.ContainsKey("Top")) { $params["Top"] = $PSBoundParameters["Top"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["Property"]) { $params["Property"] = $PSBoundParameters["Property"] } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Get-MgUserCreatedObject @params -Headers $customHeaders $properties = @{ ObjectId = "Id" DeletionTimestamp = "deletedDateTime" AppOwnerTenantId = "appOwnerOrganizationId" } $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -NotePropertyMembers $_.AdditionalProperties foreach ($prop in $properties.GetEnumerator()) { $propertyName = $prop.Name $propertyValue = $prop.Value if ($_.PSObject.Properties.Match($propertyName)) { $_ | Add-Member -MemberType AliasProperty -Name $propertyName -Value $propertyValue } } $propsToConvert = @('keyCredentials', 'passwordCredentials', 'requiredResourceAccess') foreach ($prop in $propsToConvert) { try { if ($_.PSObject.Properties.Match($prop)) { $value = $_.$prop | ConvertTo-Json -Depth 10 | ConvertFrom-Json $_ | Add-Member -MemberType NoteProperty -Name $prop -Value ($value) -Force } } catch {} } } } $response } } function Get-EntraUserDirectReport { [CmdletBinding(DefaultParameterSetName = 'GetQuery')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Return all items.")] [switch] $All, [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Maximum number of results to return.")] [Alias("Limit")] [System.Nullable`1[System.Int32]] $Top, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")] [Alias("Select")] [System.String[]] $Property ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand $topCount = $null $baseUri = '/v1.0/users' $properties = '$select=*' $Method = "GET" if ($null -ne $PSBoundParameters["Property"]) { $selectProperties = $PSBoundParameters["Property"] $selectProperties = $selectProperties -Join ',' $properties = "`$select=$($selectProperties)" } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] $URI = "$baseUri/$($params.UserId)/directReports?$properties" } if ($null -ne $PSBoundParameters["All"]) { $URI = "$baseUri/$($params.UserId)/directReports?$properties" } if ($PSBoundParameters.ContainsKey("Top")) { $topCount = $PSBoundParameters["Top"] $URI = "$baseUri/$($params.UserId)/directReports?`$top=$topCount&$properties" } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = (Invoke-GraphRequest -Headers $customHeaders -Uri $URI -Method $Method).value $response = $response | ConvertTo-Json -Depth 10 | ConvertFrom-Json $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id Add-Member -InputObject $_ -MemberType AliasProperty -Name DeletionTimestamp -Value DeletedDateTime Add-Member -InputObject $_ -MemberType AliasProperty -Name DirSyncEnabled -Value OnPremisesSyncEnabled Add-Member -InputObject $_ -MemberType AliasProperty -Name ImmutableId -Value onPremisesImmutableId Add-Member -InputObject $_ -MemberType AliasProperty -Name LastDirSyncTime -Value OnPremisesLastSyncDateTime Add-Member -InputObject $_ -MemberType AliasProperty -Name Mobile -Value mobilePhone Add-Member -InputObject $_ -MemberType AliasProperty -Name ProvisioningErrors -Value onPremisesProvisioningErrors Add-Member -InputObject $_ -MemberType AliasProperty -Name TelephoneNumber -Value BusinessPhones Add-Member -InputObject $_ -MemberType AliasProperty -Name UserState -Value ExternalUserState Add-Member -InputObject $_ -MemberType AliasProperty -Name UserStateChangedOn -Value ExternalUserStateChangeDateTime } } if ($response) { $userList = @() foreach ($data in $response) { $userType = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphDirectoryObject $data.PSObject.Properties | ForEach-Object { $propertyName = $_.Name $propertyValue = $_.Value $userType | Add-Member -MemberType NoteProperty -Name $propertyName -Value $propertyValue -Force } $userList += $userType } $userList } } } function Get-EntraUserExtension { [CmdletBinding(DefaultParameterSetName = 'Default', SupportsShouldProcess)] [OutputType([PSCustomObject])] param ( [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [string]$UserId, [Parameter(HelpMessage = "Properties to include in the results.")] [Alias("Select")] [string[]]$Property, [Parameter(HelpMessage = "Filter to only show properties synced from on-premises")] [System.Nullable[bool]]$IsSyncedFromOnPremises ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } # Define standard user properties $standardProperties = @( 'id', 'userPrincipalName', 'createdDateTime', 'employeeId', 'onPremisesDistinguishedName', 'identities' ) # Retrieve available extension properties once try { Write-Verbose "Retrieving available extension properties..." # Call Microsoft Graph API directly instead of using Get-EntraExtensionProperty $requestBody = @{ isSyncedFromOnPremises = $IsSyncedFromOnPremises } | ConvertTo-Json $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand $extensionResponse = Invoke-MgGraphRequest -Method POST -Uri "/v1.0/directoryObjects/getAvailableExtensionProperties" ` -Body $requestBody # Extract extension property names $extensions = if ($PSBoundParameters.ContainsKey('IsSyncedFromOnPremises')) { $extensionResponse.value | Where-Object { $_.isSyncedFromOnPremises -eq $IsSyncedFromOnPremises } | ForEach-Object { $_.name } } else { $extensionResponse.value | ForEach-Object { $_.name } } # Combine standard and extension properties $allProperties = $standardProperties + $extensions } catch { Write-Warning "Failed to retrieve extension properties: $_" $extensions = @() $allProperties = $standardProperties } } process { try { # Validate and select properties if ($Property) { $invalidProperties = $Property | Where-Object { $_ -notin $allProperties } if ($invalidProperties) { throw "Invalid property/properties specified: $($invalidProperties -join ', ')" } $selectedProperties = $Property } else { $selectedProperties = $allProperties } # Construct $select query parameter $selectQuery = $selectedProperties -join ',' # Create description for -WhatIf $whatIfDescription = "Retrieving user extension data for UserId: $UserId" if ($Property) { $whatIfDescription += " with properties: $($Property -join ',')" } if ($PSBoundParameters.ContainsKey('IsSyncedFromOnPremises')) { $whatIfDescription += " (SyncedFromOnPremises: $IsSyncedFromOnPremises)" } # Construct URI for the operation $userUri = "/v1.0/users/$UserId`?`$select=$selectQuery" # Add ShouldProcess check if ($PSCmdlet.ShouldProcess($userUri, $whatIfDescription)) { Write-Verbose "Retrieving user data for UserId: $UserId with properties: $selectQuery" # Retrieve user data $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand $data = Invoke-MgGraphRequest -Uri $userUri -Method GET -Headers $customHeaders | ConvertTo-Json | ConvertFrom-Json $data | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name userIdentities -Value identities } } $data | Select-Object * } } catch { Write-Error "Failed to retrieve user data for UserId '$UserId': $_" } } } function Get-EntraUserGroup { [CmdletBinding(DefaultParameterSetName = 'GetQuery')] param ( [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Filter to apply to the query.")] [System.String] $Filter, [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Retrieve all user's group memberships.")] [switch] $All, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "User object ID or UPN to retrieve.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Alias('DirectoryObjectId')] [Parameter(ParameterSetName = "GetById", Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Group object ID to retrieve.")] [System.String] $GroupId, [Alias('Limit')] [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Maximum number of results to return.")] [System.Nullable`1[System.Int32]] $Top, [Alias('Select')] [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")] [System.String[]] $Property ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand $keysChanged = @{ SearchString = "Filter" } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["GroupId"]) { $params["DirectoryObjectId"] = $PSBoundParameters["GroupId"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["SearchString"]) { $TmpValue = $PSBoundParameters["SearchString"] $Value = "displayName eq '$TmpValue' or startsWith(displayName,'$TmpValue')" $params["Filter"] = $Value } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["Top"]) { $params["Top"] = $PSBoundParameters["Top"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["All"]) { if ($PSBoundParameters["All"]) { $params["All"] = $PSBoundParameters["All"] } } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["Property"]) { $params["Property"] = $PSBoundParameters["Property"] } # Debug logging for transformations Write-Debug "============================ TRANSFORMATIONS ============================" $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug "=========================================================================`n" try { # Make the API call with -PageSize 999 if -All is used if ($PSBoundParameters.ContainsKey("All") -and $All) { $response = Get-MgUserMemberOfAsGroup @params -PageSize 999 -Headers $customHeaders } else { $response = Get-MgUserMemberOfAsGroup @params -Headers $customHeaders } return $response } catch { # Handle any errors that occur during the API call Write-Error "An error occurred while retrieving user's group membership: $_" } } } function Get-EntraUserInactiveSignIn { [CmdletBinding(DefaultParameterSetName = 'GetQuery')] [OutputType([string])] param ( # User Last Sign In Activity is before Days ago [Parameter( Mandatory = $true, ValueFromPipeline = $true, HelpMessage = "Number of days to check for Last Sign In Activity" )] [Alias("LastSignInBeforeDaysAgo")] [int] $Ago, # Return results for All, Member, or Guest userTypes [Parameter( HelpMessage = "Specifies the type of user to filter. Choose 'All' for all users, 'Member' for internal users, or 'Guest' for external users." )] [ValidateSet("All", "Member", "Guest")] [System.String] $UserType = "All" ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.Read.All, AuditLog.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } process { $Params = @{} $CustomHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand foreach ($Param in @("Debug", "WarningVariable", "InformationVariable", "InformationAction", "OutVariable", "OutBuffer", "ErrorVariable", "PipelineVariable", "ErrorAction", "WarningAction")) { if ($PSBoundParameters.ContainsKey($Param)) { $Params[$Param] = $PSBoundParameters[$Param] } } $QueryDate = Get-Date (Get-Date).AddDays($(0 - $Ago)) -UFormat %Y-%m-%dT00:00:00Z $QueryFilter = ("(signInActivity/lastSignInDateTime le {0})" -f $QueryDate) Write-Debug ("Retrieving Users with Filter {0}" -f $QueryFilter) Write-Debug("============================ TRANSFORMATIONS ============================") $Params.Keys | ForEach-Object { "$_ : $($Params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $QueryUsers = Get-MgUser -Filter $QueryFilter -PageSize 999 -All -Property signInActivity, UserPrincipalName, Id, DisplayName, Mail, UserType, CreatedDateTime, AccountEnabled -Headers $CustomHeaders $Users = if ($UserType -eq "All") { $QueryUsers } else { $QueryUsers | Where-Object { $_.UserType -eq $UserType } } foreach ($UserObject in $Users) { $CheckedUser = [ordered] @{ UserID = $UserObject.Id DisplayName = $UserObject.DisplayName UserPrincipalName = $UserObject.UserPrincipalName Mail = $UserObject.Mail UserType = $UserObject.UserType AccountEnabled = $UserObject.AccountEnabled LastSignInDateTime = $UserObject.SignInActivity.LastSignInDateTime LastSigninDaysAgo = if ($null -eq $UserObject.SignInActivity.LastSignInDateTime) { "Unknown" } else { (New-TimeSpan -Start $UserObject.SignInActivity.LastSignInDateTime -End (Get-Date)).Days } LastSignInRequestId = $UserObject.SignInActivity.LastSignInRequestId LastNonInteractiveSignInDateTime = if ($null -eq $UserObject.SignInActivity.LastNonInteractiveSignInDateTime) { "Unknown" } else { $UserObject.SignInActivity.LastNonInteractiveSignInDateTime } LastNonInteractiveSigninDaysAgo = if ($null -eq $UserObject.SignInActivity.LastNonInteractiveSignInDateTime) { "Unknown" } else { (New-TimeSpan -Start $UserObject.SignInActivity.LastNonInteractiveSignInDateTime -End (Get-Date)).Days } LastNonInteractiveSignInRequestId = $UserObject.SignInActivity.LastNonInteractiveSignInRequestId CreatedDateTime = if ($null -eq $UserObject.CreatedDateTime) { "Unknown" } else { $UserObject.CreatedDateTime } CreatedDaysAgo = if ($null -eq $UserObject.CreatedDateTime) { "Unknown" } else { (New-TimeSpan -Start $UserObject.CreatedDateTime -End (Get-Date)).Days } } Write-Output ([PSCustomObject]$CheckedUser) } } } function Get-EntraUserLicenseDetail { [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")] [Alias("Select")] [System.String[]] $Property ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["ProgressAction"]) { $params["ProgressAction"] = $PSBoundParameters["ProgressAction"] } if ($null -ne $PSBoundParameters["Property"]) { $params["Property"] = $PSBoundParameters["Property"] } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Get-MgUserLicenseDetail @params -Headers $customHeaders $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id } } $response } } function Get-EntraUserManager { [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")] [Alias("Select")] [System.String[]] $Property ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand $Method = "GET" $keysChanged = @{UserId = "Id" } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } $URI = "/v1.0/users/$($params.UserId)/manager?`$select=*" if ($null -ne $PSBoundParameters["Property"]) { $selectProperties = $PSBoundParameters["Property"] $selectProperties = $selectProperties -Join ',' $properties = "`$select=$($selectProperties)" $URI = "/v1.0/users/$($params.UserId)/manager?$properties" } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Invoke-GraphRequest -Headers $customHeaders -Uri $URI -Method $Method -ErrorAction Stop try { $response = $response | ConvertTo-Json -Depth 5 | ConvertFrom-Json $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id } } if ($response) { $userList = @() foreach ($data in $response) { $userType = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphDirectoryObject $data.PSObject.Properties | ForEach-Object { $propertyName = $_.Name $propertyValue = $_.Value $userType | Add-Member -MemberType NoteProperty -Name $propertyName -Value $propertyValue -Force } $userList += $userType } $userList } } catch {} } } function Get-EntraUserMembership { [CmdletBinding(DefaultParameterSetName = 'GetQuery')] param ( [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Maximum number of results to return.")] [Alias("Limit")] [System.Nullable`1[System.Int32]] $Top, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Return all items.")] [switch] $All, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")] [Alias("Select")] [System.String[]] $Property ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($PSBoundParameters.ContainsKey("Top")) { $params["Top"] = $PSBoundParameters["Top"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["All"]) { if ($PSBoundParameters["All"]) { $params["All"] = $PSBoundParameters["All"] } } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["ProgressAction"]) { $params["ProgressAction"] = $PSBoundParameters["ProgressAction"] } if ($null -ne $PSBoundParameters["Property"]) { $params["Property"] = $PSBoundParameters["Property"] } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Get-MgUserMemberOf @params -Headers $customHeaders $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -NotePropertyMembers $_.AdditionalProperties Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id } } $response } } function Get-EntraUserOAuth2PermissionGrant { [CmdletBinding(DefaultParameterSetName = 'GetQuery')] param ( [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Maximum number of results to return.")] [Alias("Limit")] [System.Nullable`1[System.Int32]] $Top, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Return all items.")] [switch] $All, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")] [Alias("Select")] [System.String[]] $Property ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Directory.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($PSBoundParameters.ContainsKey("Top")) { $params["Top"] = $PSBoundParameters["Top"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["All"]) { if ($PSBoundParameters["All"]) { $params["All"] = $PSBoundParameters["All"] } } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["ProgressAction"]) { $params["ProgressAction"] = $PSBoundParameters["ProgressAction"] } if ($null -ne $PSBoundParameters["Property"]) { $params["Property"] = $PSBoundParameters["Property"] } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Get-MgUserOAuth2PermissionGrant @params -Headers $customHeaders $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id } } $response } } function Get-EntraUserOwnedDevice { [CmdletBinding(DefaultParameterSetName = 'GetQuery')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Return all items.")] [switch] $All, [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Maximum number of results to return.")] [Alias("Limit")] [System.Nullable`1[System.Int32]] $Top, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")] [Alias("Select")] [System.String[]] $Property ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["All"]) { if ($PSBoundParameters["All"]) { $params["All"] = $PSBoundParameters["All"] } } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($PSBoundParameters.ContainsKey("Top")) { $params["Top"] = $PSBoundParameters["Top"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["Property"]) { $params["Property"] = $PSBoundParameters["Property"] } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Get-MgUserOwnedDevice @params -Headers $customHeaders $response | ForEach-Object { if ($null -ne $_) { $propsToConvert = @('AdditionalProperties') foreach ($prop in $propsToConvert) { $value = $_.$prop | ConvertTo-Json -Depth 10 | ConvertFrom-Json $_ | Add-Member -MemberType NoteProperty -Name $prop -Value ($value) -Force } } } $response } } function Get-EntraUserOwnedObject { [CmdletBinding(DefaultParameterSetName = 'GetQuery')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Return all items.")] [switch] $All, [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Maximum number of results to return.")] [Alias("Limit")] [System.Nullable`1[System.Int32]] $Top, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")] [Alias("Select")] [System.String[]] $Property ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } $URI = "/v1.0/users/$($params.UserId)/ownedObjects" if ($null -ne $PSBoundParameters["Property"]) { $selectProperties = $PSBoundParameters["Property"] $selectProperties = $selectProperties -Join ',' $properties = "`$select=$($selectProperties)" $URI = "/v1.0/users/$($params.UserId)/ownedObjects?$properties" } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $Method = "GET" $response = (Invoke-GraphRequest -Headers $customHeaders -Uri $URI -Method $Method).value; $Top = $null if ($PSBoundParameters.ContainsKey("Top")) { $Top = $PSBoundParameters["Top"] } if ($null -ne $Top) { $userList = @() $response | ForEach-Object { if ($null -ne $_ -and $Top -gt 0) { $data = $_ | ConvertTo-Json -Depth 10 | ConvertFrom-Json $userType = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphDirectoryObject $data.PSObject.Properties | ForEach-Object { $propertyName = $_.Name $propertyValue = $_.Value $userType | Add-Member -MemberType NoteProperty -Name $propertyName -Value $propertyValue -Force } $userList += $userType $Top = $Top - 1 } } $userList } else { $userList = @() $response | ForEach-Object { if ($null -ne $_) { $data = $_ | ConvertTo-Json -Depth 10 | ConvertFrom-Json $userType = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphDirectoryObject $data.PSObject.Properties | ForEach-Object { $propertyName = $_.Name $propertyValue = $_.Value $userType | Add-Member -MemberType NoteProperty -Name $propertyName -Value $propertyValue -Force } $userList += $userType } } $userList } } } function Get-EntraUserRegisteredDevice { [CmdletBinding(DefaultParameterSetName = 'GetQuery')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The unique identifier for the user (User Principal Name or UserId).")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Return all registered devices.")] [switch] $All, [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The maximum number of items to return.")] [Alias("Limit")] [System.Nullable`1[System.Int32]] $Top, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "The properties to include in the response.")] [Alias("Select")] [System.String[]] $Property ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["All"]) { if ($PSBoundParameters["All"]) { $params["All"] = $PSBoundParameters["All"] } } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($PSBoundParameters.ContainsKey("Top")) { $params["Top"] = $PSBoundParameters["Top"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["Property"]) { $params["Property"] = $PSBoundParameters["Property"] } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Get-MgUserRegisteredDevice @params -Headers $customHeaders $response | ForEach-Object { if ($null -ne $_) { $propsToConvert = @('AdditionalProperties') foreach ($prop in $propsToConvert) { $value = $_.$prop | ConvertTo-Json -Depth 10 | ConvertFrom-Json $_ | Add-Member -MemberType NoteProperty -Name $prop -Value ($value) -Force } } } $response } } function Get-EntraUserRole { [CmdletBinding(DefaultParameterSetName = 'GetQuery')] param ( [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Filter to apply to the query.")] [System.String] $Filter, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Retrieve all user roles.")] [switch] $All, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Alias('DirectoryObjectId')] [Parameter(ParameterSetName = "GetById", Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Directory Role ID to retrieve.")] [System.String] $DirectoryRoleId, [Alias('Limit')] [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Maximum number of results to return.")] [System.Nullable`1[System.Int32]] $Top, [Alias('Select')] [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")] [System.String[]] $Property, [Parameter(Mandatory = $false, HelpMessage = "Order items by property values.")] [Alias('OrderBy')] [System.String[]] $Sort ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Directory.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand $keysChanged = @{ SearchString = "Filter" } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["DirectoryRoleId"]) { $params["DirectoryObjectId"] = $PSBoundParameters["DirectoryRoleId"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["Filter"]) { $TmpValue = $PSBoundParameters["Filter"] foreach ($i in $keysChanged.GetEnumerator()) { $TmpValue = $TmpValue.Replace($i.Key, $i.Value) } $Value = $TmpValue $params["Filter"] = $Value } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["Top"]) { $params["Top"] = $PSBoundParameters["Top"] } if ($null -ne $PSBoundParameters["Sort"]) { $params["Sort"] = $PSBoundParameters["Sort"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["All"]) { if ($PSBoundParameters["All"]) { $params["All"] = $PSBoundParameters["All"] } } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["Property"]) { $params["Property"] = $PSBoundParameters["Property"] } # Debug logging for transformations Write-Debug "============================ TRANSFORMATIONS ============================" $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug "=========================================================================`n" try { # Make the API call with -PageSize 999 if -All is used if ($PSBoundParameters.ContainsKey("All") -and $All) { $response = Get-MgUserMemberOfAsDirectoryRole @params -PageSize 999 -Headers $customHeaders } else { $response = Get-MgUserMemberOfAsDirectoryRole @params -Headers $customHeaders } return $response } catch { # Handle any errors that occur during the API call Write-Error "An error occurred while retrieving the user roles: $_" } } } function Get-EntraUserSponsor { [CmdletBinding(DefaultParameterSetName = 'GetQuery')] param ( [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Filter to apply to the query.")] [System.String] $Filter, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The unique identifier (User ID) of the user whose sponsor information you want to retrieve.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Alias('Limit')] [Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Maximum number of results to return.")] [System.Nullable`1[System.Int32]] $Top, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Retrieve all user's sponsors.")] [switch] $All, [Alias('DirectoryObjectId')] [Parameter(ParameterSetName = "GetById", Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The User Sponsor ID to retrieve.")] [System.String] $SponsorId, [Alias('Select')] [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")] [System.String[]] $Property ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand $params = @{} $topCount = $null $baseUri = "/v1.0/users/$UserId/sponsors" $properties = '$select=*' $params["Method"] = "GET" $params["Uri"] = "$baseUri/?$properties" if ($null -ne $PSBoundParameters["Property"]) { $selectProperties = $PSBoundParameters["Property"] $selectProperties = $selectProperties -Join ',' $properties = "`$select=$($selectProperties)" $params["Uri"] = "$baseUri/?$properties" } if ($PSBoundParameters.ContainsKey("Top")) { $topCount = $PSBoundParameters["Top"] if ($topCount -gt 999) { $params["Uri"] += "&`$top=999" } else { $params["Uri"] += "&`$top=$topCount" } } if ($null -ne $PSBoundParameters["SponsorId"]) { $params["Uri"] += "&`$filter=id eq '$SponsorId'" } if ($null -ne $PSBoundParameters["Filter"]) { $Filter = $PSBoundParameters["Filter"] $f = '$' + 'Filter' $params["Uri"] += "&$f=$Filter" } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Invoke-GraphRequest -Headers $customHeaders -Uri $($params.Uri) -Method GET | ConvertTo-Json -Depth 10 | ConvertFrom-Json try { $data = $response.value | ConvertTo-Json -Depth 10 | ConvertFrom-Json $all = $All.IsPresent $increment = $topCount - $data.Count while ($response.'@odata.nextLink' -and (($all -and ($increment -lt 0)) -or $increment -gt 0)) { $params["Uri"] = $response.'@odata.nextLink' if ($increment -gt 0) { $topValue = [Math]::Min($increment, 999) $params["Uri"] = $params["Uri"].Replace('$top=999', "`$top=$topValue") $increment -= $topValue } $response = Invoke-GraphRequest -Headers $customHeaders -Uri $URI -Method $Method | ConvertTo-Json -Depth 10 | ConvertFrom-Json $data += $response.value | ConvertTo-Json -Depth 10 | ConvertFrom-Json } } catch {} if ($data) { $memberList = @() foreach ($response in $data) { $memberType = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphDirectoryObject if (-not ($response -is [PSObject])) { $response = [PSCustomObject]@{ Value = $response } } $response.PSObject.Properties | ForEach-Object { $propertyName = $_.Name $propertyValue = $_.Value $memberType | Add-Member -MemberType NoteProperty -Name $propertyName -Value $propertyValue -Force } $memberList += $memberType } return $memberList } } } function Get-EntraUserThumbnailPhoto { [CmdletBinding(DefaultParameterSetName = 'GetQuery')] param ( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "File name to save the photo.")] [System.String] $FileName, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "File path or location to save the photo.")] [System.String] $FilePath, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "View photo.")] [System.Boolean] $View, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")] [Alias("Select")] [System.String[]] $Property ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.Read.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($null -ne $PSBoundParameters["FileName"]) { $params["FileName"] = $PSBoundParameters["FileName"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["ProgressAction"]) { $params["ProgressAction"] = $PSBoundParameters["ProgressAction"] } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["FilePath"]) { $params["FilePath"] = $PSBoundParameters["FilePath"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["View"]) { $params["View"] = $PSBoundParameters["View"] } if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($null -ne $PSBoundParameters["Property"]) { $params["Property"] = $PSBoundParameters["Property"] } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Get-MgUserPhoto @params -Headers $customHeaders $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id } } $response } } function New-EntraCustomHeaders { <# .SYNOPSIS Creates a custom header for use in telemetry. .DESCRIPTION The custom header created is a User-Agent with header value "<PowerShell version> EntraPowershell/<EntraPowershell version> <Entra PowerShell command>" .PARAMETER Command The command that is being executed. .EXAMPLE New-EntraCustomHeaders -Command Get-EntraUser #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $Command ) $psVersion = $global:PSVersionTable.PSVersion $entraVersion = $ExecutionContext.SessionState.Module.Version.ToString() $userAgentHeaderValue = "PowerShell/$psVersion EntraPowershell/$entraVersion $Command" $customHeaders = New-Object 'system.collections.generic.dictionary[string,string]' $customHeaders["User-Agent"] = $userAgentHeaderValue $customHeaders } function New-EntraUser { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams", "", Scope = "Function", Target = "*")] [CmdletBinding(DefaultParameterSetName = 'CreateUser')] param ( [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The state or province in the user's address. Maximum length is 128 characters.")] [System.String] $State, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The user's fax number.")] [Alias('FacsimileTelephoneNumber', 'Fax')] [System.String] $FaxNumber, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The type of user (e.g., Member, Guest).")] [System.String] $UserType, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The user's preferred language (e.g., en-US).")] [System.String] $PreferredLanguage, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The street address of the user's place of business. Maximum length is 1,024 characters.")] [System.String] $StreetAddress, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "Indicates how the user was created (e.g., LocalAccount, Invitation).")] [System.String] $CreationType, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "Immutable identifier for the user from on-premises directory.")] [System.String] $ImmutableId, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The user's company name, useful for identifying a guest's organization. Maximum length: 64 characters.")] [System.String] $CompanyName, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The user's postal code, specific to their country or region (ZIP code in the U.S.). Maximum length: 40 characters.")] [System.String] $PostalCode, [Parameter(ParameterSetName = "CreateUser", Mandatory = $true, HelpMessage = "The display name of the user.")] [ValidateNotNullOrEmpty()] [System.String] $DisplayName, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "Indicates if consent was obtained for minors. Values: null, Granted, Denied, or NotRequired.")] [System.String] $ConsentProvidedForMinor, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The user's department.")] [System.String] $Department, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The user's mobile phone number.")] [System.String] $Mobile, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "Timestamp of the most recent change to the *externalUserState* property.")] [Alias('UserStateChangedOn')] [System.String] $ExternalUserStateChangeDateTime, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The given name (first name) of the user. Maximum length is 64 characters.")] [System.String] $GivenName, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The user's country or region; for example, US or UK. Maximum length is 128 characters.")] [System.String] $Country, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "Set password policies like DisableStrongPassword or DisablePasswordExpiration. You can use both, separated by a comma.")] [System.String] $PasswordPolicies, [Parameter(ParameterSetName = "CreateUser", Mandatory = $true, HelpMessage = "Defines the user's password profile. Required when creating a user. The password must meet the policy requirements-strong by default.")] [ValidateNotNullOrEmpty()] [Microsoft.Open.AzureAD.Model.PasswordProfile] $PasswordProfile, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The user's mail alias. Required when creating a user. Maximum length: 64 characters.")] [System.String] $MailNickName, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The user's job title. Maximum length: 128 characters.")] [System.String] $JobTitle, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The user's external state for invited guest users (e.g., PendingAcceptance, Accepted).")] [Alias('UserState')] [System.String] $ExternalUserState, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The user's city location. Maximum length: 128 characters.")] [System.String] $City, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "A two-letter country code (ISO 3166). Required for licensed users to verify service availability. Examples: US, JP, GB.")] [System.String] $UsageLocation, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The user's surname (last name). Maximum length: 64 characters.")] [System.String] $Surname, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "A list of the user’s additional email addresses (e.g., ['bob@contoso.com', 'Robert@fabrikam.com']). Supports up to 250 entries, each up to 250 characters.")] [System.Collections.Generic.List`1[System.String]] $OtherMails, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The user's sign-in name (UPN) in the format alias@domain. It should match the user's email and use a verified domain in the tenant.")] [Alias('UPN')] [ValidateNotNullOrEmpty()] [ValidateScript({ try { $null = [System.Net.Mail.MailAddress]$_ return $true } catch { throw "UserPrincipalName must be a valid email address." } })] [System.String] $UserPrincipalName, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "The user's phone number. Only one number is allowed. Read-only for users synced from on-premises.")] [Alias('TelephoneNumber')] [System.String] $BusinessPhones, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "Sets the user's age group. Options: null, Minor, NotAdult, or Adult.")] [System.String] $AgeGroup, [Parameter(ParameterSetName = "CreateUser", Mandatory = $true, HelpMessage = "Indicates if the account is active. Required when creating a user.")] [System.Nullable`1[System.Boolean]] $AccountEnabled, [Parameter(ParameterSetName = "CreateUser", HelpMessage = "Represents the identities that can be used to sign in to this user account. Microsoft (also known as a local account), organizations, or social identity providers such as Facebook, Google, and Microsoft can provide identity and tie it to a user account. It might contain multiple items with the same signInType value.")] [Alias('SignInNames')] [System.Collections.Generic.List`1[Microsoft.Open.AzureAD.Model.SignInName]] $Identities ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.ReadWrite.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["PostalCode"]) { $params["PostalCode"] = $PSBoundParameters["PostalCode"] } if ($null -ne $PSBoundParameters["MailNickName"]) { $params["MailNickName"] = $PSBoundParameters["MailNickName"] } if ($null -ne $PSBoundParameters["ShowInAddressList"]) { $params["ShowInAddressList"] = $PSBoundParameters["ShowInAddressList"] } if ($null -ne $PSBoundParameters["DisplayName"]) { $params["DisplayName"] = $PSBoundParameters["DisplayName"] } if ($null -ne $PSBoundParameters["Mobile"]) { $params["MobilePhone"] = $PSBoundParameters["Mobile"] } if ($null -ne $PSBoundParameters["JobTitle"]) { $params["JobTitle"] = $PSBoundParameters["JobTitle"] } if ($null -ne $PSBoundParameters["ConsentProvidedForMinor"]) { $params["ConsentProvidedForMinor"] = $PSBoundParameters["ConsentProvidedForMinor"] } if ($null -ne $PSBoundParameters["OtherMails"]) { $params["OtherMails"] = $PSBoundParameters["OtherMails"] } if ($null -ne $PSBoundParameters["PasswordPolicies"]) { $params["PasswordPolicies"] = $PSBoundParameters["PasswordPolicies"] } if ($null -ne $PSBoundParameters["SignInNames"]) { $params["Identities"] = $PSBoundParameters["SignInNames"] } if ($null -ne $PSBoundParameters["PreferredLanguage"]) { $params["PreferredLanguage"] = $PSBoundParameters["PreferredLanguage"] } if ($null -ne $PSBoundParameters["ExternalUserState"]) { $params["ExternalUserState"] = $PSBoundParameters["ExternalUserState"] } if ($null -ne $PSBoundParameters["ImmutableId"]) { $params["OnPremisesImmutableId"] = $PSBoundParameters["ImmutableId"] } if ($null -ne $PSBoundParameters["City"]) { $params["City"] = $PSBoundParameters["City"] } if ($null -ne $PSBoundParameters["AgeGroup"]) { $params["AgeGroup"] = $PSBoundParameters["AgeGroup"] } if ($null -ne $PSBoundParameters["UsageLocation"]) { $params["UsageLocation"] = $PSBoundParameters["UsageLocation"] } if ($null -ne $PSBoundParameters["ExternalUserStateChangeDateTime"]) { $params["ExternalUserStateChangeDateTime"] = $PSBoundParameters["ExternalUserStateChangeDateTime"] } if ($null -ne $PSBoundParameters["AccountEnabled"]) { $params["AccountEnabled"] = $PSBoundParameters["AccountEnabled"] } if ($null -ne $PSBoundParameters["Country"]) { $params["Country"] = $PSBoundParameters["Country"] } if ($null -ne $PSBoundParameters["UserPrincipalName"]) { $params["UserPrincipalName"] = $PSBoundParameters["UserPrincipalName"] } if ($null -ne $PSBoundParameters["GivenName"]) { $params["GivenName"] = $PSBoundParameters["GivenName"] } if ($null -ne $PSBoundParameters["PasswordProfile"]) { $TmpValue = $PSBoundParameters["PasswordProfile"] $Value = @{ forceChangePasswordNextSignIn = $TmpValue.ForceChangePasswordNextLogin forceChangePasswordNextSignInWithMfa = $TmpValue.EnforceChangePasswordPolicy password = $TmpValue.Password } $params["passwordProfile"] = $Value } if ($null -ne $PSBoundParameters["UserType"]) { $params["UserType"] = $PSBoundParameters["UserType"] } if ($null -ne $PSBoundParameters["StreetAddress"]) { $params["StreetAddress"] = $PSBoundParameters["StreetAddress"] } if ($null -ne $PSBoundParameters["State"]) { $params["State"] = $PSBoundParameters["State"] } if ($null -ne $PSBoundParameters["Department"]) { $params["Department"] = $PSBoundParameters["Department"] } if ($null -ne $PSBoundParameters["CompanyName"]) { $params["CompanyName"] = $PSBoundParameters["CompanyName"] } if ($null -ne $PSBoundParameters["FaxNumber"]) { $params["faxNumber"] = $PSBoundParameters["FaxNumber"] } if ($null -ne $PSBoundParameters["Surname"]) { $params["Surname"] = $PSBoundParameters["Surname"] } if ($null -ne $PSBoundParameters["BusinessPhones"]) { $params["BusinessPhones"] = @($PSBoundParameters["BusinessPhones"]) } if ($null -ne $PSBoundParameters["CreationType"]) { $params["CreationType"] = $PSBoundParameters["CreationType"] } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $params = $params | ConvertTo-Json $response = Invoke-GraphRequest -Headers $customHeaders -Uri '/v1.0/users?$select=*' -Method POST -Body $params $response = $response | ConvertTo-Json | ConvertFrom-Json $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id Add-Member -InputObject $_ -MemberType AliasProperty -Name UserState -Value ExternalUserState Add-Member -InputObject $_ -MemberType AliasProperty -Name UserStateChangedOn -Value ExternalUserStateChangeDateTime Add-Member -InputObject $_ -MemberType AliasProperty -Name Mobile -Value mobilePhone Add-Member -InputObject $_ -MemberType AliasProperty -Name DeletionTimestamp -Value DeletedDateTime Add-Member -InputObject $_ -MemberType AliasProperty -Name DirSyncEnabled -Value OnPremisesSyncEnabled Add-Member -InputObject $_ -MemberType AliasProperty -Name ImmutableId -Value onPremisesImmutableId Add-Member -InputObject $_ -MemberType AliasProperty -Name LastDirSyncTime -Value OnPremisesLastSyncDateTime Add-Member -InputObject $_ -MemberType AliasProperty -Name ProvisioningErrors -Value onPremisesProvisioningErrors Add-Member -InputObject $_ -MemberType AliasProperty -Name TelephoneNumber -Value BusinessPhones $userData = [Microsoft.Graph.PowerShell.Models.MicrosoftGraphUser]::new() $_.PSObject.Properties | ForEach-Object { $userData | Add-Member -MemberType NoteProperty -Name $_.Name -Value $_.Value -Force } } } $userData } } function New-EntraUserAppRoleAssignment { [CmdletBinding(DefaultParameterSetName = 'ByUserIdAndRoleParameters')] param ( [Parameter(ParameterSetName = "ByUserIdAndRoleParameters", Mandatory = $true, HelpMessage = "Specifies the object ID of the principal (user, group, or service principal) to assign the app role to.")] [ValidateNotNullOrEmpty()] [guid] $PrincipalId, [Parameter(ParameterSetName = "ByUserIdAndRoleParameters", Mandatory = $true, HelpMessage = "Specifies the object ID of the resource service principal (application) that exposes the app role.")] [ValidateNotNullOrEmpty()] [guid] $ResourceId, [Parameter(ParameterSetName = "ByUserIdAndRoleParameters", Mandatory = $true, HelpMessage = "Specifies the ID of the app role to assign to the user.")] [ValidateNotNullOrEmpty()] [Alias("Id")] [guid] $AppRoleId, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of the user (as a UserPrincipalName or ObjectId) to whom the app role is assigned.")] [ValidateNotNullOrEmpty()] [Alias("ObjectId")] [guid] $UserId ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes AppRoleAssignment.ReadWrite.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($null -ne $PSBoundParameters["PrincipalId"]) { $params["PrincipalId"] = $PSBoundParameters["PrincipalId"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["ResourceId"]) { $params["ResourceId"] = $PSBoundParameters["ResourceId"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["AppRoleId"]) { $params["AppRoleId"] = $PSBoundParameters["AppRoleId"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["ProgressAction"]) { $params["ProgressAction"] = $PSBoundParameters["ProgressAction"] } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = New-MgUserAppRoleAssignment @params -Headers $customHeaders $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id } } $response } } function Remove-EntraUser { [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.ReadWrite.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["ProgressAction"]) { $params["ProgressAction"] = $PSBoundParameters["ProgressAction"] } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Remove-MgUser @params -Headers $customHeaders $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id } } $response } } function Remove-EntraUserAppRoleAssignment { [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of the app role assignment to remove.")] [ValidateNotNullOrEmpty()] [guid] $AppRoleAssignmentId, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes AppRoleAssignment.ReadWrite.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($null -ne $PSBoundParameters["AppRoleAssignmentId"]) { $params["AppRoleAssignmentId"] = $PSBoundParameters["AppRoleAssignmentId"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["ProgressAction"]) { $params["ProgressAction"] = $PSBoundParameters["ProgressAction"] } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Remove-MgUserAppRoleAssignment @params -Headers $customHeaders $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id } } $response } } function Remove-EntraUserExtension { [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Parameter(ParameterSetName = "SetMultiple", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [System.Collections.Generic.List`1[System.String]] $ExtensionNames, [Alias('ObjectId')] [Parameter(ParameterSetName = "SetSingle", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Parameter(ParameterSetName = "SetMultiple", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [System.String] $ExtensionId, [Parameter(ParameterSetName = "SetSingle", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [System.String] $ExtensionName ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.ReadWrite.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["ExtensionNames"]) { $params["ExtensionNames"] = $PSBoundParameters["ExtensionNames"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["ExtensionId"]) { $params["ExtensionId"] = $PSBoundParameters["ExtensionId"] } if ($null -ne $PSBoundParameters["ExtensionName"]) { $params["ExtensionName"] = $PSBoundParameters["ExtensionName"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["ProgressAction"]) { $params["ProgressAction"] = $PSBoundParameters["ProgressAction"] } if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Remove-MgUserExtension @params -Headers $customHeaders $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id } } $response } } function Remove-EntraUserManager { [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.ReadWrite.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["ProgressAction"]) { $params["ProgressAction"] = $PSBoundParameters["ProgressAction"] } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Remove-MgUserManagerByRef @params -Headers $customHeaders $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id } } $response } } function Remove-EntraUserSponsor { [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The unique identifier (User ID) of the user whose sponsor you want to remove.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Alias('DirectoryObjectId')] [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The User Sponsor ID to be removed.")] [ValidateNotNullOrEmpty()] [guid] $SponsorId ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.ReadWrite.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand $params = @{} $params["Uri"] = "/v1.0/users/$UserId/sponsors/$SponsorId/`$ref" $params["Method"] = "DELETE" Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Invoke-GraphRequest -Headers $customHeaders -Uri $($params.Uri) -Method $($params.Method) $response } } function Set-EntraUser { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams", "", Scope = "Function", Target = "*")] [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The unique identifier for the user, such as their object ID or user principal name.")] [Alias('ObjectId', 'UPN', 'Identity', 'Id')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [string]$UserId, [Parameter(HelpMessage = "A short biography or description about the user.")] [string]$aboutMe, [Parameter(HelpMessage = "Indicates whether the account is enabled. true if enabled; otherwise, false.")] [bool]$accountEnabled, [Parameter(HelpMessage = "The user's age group. Allowed values: minor, notAdult, adult.")] [ValidateSet("minor", "notAdult", "adult")] [string]$ageGroup, [Parameter(HelpMessage = "The user's birthday.")] [datetime]$birthday, [Parameter(HelpMessage = "The user's business phone numbers.")] [string[]]$businessPhones, [Parameter(HelpMessage = "The city where the user is located.")] [string]$city, [Parameter(HelpMessage = "The company name associated with the user.")] [string]$companyName, [Parameter(HelpMessage = "Indicates if consent has been obtained for minors. Allowed values: Granted, Denied, NotRequired.")] [ValidateSet("Granted", "Denied", "NotRequired")] [string]$consentProvidedForMinor, [Parameter(HelpMessage = "The country/region where the user is located.")] [string]$country, [Parameter(HelpMessage = "The department where the user works.")] [string]$department, [Parameter(HelpMessage = "The name displayed in the address book for the user.")] [string]$displayName, [Parameter(HelpMessage = "The date and time when the user was hired.")] [datetime]$employeeHireDate, [Parameter(HelpMessage = "The date and time when the user will leave the company.")] [datetime]$employeeLeaveDateTime, [Parameter(HelpMessage = "The employee identifier assigned to the user.")] [string]$employeeId, [Parameter(HelpMessage = "The organization data related to the user.")] [hashtable]$employeeOrgData, [Parameter(HelpMessage = "Captures enterprise worker type: Employee, Contractor, Consultant, Vendor, etc.")] [string]$employeeType, [Parameter(HelpMessage = "The user's fax number.")] [string]$faxNumber, [Parameter(HelpMessage = "The given name (first name) of the user.")] [string]$givenName, [Parameter(HelpMessage = "The hire date of the user.")] [datetime]$hireDate, [Parameter(HelpMessage = "The instant message addresses for the user.")] [string[]]$imAddresses, [Parameter(HelpMessage = "A list of interests for the user.")] [string[]]$interests, [Parameter(HelpMessage = "The user's job title.")] [string]$jobTitle, [Parameter(HelpMessage = "Specifies the legal age group classification.")] [string]$legalAgeGroupClassification, [Parameter(HelpMessage = "The SMTP address for the user.")] [string]$mail, [Parameter(HelpMessage = "The mail alias for the user.")] [string]$mailNickname, [Parameter(HelpMessage = "The primary cellular telephone number for the user.")] [string]$mobilePhone, [Parameter(HelpMessage = "The URL for the user's personal site.")] [string]$mySite, [Parameter(HelpMessage = "The office location in the user's place of business.")] [string]$officeLocation, [Parameter(HelpMessage = "A collection of other email addresses for the user.")] [string[]]$otherMails, [Parameter(HelpMessage = "Specifies password policies for the user.")] [string]$passwordPolicies, [Parameter(HelpMessage = "Specifies the password profile for the user.")] [hashtable]$passwordProfile, [Parameter(HelpMessage = "The postal code for the user's postal address.")] [string]$postalCode, [Parameter(HelpMessage = "The preferred data location for the user.")] [string]$preferredDataLocation, [Parameter(HelpMessage = "The preferred language for the user.")] [string]$preferredLanguage, [Parameter(HelpMessage = "The user's surname (last name).")] [string]$surname, [Parameter(HelpMessage = "A two-letter country code (ISO 3166). Required for users who will be assigned licenses.")] [string]$usageLocation, [Parameter(HelpMessage = "The user principal name (UPN) of the user.")] [string]$userPrincipalName, [Parameter(HelpMessage = "The type of user.")] [string]$UserType, [Parameter(HelpMessage = "The street address for the user.")] [string]$StreetAddress, [Parameter(HelpMessage = "The state associated with the user.")] [string]$State, # New: Accepts a hashtable for bulk updates [Parameter(Mandatory = $false, HelpMessage = "A hashtable of additional user properties to update.")] [Alias("BodyParameter", "Body", "BodyParameters")] [hashtable]$AdditionalProperties = @{} # Default to an empty hashtable if not provided ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.ReadWrite.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } process { $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand # Microsoft Graph API URL for updating users $graphUri = "/v1.0/users/$UserId" # Initialize hashtable for user properties $UserProperties = @{} $CommonParameters = @("Verbose", "Debug", "WarningAction", "WarningVariable", "ErrorAction", "ErrorVariable", "OutVariable", "OutBuffer", "WhatIf", "Confirm") # Merge individual parameters into UserProperties foreach ($param in $PSBoundParameters.Keys) { if ($param -ne "UserId" -and $param -ne "AdditionalProperties" -and $CommonParameters -notcontains $param) { $UserProperties[$param] = $PSBoundParameters[$param] } } # Merge AdditionalProperties if provided foreach ($key in $AdditionalProperties.Keys) { $UserProperties[$key] = $AdditionalProperties[$key] } # Convert final update properties to JSON $bodyJson = $UserProperties | ConvertTo-Json -Depth 2 if ($UserProperties.Count -eq 0) { Write-Warning "No properties provided for update. Exiting." return } try { # Invoke Microsoft Graph API Request Invoke-MgGraphRequest -Uri $graphUri -Method PATCH -Body $bodyJson -Headers $customHeaders Write-Verbose "Properties for user $UserId updated successfully. Updated properties: $($UserProperties | Out-String)" } catch { Write-Debug "Error Details: $_" Write-Error "Failed to update user properties: $_" } } } Set-Alias -Name Update-EntraUser -Value Set-EntraUser -Scope Global -Force function Set-EntraUserExtension { [CmdletBinding(DefaultParameterSetName = 'SetSingle')] param ( [Parameter(ParameterSetName = "SetSingle", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The user to set the extension property for. For example, 'user@domain.com'")] [Parameter(ParameterSetName = "SetMultiple", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The user to set the extension property for. For example, 'user@domain.com'")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Parameter(ParameterSetName = "SetMultiple", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The dictionary of extension name and values. For example, @{extension_d2ba83696c3f45429fbabb363ae391a0_JobGroup='Job Group N'; extension_d2ba83696c3f45429fbabb363ae391a0_JobTitle='Job Title N'}")] [ValidateNotNullOrEmpty()] [System.Collections.Generic.Dictionary`2[System.String, System.String]] $ExtensionNameValues, [Parameter(ParameterSetName = "SetSingle", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The value of the extension property to set. For example, 'Job Group N'")] [ValidateNotNullOrEmpty()] [System.String] $ExtensionValue, [Parameter(ParameterSetName = "SetSingle", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The name of the extension property to set. For example, extension_d2ba83696c3f45429fbabb363ae391a0_JobGroup")] [ValidateNotNullOrEmpty()] [System.String] $ExtensionName ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.ReadWrite.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["ProgressAction"]) { $params["ProgressAction"] = $PSBoundParameters["ProgressAction"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($null -ne $PSBoundParameters["ExtensionNameValues"]) { $params["ExtensionNameValues"] = $PSBoundParameters["ExtensionNameValues"] } if ($null -ne $PSBoundParameters["ExtensionValue"]) { $params["ExtensionValue"] = $PSBoundParameters["ExtensionValue"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["ExtensionName"]) { $params["ExtensionName"] = $PSBoundParameters["ExtensionName"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } $uri = "/v1.0/users/$UserId" Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") if ($PSCmdlet.ParameterSetName -eq "SetSingle") { $properties = @{ $ExtensionName = $ExtensionValue } $jsonBody = $properties | ConvertTo-Json -Depth 2 $response = Invoke-MgGraphRequest -Method PATCH -Uri $uri -Body $jsonBody -ContentType "application/json" -Headers $customHeaders return $response } elseif ($PSCmdlet.ParameterSetName -eq "SetMultiple") { $properties = @{} foreach ($key in $ExtensionNameValues.Keys) { $properties[$key] = $ExtensionNameValues[$key] } # Convert hashtable to JSON $jsonBody = $properties | ConvertTo-Json -Depth 2 # Make the PATCH request to update the user properties $response = Invoke-MgGraphRequest -Method PATCH -Uri $uri -Body $jsonBody -ContentType "application/json" -Headers $customHeaders return $response } } } Set-Alias -Name Update-EntraUserExtension -Value Set-EntraUserExtension -Scope Global -Force function Set-EntraUserLicense { [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the licenses to assign to the user.")] [ValidateNotNullOrEmpty()] [Microsoft.Open.AzureAD.Model.AssignedLicenses] $AssignedLicenses ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.ReadWrite.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] $UserId = $PSBoundParameters["UserId"] } $jsonBody = @{ addLicenses = @(if ($PSBoundParameters.AssignedLicenses.AddLicenses) { $PSBoundParameters.AssignedLicenses.AddLicenses | Select-Object @{Name = 'skuId'; Expression = { $_.'skuId' -replace 's', 's'.ToLower() } } } else { @() }) removeLicenses = @(if ($PSBoundParameters.AssignedLicenses.RemoveLicenses) { $PSBoundParameters.AssignedLicenses.RemoveLicenses } else { @() }) } | ConvertTo-Json $customHeaders['Content-Type'] = 'application/json' $graphApiEndpoint = "/v1.0/users/$UserId/microsoft.graph.assignLicense" Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Invoke-GraphRequest -Headers $customHeaders -Uri $graphApiEndpoint -Method Post -Body $jsonBody $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name UserId -Value Id } } $response } } function Set-EntraUserManager { [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Alias('RefObjectId')] [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The manager's unique identifier in Microsoft Entra ID.")] [ValidateNotNullOrEmpty()] [guid] $ManagerId, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The unique identifier of a user in Microsoft Entra ID (User Principal Name or UserId).")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.ReadWrite.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand $rootUri = (Get-EntraEnvironment -Name (Get-EntraContext).Environment).GraphEndpoint if (-not $rootUri) { $rootUri = "https://graph.microsoft.com" Write-Verbose "Using default Graph endpoint: $rootUri" } if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["ProgressAction"]) { $params["ProgressAction"] = $PSBoundParameters["ProgressAction"] } if ($null -ne $PSBoundParameters["ManagerId"]) { $TmpValue = $PSBoundParameters["ManagerId"] $Value = @{ "@odata.id" = "$rootUri/v1.0/users/$TmpValue" } $params["BodyParameter"] = $Value } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Set-MgUserManagerByRef @params -Headers $customHeaders $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id } } $response } } function Set-EntraUserPassword { [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies whether the user must change their password at next sign-in.")] [System.Boolean] $ForceChangePasswordNextLogin, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the password for the user.")] [ValidateNotNullOrEmpty()] [System.Security.SecureString] $Password, [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "If set to true, force the user to change their password.")] [System.Boolean] $EnforceChangePasswordPolicy ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Directory.AccessAsUser.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["UserId"]) { $userId = $PSBoundParameters["UserId"] } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["Password"]) { $Temp = $PSBoundParameters["Password"] $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Temp) $PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["ForceChangePasswordNextLogin"]) { $ForceChangePasswordNextSignIn = $PSBoundParameters["ForceChangePasswordNextLogin"] } if ($null -ne $PSBoundParameters["EnforceChangePasswordPolicy"]) { $ForceChangePasswordNextSignInWithMfa = $PSBoundParameters["EnforceChangePasswordPolicy"] } $PasswordProfile = @{} if ($null -ne $PSBoundParameters["ForceChangePasswordNextLogin"]) { $PasswordProfile["ForceChangePasswordNextSignIn"] = $ForceChangePasswordNextSignIn } if ($null -ne $PSBoundParameters["EnforceChangePasswordPolicy"]) { $PasswordProfile["ForceChangePasswordNextSignInWithMfa"] = $ForceChangePasswordNextSignInWithMfa } if ($null -ne $PSBoundParameters["Password"]) { $PasswordProfile["password"] = $PlainPassword } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Update-MgUser -Headers $customHeaders -UserId $userId -PasswordProfile $PasswordProfile @params $response } } function Set-EntraUserSponsor { [CmdletBinding(DefaultParameterSetName = "SetUserSponsor")] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The unique identifier (User ID or User Principal Name) of the user whose sponsor information you want to set.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Type of sponsor to assign to a User. Can be either 'User' or 'Group'.")] [ValidateSet("User", "Group")] [ValidateNotNullOrEmpty()] [System.String] $Type, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "List of sponsors to assign to the user.")] [ValidateNotNullOrEmpty()] [System.String[]] $SponsorIds ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.ReadWrite.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { # Set up headers $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand $customHeaders['Content-Type'] = 'application/json' $batchEndpoint = "/v1.0/`$batch" # Initialize request collection $requests = @() $rootUri = (Get-EntraEnvironment -Name (Get-EntraContext).Environment).GraphEndpoint if (-not $rootUri) { $rootUri = "https://graph.microsoft.com" Write-Verbose "Using default Graph endpoint: $rootUri" } # Determine target endpoint based on parameter set $targetResource = if ($Type -eq "User") { "users" } else { "groups" } $targetEndpoint = "users/$UserId/sponsors/`$ref" foreach ($sponsorId in $SponsorIds) { $request = @{ id = $sponsorId method = "POST" url = "/$targetEndpoint" body = @{ "@odata.id" = "$rootUri/v1.0/$targetResource/$sponsorId" } headers = @{ "Content-Type" = "application/json" } } $requests += $request } # Execute batch request with all sponsors if ($requests.Count -gt 0) { $batchBody = @{ requests = $requests } $response = Invoke-MgGraphRequest -Method POST -Uri $batchEndpoint -Body ($batchBody | ConvertTo-Json -Depth 4) -Headers $customHeaders | ConvertTo-Json -Depth 10 | ConvertFrom-Json $batchResponse = $response.responses | ForEach-Object { if ($_.status -ne 204) { [PSCustomObject]@{ Id = $_.id Error = $_.body.error.message } } } $batchResponse } else { Write-Error "No sponsors to add." } } } Set-Alias -Name Update-EntraUserSponsor -Value Set-EntraUserSponsor -Description "Set or update the sponsor information for a user." -Scope Global -Force function Set-EntraUserThumbnailPhoto { [CmdletBinding(DefaultParameterSetName = 'File')] param ( [Parameter(ParameterSetName = "Stream", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the stream of the image file to upload.")] [ValidateNotNullOrEmpty()] [System.IO.Stream] $FileStream, [Parameter(ParameterSetName = "ByteArray", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the byte array of the image file to upload.")] [ValidateNotNullOrEmpty()] [System.Byte[]] $ImageByteArray, [Parameter(ParameterSetName = "File", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the path to the image file to upload.")] [ValidateNotNullOrEmpty()] [System.String] $FilePath, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the ID of a user (as a UserPrincipalName or ObjectId) in Microsoft Entra ID.")] [Parameter(ParameterSetName = "Stream")] [Parameter(ParameterSetName = "File")] [Parameter(ParameterSetName = "ByteArray")] [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserId must be a valid email address or GUID." })] [System.String] $UserId ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes User.ReadWrite.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["FileStream"]) { $params["FileStream"] = $PSBoundParameters["FileStream"] } if ($null -ne $PSBoundParameters["OutVariable"]) { $params["OutVariable"] = $PSBoundParameters["OutVariable"] } if ($PSBoundParameters.ContainsKey("Debug")) { $params["Debug"] = $PSBoundParameters["Debug"] } if ($null -ne $PSBoundParameters["PipelineVariable"]) { $params["PipelineVariable"] = $PSBoundParameters["PipelineVariable"] } if ($null -ne $PSBoundParameters["InformationVariable"]) { $params["InformationVariable"] = $PSBoundParameters["InformationVariable"] } if ($null -ne $PSBoundParameters["ImageByteArray"]) { $params["ImageByteArray"] = $PSBoundParameters["ImageByteArray"] } if ($null -ne $PSBoundParameters["OutBuffer"]) { $params["OutBuffer"] = $PSBoundParameters["OutBuffer"] } if ($null -ne $PSBoundParameters["WarningVariable"]) { $params["WarningVariable"] = $PSBoundParameters["WarningVariable"] } if ($PSBoundParameters.ContainsKey("Verbose")) { $params["Verbose"] = $PSBoundParameters["Verbose"] } if ($null -ne $PSBoundParameters["ErrorVariable"]) { $params["ErrorVariable"] = $PSBoundParameters["ErrorVariable"] } if ($null -ne $PSBoundParameters["FilePath"]) { $params["InFile"] = $PSBoundParameters["FilePath"] } if ($null -ne $PSBoundParameters["ErrorAction"]) { $params["ErrorAction"] = $PSBoundParameters["ErrorAction"] } if ($null -ne $PSBoundParameters["UserId"]) { $params["UserId"] = $PSBoundParameters["UserId"] } if ($null -ne $PSBoundParameters["InformationAction"]) { $params["InformationAction"] = $PSBoundParameters["InformationAction"] } if ($null -ne $PSBoundParameters["WarningAction"]) { $params["WarningAction"] = $PSBoundParameters["WarningAction"] } if ($null -ne $PSBoundParameters["ProgressAction"]) { $params["ProgressAction"] = $PSBoundParameters["ProgressAction"] } Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Set-MgUserPhotoContent @params -Headers $customHeaders $response | ForEach-Object { if ($null -ne $_) { Add-Member -InputObject $_ -MemberType AliasProperty -Name ObjectId -Value Id } } $response } } function Update-EntraSignedInUserPassword { [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the new password for the signed-in user.")] [ValidateNotNullOrEmpty()] [System.Security.SecureString] $NewPassword, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Specifies the current password for the signed-in user.")] [ValidateNotNullOrEmpty()] [System.Security.SecureString] $CurrentPassword ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Directory.AccessAsUser.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { $params = @{} $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand if ($null -ne $PSBoundParameters["NewPassword"]) { $params["NewPassword"] = $PSBoundParameters["NewPassword"] } if ($null -ne $PSBoundParameters["CurrentPassword"]) { $params["CurrentPassword"] = $PSBoundParameters["CurrentPassword"] } $currsecur = [System.Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($params.CurrentPassword) $curr = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($currsecur) $newsecur = [System.Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($params.NewPassword) $new = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($newsecur) $params["Url"] = "/v1.0/me/changePassword" $body = @{ currentPassword = $curr newPassword = $new } $body = $body | ConvertTo-Json Write-Debug("============================ TRANSFORMATIONS ============================") $params.Keys | ForEach-Object { "$_ : $($params[$_])" } | Write-Debug Write-Debug("=========================================================================`n") $response = Invoke-GraphRequest -Headers $customHeaders -Uri $params.Url -Method POST -Body $body $response } } function Update-EntraUserFromFederated { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams", "", Scope = "Function", Target = "*")] [CmdletBinding(DefaultParameterSetName = 'CloudOnlyPasswordScenarios')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "UserPrincipalName of the user to update.")] [Alias('ObjectId', 'UPN', 'Identity', 'UserId')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') { return $true } throw "UserPrincipalName must be a valid email address or GUID." })] [System.String] $UserPrincipalName, [Parameter(ParameterSetName = "HybridPasswordScenarios", Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "New password for the user.")] [SecureString] $NewPassword, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "TenantId of the user to update.")] [Obsolete("This parameter provides compatibility with Azure AD and MSOnline for partner scenarios. TenantID is the signed-in user's tenant ID. It should not be used for any other purpose.")] [guid] $TenantId ) begin { # Ensure connection to Microsoft Entra if (-not (Get-EntraContext)) { $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes UserAuthenticationMethod.ReadWrite.All' to authenticate." Write-Error -Message $errorMessage -ErrorAction Stop return } } PROCESS { # Define essential variables $authenticationMethodId = "28c10230-6103-485e-b985-444c60001490" $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand $params = @{ "UserId" = $UserPrincipalName } $params["Url"] = "/v1.0/users/$($UserPrincipalName)/authentication/methods/$authenticationMethodId/resetPassword" # Handle password conversion securely $passwordRedacted = $false $newPasswordValue = $null if ($PSBoundParameters.ContainsKey("NewPassword") -and $NewPassword) { $newSecurePassword = [System.Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($NewPassword) try { $newPasswordValue = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($newSecurePassword) $params["NewPassword"] = $newPasswordValue } finally { [System.Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($newSecurePassword) # Securely free memory } # Mark for redaction $passwordRedacted = $true } # Create JSON body $body = if ($passwordRedacted) { if ($DebugPreference -ne 'SilentlyContinue') { # Redact password in debug mode @{ newPassword = "[REDACTED]" } | ConvertTo-Json } else { @{ newPassword = $newPasswordValue } | ConvertTo-Json } } else { @{} | ConvertTo-Json } # Debugging output with redaction Write-Debug "========================= TRANSFORMATIONS =========================" foreach ($key in $params.Keys) { $value = if ($passwordRedacted -and $key -eq "NewPassword") { "[REDACTED]" } else { $params[$key] } Write-Debug "$key : $value" } Write-Debug "JSON Body: $body" Write-Debug "==================================================================`n" # Invoke request try { $response = Invoke-GraphRequest -Headers $customHeaders -Uri $params.Url -Method POST -Body $body return $response } catch { Write-Error "Failed to update user $($UserPrincipalName): $_" return $null } } } Export-ModuleMember -Function @('Get-EntraDeletedUser', 'Get-EntraInactiveSignInUser', 'Get-EntraUnsupportedCommand', 'Get-EntraUser', 'Get-EntraUserAdministrativeUnit', 'Get-EntraUserAppRoleAssignment', 'Get-EntraUserCreatedObject', 'Get-EntraUserDirectReport', 'Get-EntraUserExtension', 'Get-EntraUserGroup', 'Get-EntraUserInactiveSignIn', 'Get-EntraUserLicenseDetail', 'Get-EntraUserManager', 'Get-EntraUserMembership', 'Get-EntraUserOAuth2PermissionGrant', 'Get-EntraUserOwnedDevice', 'Get-EntraUserOwnedObject', 'Get-EntraUserRegisteredDevice', 'Get-EntraUserRole', 'Get-EntraUserSponsor', 'Get-EntraUserThumbnailPhoto', 'New-EntraCustomHeaders', 'New-EntraUser', 'New-EntraUserAppRoleAssignment', 'Remove-EntraUser', 'Remove-EntraUserAppRoleAssignment', 'Remove-EntraUserExtension', 'Remove-EntraUserManager', 'Remove-EntraUserSponsor', 'Set-EntraUser', 'Set-EntraUserExtension', 'Set-EntraUserLicense', 'Set-EntraUserManager', 'Set-EntraUserPassword', 'Set-EntraUserSponsor', 'Set-EntraUserThumbnailPhoto', 'Update-EntraSignedInUserPassword', 'Update-EntraUserFromFederated') # Typedefs # ------------------------------------------------------------------------------ # Type definitions required for commands inputs # ------------------------------------------------------------------------------ $def = @" namespace Microsoft.Open.AzureAD.Graph.PowerShell.Custom { using System.Linq; public enum KeyType{ Symmetric = 0, AsymmetricX509Cert = 1, } public enum KeyUsage{ Sign = 0, Verify = 1, Decrypt = 2, Encrypt = 3, } } namespace Microsoft.Open.AzureAD.Model { using System.Linq; public class AlternativeSecurityId { public System.String IdentityProvider; public System.Byte[] Key; public System.Nullable<System.Int32> Type; } public class AppRole { public System.Collections.Generic.List<System.String> AllowedMemberTypes; public System.String Description; public System.String DisplayName; public System.String Id; public System.Nullable<System.Boolean> IsEnabled; public System.String Origin; public System.String Value; } public class AssignedLicense { public System.Collections.Generic.List<System.String> DisabledPlans; public System.String SkuId; } public class AssignedLicenses { public System.Collections.Generic.List<Microsoft.Open.AzureAD.Model.AssignedLicense> AddLicenses; public System.Collections.Generic.List<System.String> RemoveLicenses; } public class CertificateAuthorityInformation { public enum AuthorityTypeEnum{ RootAuthority = 0, IntermediateAuthority = 1, } public System.Nullable<AuthorityTypeEnum> AuthorityType; public System.String CrlDistributionPoint; public System.String DeltaCrlDistributionPoint; public System.Byte[] TrustedCertificate; public System.String TrustedIssuer; public System.String TrustedIssuerSki; } public class CrossCloudVerificationCodeBody { public System.String CrossCloudVerificationCode; public CrossCloudVerificationCodeBody() { } public CrossCloudVerificationCodeBody(System.String value) { CrossCloudVerificationCode = value; } } public class GroupIdsForMembershipCheck { public System.Collections.Generic.List<System.String> GroupIds; public GroupIdsForMembershipCheck() { } public GroupIdsForMembershipCheck(System.Collections.Generic.List<System.String> value) { GroupIds = value; } } public class KeyCredential { public System.Byte[] CustomKeyIdentifier; public System.Nullable<System.DateTime> EndDate; public System.String KeyId; public System.Nullable<System.DateTime> StartDate; public System.String Type; public System.String Usage; public System.Byte[] Value; } public class PasswordCredential { public System.Byte[] CustomKeyIdentifier; public System.Nullable<System.DateTime> EndDate; public System.String KeyId; public System.Nullable<System.DateTime> StartDate; public System.String Value; } public class PasswordProfile { public System.String Password; public System.Nullable<System.Boolean> ForceChangePasswordNextLogin; public System.Nullable<System.Boolean> EnforceChangePasswordPolicy; } public class PrivacyProfile { public System.String ContactEmail; public System.String StatementUrl; } public class SignInName { public System.String Type; public System.String Value; } } namespace Microsoft.Open.MSGraph.Model { using System.Linq; public class AddIn { public System.String Id; public System.String Type; public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.KeyValue> Properties; } public class ApiApplication { public System.Nullable<System.Boolean> AcceptMappedClaims; public System.Collections.Generic.List<System.String> KnownClientApplications; public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.PreAuthorizedApplication> PreAuthorizedApplications; public System.Nullable<System.Int32> RequestedAccessTokenVersion; public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.PermissionScope> Oauth2PermissionScopes; } public class AppRole { public System.Collections.Generic.List<System.String> AllowedMemberTypes; public System.String Description; public System.String DisplayName; public System.String Id; public System.Nullable<System.Boolean> IsEnabled; public System.String Origin; public System.String Value; } public class ConditionalAccessApplicationCondition { public System.Collections.Generic.List<System.String> IncludeApplications; public System.Collections.Generic.List<System.String> ExcludeApplications; public System.Collections.Generic.List<System.String> IncludeUserActions; public System.Collections.Generic.List<System.String> IncludeProtectionLevels; } public class ConditionalAccessApplicationEnforcedRestrictions { public System.Nullable<System.Boolean> IsEnabled; public ConditionalAccessApplicationEnforcedRestrictions() { } public ConditionalAccessApplicationEnforcedRestrictions(System.Nullable<System.Boolean> value) { IsEnabled = value; } } public class ConditionalAccessCloudAppSecurity { public enum CloudAppSecurityTypeEnum{ McasConfigured = 0, MonitorOnly = 1, BlockDownloads = 2, } public System.Nullable<CloudAppSecurityTypeEnum> CloudAppSecurityType; public System.Nullable<System.Boolean> IsEnabled; } public class ConditionalAccessConditionSet { public Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition Applications; public Microsoft.Open.MSGraph.Model.ConditionalAccessUserCondition Users; public Microsoft.Open.MSGraph.Model.ConditionalAccessPlatformCondition Platforms; public Microsoft.Open.MSGraph.Model.ConditionalAccessLocationCondition Locations; public enum ConditionalAccessRiskLevel{ Low = 0, Medium = 1, High = 2, Hidden = 3, None = 4, UnknownFutureValue = 5, } public System.Collections.Generic.List<ConditionalAccessRiskLevel> SignInRiskLevels; public enum ConditionalAccessClientApp{ All = 0, Browser = 1, MobileAppsAndDesktopClients = 2, ExchangeActiveSync = 3, EasSupported = 4, Other = 5, } public System.Collections.Generic.List<ConditionalAccessClientApp> ClientAppTypes; } public class ConditionalAccessGrantControls { public System.String _Operator; public enum ConditionalAccessGrantControl{ Block = 0, Mfa = 1, CompliantDevice = 2, DomainJoinedDevice = 3, ApprovedApplication = 4, CompliantApplication = 5, PasswordChange = 6, } public System.Collections.Generic.List<ConditionalAccessGrantControl> BuiltInControls; public System.Collections.Generic.List<System.String> CustomAuthenticationFactors; public System.Collections.Generic.List<System.String> TermsOfUse; } public class ConditionalAccessLocationCondition { public System.Collections.Generic.List<System.String> IncludeLocations; public System.Collections.Generic.List<System.String> ExcludeLocations; } public class ConditionalAccessPersistentBrowser { public enum ModeEnum{ Always = 0, Never = 1, } public System.Nullable<ModeEnum> Mode; public System.Nullable<System.Boolean> IsEnabled; } public class ConditionalAccessPlatformCondition { public enum ConditionalAccessDevicePlatforms{ Android = 0, IOS = 1, Windows = 2, WindowsPhone = 3, MacOS = 4, All = 5, } public System.Collections.Generic.List<ConditionalAccessDevicePlatforms> IncludePlatforms; public System.Collections.Generic.List<ConditionalAccessDevicePlatforms> ExcludePlatforms; } public class ConditionalAccessSessionControls { public Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationEnforcedRestrictions ApplicationEnforcedRestrictions; public Microsoft.Open.MSGraph.Model.ConditionalAccessCloudAppSecurity CloudAppSecurity; public Microsoft.Open.MSGraph.Model.ConditionalAccessSignInFrequency SignInFrequency; public Microsoft.Open.MSGraph.Model.ConditionalAccessPersistentBrowser PersistentBrowser; } public class ConditionalAccessSignInFrequency { public enum TypeEnum{ Days = 0, Hours = 1, } public System.Nullable<TypeEnum> Type; public System.Nullable<System.Int32> Value; public System.Nullable<System.Boolean> IsEnabled; } public class ConditionalAccessUserCondition { public System.Collections.Generic.List<System.String> IncludeUsers; public System.Collections.Generic.List<System.String> ExcludeUsers; public System.Collections.Generic.List<System.String> IncludeGroups; public System.Collections.Generic.List<System.String> ExcludeGroups; public System.Collections.Generic.List<System.String> IncludeRoles; public System.Collections.Generic.List<System.String> ExcludeRoles; } public enum CountriesAndRegion{ AD = 0, AE = 1, AF = 2, AG = 3, AI = 4, AL = 5, AM = 6, AN = 7, AO = 8, AQ = 9, AR = 10, AS = 11, AT = 12, AU = 13, AW = 14, AX = 15, AZ = 16, BA = 17, BB = 18, BD = 19, BE = 20, BF = 21, BG = 22, BH = 23, BI = 24, BJ = 25, BL = 26, BM = 27, BN = 28, BO = 29, BQ = 30, BR = 31, BS = 32, BT = 33, BV = 34, BW = 35, BY = 36, BZ = 37, CA = 38, CC = 39, CD = 40, CF = 41, CG = 42, CH = 43, CI = 44, CK = 45, CL = 46, CM = 47, CN = 48, CO = 49, CR = 50, CU = 51, CV = 52, CW = 53, CX = 54, CY = 55, CZ = 56, DE = 57, DJ = 58, DK = 59, DM = 60, DO = 61, DZ = 62, EC = 63, EE = 64, EG = 65, EH = 66, ER = 67, ES = 68, ET = 69, FI = 70, FJ = 71, FK = 72, FM = 73, FO = 74, FR = 75, GA = 76, GB = 77, GD = 78, GE = 79, GF = 80, GG = 81, GH = 82, GI = 83, GL = 84, GM = 85, GN = 86, GP = 87, GQ = 88, GR = 89, GS = 90, GT = 91, GU = 92, GW = 93, GY = 94, HK = 95, HM = 96, HN = 97, HR = 98, HT = 99, HU = 100, ID = 101, IE = 102, IL = 103, IM = 104, IN = 105, IO = 106, IQ = 107, IR = 108, IS = 109, IT = 110, JE = 111, JM = 112, JO = 113, JP = 114, KE = 115, KG = 116, KH = 117, KI = 118, KM = 119, KN = 120, KP = 121, KR = 122, KW = 123, KY = 124, KZ = 125, LA = 126, LB = 127, LC = 128, LI = 129, LK = 130, LR = 131, LS = 132, LT = 133, LU = 134, LV = 135, LY = 136, MA = 137, MC = 138, MD = 139, ME = 140, MF = 141, MG = 142, MH = 143, MK = 144, ML = 145, MM = 146, MN = 147, MO = 148, MP = 149, MQ = 150, MR = 151, MS = 152, MT = 153, MU = 154, MV = 155, MW = 156, MX = 157, MY = 158, MZ = 159, NA = 160, NC = 161, NE = 162, NF = 163, NG = 164, NI = 165, NL = 166, NO = 167, NP = 168, NR = 169, NU = 170, NZ = 171, OM = 172, PA = 173, PE = 174, PF = 175, PG = 176, PH = 177, PK = 178, PL = 179, PM = 180, PN = 181, PR = 182, PS = 183, PT = 184, PW = 185, PY = 186, QA = 187, RE = 188, RO = 189, RS = 190, RU = 191, RW = 192, SA = 193, SB = 194, SC = 195, SD = 196, SE = 197, SG = 198, SH = 199, SI = 200, SJ = 201, SK = 202, SL = 203, SM = 204, SN = 205, SO = 206, SR = 207, SS = 208, ST = 209, SV = 210, SX = 211, SY = 212, SZ = 213, TC = 214, TD = 215, TF = 216, TG = 217, TH = 218, TJ = 219, TK = 220, TL = 221, TM = 222, TN = 223, TO = 224, TR = 225, TT = 226, TV = 227, TW = 228, TZ = 229, UA = 230, UG = 231, UM = 232, US = 233, UY = 234, UZ = 235, VA = 236, VC = 237, VE = 238, VG = 239, VI = 240, VN = 241, VU = 242, WF = 243, WS = 244, YE = 245, YT = 246, ZA = 247, ZM = 248, ZW = 249, } public class DefaultUserRolePermissions { public System.Nullable<System.Boolean> AllowedToCreateApps; public System.Nullable<System.Boolean> AllowedToCreateSecurityGroups; public System.Nullable<System.Boolean> AllowedToReadOtherUsers; public System.Collections.Generic.List<System.String> PermissionGrantPoliciesAssigned; } public class DelegatedPermissionClassification { public enum ClassificationEnum{ Low = 0, Medium = 1, High = 2, } public System.Nullable<ClassificationEnum> Classification; public System.String Id; public System.String PermissionId; public System.String PermissionName; } public class EmailAddress { public System.String Name; public System.String Address; } public class ImplicitGrantSettings { public System.Nullable<System.Boolean> EnableIdTokenIssuance; public System.Nullable<System.Boolean> EnableAccessTokenIssuance; } public class InformationalUrl { public System.String TermsOfServiceUrl; public System.String MarketingUrl; public System.String PrivacyStatementUrl; public System.String SupportUrl; public System.String LogoUrl; } public class InvitedUserMessageInfo { public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.Recipient> CcRecipients; public System.String CustomizedMessageBody; public System.String MessageLanguage; } public class IpRange { public System.String CidrAddress; public IpRange() { } public IpRange(System.String value) { CidrAddress = value; } } public class KeyCredential { public System.Byte[] CustomKeyIdentifier; public System.String DisplayName; public System.Nullable<System.DateTime> EndDateTime; public System.String KeyId; public System.Nullable<System.DateTime> StartDateTime; public System.String Type; public System.String Usage; public System.Byte[] Key; } public class KeyValue { public System.String Key; public System.String Value; } public class MsDirectoryObject { public System.String Id; public System.String OdataType; } public class MsRoleMemberInfo { public System.String Id; } public class OptionalClaim { public System.String Name; public System.String Source; public System.Nullable<System.Boolean> Essential; public System.Collections.Generic.List<System.String> AdditionalProperties; } public class OptionalClaims { public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.OptionalClaim> IdToken; public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.OptionalClaim> AccessToken; public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.OptionalClaim> Saml2Token; } public class ParentalControlSettings { public enum LegalAgeGroupRuleEnum{ Allow = 0, RequireConsentForPrivacyServices = 1, RequireConsentForMinors = 2, RequireConsentForKids = 3, BlockMinors = 4, } public System.Nullable<LegalAgeGroupRuleEnum> LegalAgeGroupRule; public System.Collections.Generic.List<System.String> CountriesBlockedForMinors; } public class PasswordCredential { public System.Byte[] CustomKeyIdentifier; public System.Nullable<System.DateTime> EndDateTime; public System.String DisplayName; public System.String KeyId; public System.Nullable<System.DateTime> StartDateTime; public System.String SecretText; public System.String Hint; } public class PermissionScope { public System.String AdminConsentDescription; public System.String AdminConsentDisplayName; public System.String Id; public System.Nullable<System.Boolean> IsEnabled; public System.String Type; public System.String UserConsentDescription; public System.String UserConsentDisplayName; public System.String Value; } public class PreAuthorizedApplication { public System.String AppId; public System.Collections.Generic.List<System.String> DelegatedPermissionIds; } public class PublicClientApplication { public System.Collections.Generic.List<System.String> RedirectUris; public PublicClientApplication() { } public PublicClientApplication(System.Collections.Generic.List<System.String> value) { RedirectUris = value; } } public class Recipient { public Microsoft.Open.MSGraph.Model.EmailAddress EmailAddress; public Recipient() { } public Recipient(Microsoft.Open.MSGraph.Model.EmailAddress value) { EmailAddress = value; } } public class RequiredResourceAccess { public System.String ResourceAppId; public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.ResourceAccess> ResourceAccess; } public class ResourceAccess { public System.String Id; public System.String Type; } public class RolePermission { public System.Collections.Generic.List<System.String> AllowedResourceActions; public System.String Condition; } public class SetVerifiedPublisherRequest { public System.String VerifiedPublisherId; public SetVerifiedPublisherRequest() { } public SetVerifiedPublisherRequest(System.String value) { VerifiedPublisherId = value; } } public class User { public System.String Id; public System.String OdataType; } public class WebApplication { public System.String HomePageUrl; public System.String LogoutUrl; public System.Collections.Generic.List<System.String> RedirectUris; public Microsoft.Open.MSGraph.Model.ImplicitGrantSettings ImplicitGrantSettings; } } "@ try { Add-Type -TypeDefinition $def -ErrorAction SilentlyContinue } catch { # No error message will be displayed, and type will be added if it doesn't exist } # ------------------------------------------------------------------------------ # End of Type definitions required for commands inputs # ------------------------------------------------------------------------------ # SIG # Begin signature block # MIIoLQYJKoZIhvcNAQcCoIIoHjCCKBoCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBU59fpk7bXvrey # XKK5trmdxrnyaMBsWI95DpFPcJtLpqCCDXYwggX0MIID3KADAgECAhMzAAAEBGx0 # Bv9XKydyAAAAAAQEMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjQwOTEyMjAxMTE0WhcNMjUwOTExMjAxMTE0WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQC0KDfaY50MDqsEGdlIzDHBd6CqIMRQWW9Af1LHDDTuFjfDsvna0nEuDSYJmNyz # NB10jpbg0lhvkT1AzfX2TLITSXwS8D+mBzGCWMM/wTpciWBV/pbjSazbzoKvRrNo # DV/u9omOM2Eawyo5JJJdNkM2d8qzkQ0bRuRd4HarmGunSouyb9NY7egWN5E5lUc3 # a2AROzAdHdYpObpCOdeAY2P5XqtJkk79aROpzw16wCjdSn8qMzCBzR7rvH2WVkvF # HLIxZQET1yhPb6lRmpgBQNnzidHV2Ocxjc8wNiIDzgbDkmlx54QPfw7RwQi8p1fy # 4byhBrTjv568x8NGv3gwb0RbAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU8huhNbETDU+ZWllL4DNMPCijEU4w # RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW # MBQGA1UEBRMNMjMwMDEyKzUwMjkyMzAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci # tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG # CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0 # MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAIjmD9IpQVvfB1QehvpC # Ge7QeTQkKQ7j3bmDMjwSqFL4ri6ae9IFTdpywn5smmtSIyKYDn3/nHtaEn0X1NBj # L5oP0BjAy1sqxD+uy35B+V8wv5GrxhMDJP8l2QjLtH/UglSTIhLqyt8bUAqVfyfp # h4COMRvwwjTvChtCnUXXACuCXYHWalOoc0OU2oGN+mPJIJJxaNQc1sjBsMbGIWv3 # cmgSHkCEmrMv7yaidpePt6V+yPMik+eXw3IfZ5eNOiNgL1rZzgSJfTnvUqiaEQ0X # dG1HbkDv9fv6CTq6m4Ty3IzLiwGSXYxRIXTxT4TYs5VxHy2uFjFXWVSL0J2ARTYL # E4Oyl1wXDF1PX4bxg1yDMfKPHcE1Ijic5lx1KdK1SkaEJdto4hd++05J9Bf9TAmi # u6EK6C9Oe5vRadroJCK26uCUI4zIjL/qG7mswW+qT0CW0gnR9JHkXCWNbo8ccMk1 # sJatmRoSAifbgzaYbUz8+lv+IXy5GFuAmLnNbGjacB3IMGpa+lbFgih57/fIhamq # 5VhxgaEmn/UjWyr+cPiAFWuTVIpfsOjbEAww75wURNM1Imp9NJKye1O24EspEHmb # DmqCUcq7NqkOKIG4PVm3hDDED/WQpzJDkvu4FrIbvyTGVU01vKsg4UfcdiZ0fQ+/ # V0hf8yrtq9CkB8iIuk5bBxuPMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq # hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 # IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG # EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG # A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg # Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC # CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03 # a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr # rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg # OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy # 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9 # sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh # dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k # A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB # w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn # Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90 # lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w # ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o # ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD # VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa # BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny # bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG # AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t # L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV # HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG # AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl # AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb # C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l # hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6 # I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0 # wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560 # STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam # ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa # J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah # XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA # 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt # Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr # /Xmfwb1tbWrJUnMTDXpQzTGCGg0wghoJAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp # Z25pbmcgUENBIDIwMTECEzMAAAQEbHQG/1crJ3IAAAAABAQwDQYJYIZIAWUDBAIB # BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO # MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIFJtnn4pfJeanmi4CkMJM6pn # btrmWFwe+i+86QIPM/vJMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A # cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB # BQAEggEAFqUlitxpeFEoPoLfyC0R0vaUPVZdlcrqyX73jvDAug61RgclBKGN91Fv # YjoLiE5KD5NVq5mO6tYt7nzXmf6jXGHd9hsqXrsN660w7xd0wY6aIZCHW6LVDzAy # ZPu4gYY8yWn1CZ/4HuB518XZne131uyg9acXwZB3GrLc+Ju6AuZPJFzwiIQX70g/ # dCL4dpF+/GGKVeHRjgzEFmBPzXGEvAsTTVlEeokNw+VrIgtcDEeWEWmObve48SxA # +7Uh4hmlMLCHk+SMtqyjRfkdunogcToqmchpT+uUnh06ecgTOoRmgFADjOzUVwTu # lNoGr1piTsLmzZ3bQeELygr4b98y3KGCF5cwgheTBgorBgEEAYI3AwMBMYIXgzCC # F38GCSqGSIb3DQEHAqCCF3AwghdsAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsq # hkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl # AwQCAQUABCAK4oW7x7jFC/hamdff/lXgcv7q54zvnocSo0dlpy5fXwIGaEtAoVAS # GBMyMDI1MDYyNzE1NTAxNC42MzJaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l # cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046RjAwMi0w # NUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wg # ghHtMIIHIDCCBQigAwIBAgITMwAAAgU8dWyCRIfN/gABAAACBTANBgkqhkiG9w0B # AQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD # VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yNTAxMzAxOTQy # NDlaFw0yNjA0MjIxOTQyNDlaMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz # aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv # cnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25z # MScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046RjAwMi0wNUUwLUQ5NDcxJTAjBgNV # BAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEB # AQUAA4ICDwAwggIKAoICAQCSkvLfd7gF1r2wGdy85CFYXHUC8ywEyD4LRLv0WYEX # eeZ0u5YuK7p2cXVzQmZPOHTN8TWqG2SPlUb+7PldzFDDAlR3vU8piOjmhu9rHW43 # M2dbor9jl9gluhzwUd2SciVGa7f9t67tM3KFKRSMXFtHKF3KwBB7aVo+b1qy5p9D # Wlo2N5FGrBqHMEVlNyzreHYoDLL+m8fSsqMu/iYUqxzK5F4S7IY5NemAB8B+A3Qg # wVIi64KJIfeKZUeiWKCTf4odUgP3AQilxh48P6z7AT4IA0dMEtKhYLFs4W/KNDMs # Yr7KpQPKVCcC5E8uDHdKewubyzenkTxy4ff1N3g8yho5Pi9BfjR0VytrkmpDfep8 # JPwcb4BNOIXOo1pfdHZ8EvnR7JFZFQiqpMZFlO5CAuTYH8ujc5PUHlaMAJ8NEa9T # FJTOSBrB7PRgeh/6NJ2xu9yxPh/kVN9BGss93MC6UjpoxeM4x70bwbwiK8SNHIO8 # D8cql7VSevUYbjN4NogFFwhBClhodE/zeGPq6y6ixD4z65IHY3zwFQbBVX/w+L/V # HNn/BMGs2PGHnlRjO/Kk8NIpN4shkFQqA1fM08frrDSNEY9VKDtpsUpAF51Y1oQ6 # tJhWM1d3neCXh6b/6N+XeHORCwnY83K+pFMMhg8isXQb6KRl65kg8XYBd4JwkbKo # VQIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFHR6Wrs27b6+yJ3bEZ9o5NdL1bLwMB8G # A1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCG # Tmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy # MFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4w # XAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy # dHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwG # A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD # AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQAOuxk47b1i75V81Tx6xo10xNIr4zZxYVfk # F5TFq2kndPHgzVyLnssw/HKkEZRCgZVpkKEJ6Y4jvG5tugMi+Wjt7hUMSipk+RpB # 5gFQvh1xmAEL2flegzTWEsnj0wrESplI5Z3vgf2eGXAr/RcqGjSpouHbD2HY9Y3F # 0Ol6FRDCV/HEGKRHzn2M5rQpFGSjacT4DkqVYmem/ArOfSvVojnKEIW914UxGtuh # JSr9jOo5RqTX7GIqbtvN7zhWld+i3XxdhdNcflQz9YhoFqQexBenoIRgAPAtwH68 # xczr9LMC3l9ALEpnsvO0RiKPXF4l22/OfcFffaphnl/TDwkiJfxOyAMfUF3xI9+3 # izT1WX2CFs2RaOAq3dcohyJw+xRG0E8wkCHqkV57BbUBEzLX8L9lGJ1DoxYNpoDX # 7iQzJ9Qdkypi5fv773E3Ch8A+toxeFp6FifQZyCc8IcIBlHyak6MbT6YTVQNgQ/h # 8FF+S5OqP7CECFvIH2Kt2P0GlOu9C0BfashnTjodmtZFZsptUvirk/2HOLLjBiMj # DwJsQAFAzJuz4ZtTyorrvER10Gl/mbmViHqhvNACfTzPiLfjDgyvp9s7/bHu/Cal # KmeiJULGjh/lwAj5319pggsGJqbhJ4FbFc+oU5zffbm/rKjVZ8kxND3im10Qp41n # 2t/qpyP6ETCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZI # hvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw # DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x # MjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAy # MDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMC # VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV # BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp # bWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC # AQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25Phdg # M/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPF # dvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6 # GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBp # Dco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50Zu # yjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3E # XzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0 # lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1q # GFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ # +QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PA # PBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkw # EgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxG # NSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARV # MFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj # cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAK # BggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC # AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX # zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v # cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI # KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG # 9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0x # M7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmC # VgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449 # xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wM # nosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDS # PeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2d # Y3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxn # GSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+Crvs # QWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokL # jzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL # 6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNQ # MIICOAIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp # bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw # b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEn # MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOkYwMDItMDVFMC1EOTQ3MSUwIwYDVQQD # ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQDV # sH9p1tJn+krwCMvqOhVvXrbetKCBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w # IFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA7AjbjDAiGA8yMDI1MDYyNzA4NTc0 # OFoYDzIwMjUwNjI4MDg1NzQ4WjB3MD0GCisGAQQBhFkKBAExLzAtMAoCBQDsCNuM # AgEAMAoCAQACAiScAgH/MAcCAQACAhNFMAoCBQDsCi0MAgEAMDYGCisGAQQBhFkK # BAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJ # KoZIhvcNAQELBQADggEBADDZtT+W5ZA6VOgnZKX0rqL4p5BM8hZdVbw9Jb8MIyna # A57FFYopCBJFiv+Y34Og5YU1bNAq+uJy8fCguMpVp47VH1jFO7gGvuimnlOE0atR # PEAyKge2uw6BnTrLAsBRedlBTn1TP0bMlsPzZEtF9z4xLxKiyqjqiwBmBrUpJDBc # 4BV7bl0/WpPRkscOWZwg91cRYc+ZLVWqqRCGX0S5DUxDuwUfLrPGiEw2nDrvTbwa # PsMy/R9MsJa6OkyJbks65D67OvfkerQRP+luw7sEaBnkzzh4Cb1+rIRJkiVBcgTo # CPV1S173dtsxnOue+ZQk93ioMJVga14Tn7ydlrcdq8MxggQNMIIECQIBATCBkzB8 # MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk # bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1N # aWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAgU8dWyCRIfN/gABAAAC # BTANBglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEE # MC8GCSqGSIb3DQEJBDEiBCDTY6k9TIOBAu22jPZC3Q80mr5aBmLt0IgarWwFiqjF # 5zCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EIIANAz3ceY0umhdWLR2sJpq0 # OPqtJDTAYRmjHVkwEW9IMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT # Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m # dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB # IDIwMTACEzMAAAIFPHVsgkSHzf4AAQAAAgUwIgQgUnB8h1tga20X12Cr+u9PnBQW # 6/XXiDmVU3KxB6iJCkYwDQYJKoZIhvcNAQELBQAEggIAHhdVDd/+LLmVr3hBajjM # lCBtaDqg1eaDQ8sdG5gpsUTtsITgZt4RUPH8jsIBGqJqbh+4Cc0kyfMgWAsS8eSb # cY9Xym2J7TLCecIlE3Wi0LAdcZCOyTopfHWyjGtrxQi7836zBhdeRNHO0fs4E50Y # hBp0tyRDvFbzPEgBce6Oe61dySjUGeTisSzi0s31785PRY87mnNyBEiFSeC6XOMl # 0zjuiLE/QnZBDFxauekBiBCZQMrEX2o/8PrC0nyiw2/WjZcB8c4iMaNKlgKAofXu # DXncPY35Hch89P8XIlkC6FfxRxJ222hdTHXvFaNwozaSD7c9b2EvSLTbN1TNkESS # C2/NhMHldMrvbl+Ono7gimSEMiDsae2QSYp+r1lGIBvAfo2SD3fISZd1t9pO3xh2 # aR3fW77PADoa1B2H0BZZkB0kGWhjmQKeNU5h0pEn0UIeg1BGH5Zt+pvYMLamEI3A # Ft4ELNokrwbcQ8gMAkykT1/8jsFjjeTW+cL0GVk3EKLEJtACV743awhJYnrNY0IE # BPba+vtKE5tPjBEOKFglHBiFoVD4CRqMZx0DDUCf03kiSkpHqXndb+rnNTXgPgoD # Nf4BnG0nlx7PyPb3yFvcvjQYeMLcz4gtFbaVkmCk45uU6BMBntRcNCr9ifg3jQxk # Iqiq6NEYeoJ9lsgts8ifAHU= # SIG # End signature block |