Just in time privilege's access to Azure DevOps

Published Jan 18 2022 11:39 AM 2,847 Views
Microsoft

To perform certain actions on Azure DevOps including, process template changes, extension import, build modification etc. requires user to have privilege's scopes at either organization or project level. In large enterprises where Azure DevOps organizations are centrally managed or managed via service accounts, enabling permanent privilege access for group of members posses lot of security risk. In scenario's where organizations are created using service account, require user to login via same to perform privilege actions. This posses a security risk of sharing credentials with multiple users and traceability of action performed.

 

Since there is no out of box solution available to enable just in time access with privilege role alike "Azure PIM", there is a custom approach can be used to enable just in time experience and control.

 

Technology involved:

  • PowerShell
  • Azure DevOps Api's
  • Azure SQL server
  • Azure DevOps pipeline

Approach:

  1. Write a script which contains steps to add user to Azure DevOps organization/project based on input
  2. Create a release pipeline(pipeline1) with pre-deployment gate enabled
  3. Store execution output in database
  4. Create another script which will be used to fetch data from database and remove privilege access enabled by pipeline1.
  5. Create another Azure DevOps pipeline(pipeline2) which will run every 10 min and execute script to remove user.

 

Steps:

1. Login to Azure DevOps using service account having owner access across Azure DevOps organization managed by team.

2. Create a personal access token with below scopes across "All accessible organization"

permissions: vso.graph_manage vso.project.

3. Create addUser.ps1 as below:

This script will add user to respective organization/project with required privilege role and enter the data within Azure Sql server.

 

 

 

Param
(

    [Parameter(Mandatory=$true,HelpMessage = "Org name for which access is requeseted")]
    [string][ValidateNotNullOrEmpty()] $OrgName,

    [Parameter(Mandatory=$true,HelpMessage = "Operation for which request is raised")]
    [string][ValidateNotNullOrEmpty()] $RequestType,

    [Parameter(Mandatory=$true,HelpMessage = "email address for which access should be provded")]
    $UserEmailAddress,

    [Parameter(Mandatory=$true,HelpMessage = "Application Insights details")]
    [string][ValidateNotNullOrEmpty()] $LoggingTelemetryID,

    [Parameter(Mandatory=$true)]
    [string][ValidateNotNullOrEmpty()] $PAT,

    [Parameter(Mandatory=$true)]
    [string][ValidateNotNullOrEmpty()] $SQLPassword,

    [Parameter(Mandatory=$true)]
    [string][ValidateNotNullOrEmpty()] $SQLUserID,

    [Parameter(Mandatory=$true)]
    [string][ValidateNotNullOrEmpty()] $SQLDataBase,

    [Parameter(Mandatory=$true)]
    [string][ValidateNotNullOrEmpty()] $SQLServer,

    [Parameter(Mandatory=$true)]
    [string][ValidateNotNullOrEmpty()] $UserDescriptorOrganization,

    [Parameter(Mandatory=$false,HelpMessage = "Project name for which access is requeseted")]
    [string] $ProjectName

)

#####Creating session id####
try
{
    $sessionId = [guid]::NewGuid().GUID
}
catch
{
    Write-Error "Failed to create session id"
    Write-Output $_.Exception.Message
}

###Initializing telemetry client###
try
{
    $AppInsightsdllPath = "$PSScriptRoot\Microsoft.ApplicationInsights.dll"
    [Reflection.Assembly]::LoadFile($AppInsightsdllPath)   
    $TelClient = New-Object "Microsoft.ApplicationInsights.TelemetryClient"
    $TelClient.InstrumentationKey = $LoggingTelemetryID
    $credentials = "Basic " + [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$PAT"))
    $SQLRetryCount = 0 
}
catch
{
    Write-Error "Failed to initialize ApplicationInsights"
    Write-Output $_.Exception.Message
}

####Function to get user descriptor which will be used in adding function####
function Get_User_Descriptor
{
    try
    {
        $ContinuationToken=$null
        do
        {
            ## Set communication protol to TLS1.2
            [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
            $usersList= Invoke-webrequest -Method Get -Uri "https://vssps.dev.azure.com/$($UserDescriptorOrganization)/_apis/graph/users?api-version=6.0-preview.1&subjectTypes=aad&continuationToken=$($ContinuationToken)" -Headers @{Authorization = $credentials } -ContentType 'application/json' -UseBasicParsing
            $APIContents = $usersList.Content | ConvertFrom-Json 
            foreach($user in $APIContents.value)
            {
                if($user.principalName -eq $UserEmailAddress)
                {          
                    return $user.descriptor
                }
            }
            $ContinuationToken = $usersList.Headers.'x-ms-continuationtoken'
            } while ($ContinuationToken -ne $null)
        }


    catch
    {

        Write-Error "Failed to get user descriptor"
        Write-Output $_.Exception.Message
        $TelClient.TrackException($_.Exception)
        $TelClient.Flush()
    }
}

#### Function to add user to Org####

function Add_Users
{
    param (
        [string]$UserDescriptor
    )

    try
    {
        $checkUser= Invoke-webrequest -Method Get -Uri "https://vssps.dev.azure.com/$($OrgName)/_apis/graph/users/$($UserDescriptor)?api-version=6.0-preview.1" -Headers @{Authorization = $credentials } -ContentType 'application/json' -UseBasicParsing     
    }
    catch
    {
        if($_.Exception.Message -match "(401)")
        {
            Write-Error "gdbldsvc don't have access to ADO $($OrgName)"
            Write-Output $_.Exception.Message
            $TelClient.TrackException($_.Exception)
            $TelClient.Flush()            
        }

        elseif($_.Exception.Message -match "(404)")
        {
            try
            {
                $UserBody = '{"principalName":'+'"'+$UserEmailAddress+'"}'
                $addUser= Invoke-webrequest -Method POST -Body $UserBody -Uri "https://vssps.dev.azure.com/$($OrgName)/_apis/graph/users/$($UserDescriptor)?api-version=6.0-preview.1" -Headers @{Authorization = $credentials } -ContentType 'application/json' -UseBasicParsing
                return $UserDescriptor
            }
            catch
            {
                Write-Error "Failed to add user to ADO"
                Write-Output $_.Exception.Message
                $TelClient.TrackException($_.Exception)
                $TelClient.Flush()
            }
        }
        else
        {
            Write-Error "Failed to add users to ADO $($OrgName)"
            Write-Output $_.Exception.Message
            $TelClient.TrackException($_.Exception)
            $TelClient.Flush()
        }
        
    }
}

#### Function to add user to organization####
function Add_UsersTo_Org_PCA
{
    param (
        [string]$OrganizationName
    )

    try
    {
        $userDescriptor = Get_User_Descriptor
        Add_Users -UserDescriptor $userDescriptor
        do
        {

            ## Set communication protol to TLS1.2
            [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
            $grouplist= Invoke-webrequest -Method Get -Uri "https://vssps.dev.azure.com/$($OrganizationName)/_apis/graph/groups?api-version=6.0-preview.1&continuationToken=$($ContinuationToken)" -Headers @{Authorization = $credentials } -ContentType 'application/json' -UseBasicParsing
            $ContinuationToken = $grouplist.Headers.'x-ms-continuationtoken'
            $APIContents = $grouplist.Content | ConvertFrom-Json 
            foreach($group in $APIContents.value)
            {
                try
                {
                    if("[$OrgName]\Project Collection Administrators" -eq $group.principalName)
                    {            
                        $groupdescriptor = $group.descriptor
                        $url = "https://vssps.dev.azure.com/$($OrganizationName)/_apis/graph/memberships/$($userDescriptor)/$($groupdescriptor)?api-version=6.0-preview.1"
                        ## Set communication protol to TLS1.2
                        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
                        $result= Invoke-RestMethod -Method PUT -Uri $url -ContentType 'application/json' -Headers @{Authorization = $credentials } -ErrorAction Continue -UseBasicParsing
                        Add_Roleassignment_database -Roleassignment $group.principalName
                        $TelClient.TrackEvent("Added $($UserEmailAddress) to $($group.principalName)")
                        $TelClient.Flush()
                        $ContinuationToken=$null 
                        break
                    }
                }
                catch
                {
                    Write-Error "Failed to users as Project Collection Administrators"
                    Write-Output $_.Exception.Message
                    $TelClient.TrackException($_.Exception)
                    $TelClient.Flush()

            }
        }
        } while ($null -ne $ContinuationToken)

        
    }
    catch
    {
        Write-Error "Failed to get group details for the organization"
        Write-Output $_.Exception.Message
        $TelClient.TrackException($_.Exception)
        $TelClient.Flush()
        
    }
}

####Function to add user to project####
function Add_UsersTo_Project
{
    param (
        [string]$OrganizationName,
        [string]$ProjectName

    )

    $userDescriptor = Get_User_Descriptor
    Add_Users -UserDescriptor $userDescriptor 
    try
    {
        ## Set communication protol to TLS1.2
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $projectList = Invoke-RestMethod -Uri "https://dev.azure.com/$($OrganizationName)/_apis/projects?`$top=999&api-version=6.0" -Headers @{Authorization = $credentials } -Method Get -ContentType 'application/json' 
        foreach($project in $projectList.value)
        {
            if($ProjectName -eq $project.name)
            {
                try
                {
                    ## Set communication protol to TLS1.2
                    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
                    $projectDetails = Invoke-RestMethod -Uri "https://vssps.dev.azure.com/$($OrganizationName)/_apis/graph/descriptors/$($project.id)?api-version=5.0-preview.1" -Headers @{Authorization = $credentials } -Method Get -ContentType 'application/json' 
                    $GroupsUrl = "https://vssps.dev.azure.com/$($OrganizationName)/_apis/graph/groups?scopeDescriptor=$($projectDetails.value)&api-version=6.0-preview.1" 
                    ## Set communication protol to TLS1.2
                    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
                    $grouplist= Invoke-RestMethod -Uri $GroupsUrl -Headers @{Authorization = $credentials } -Method Get -ContentType 'application/json'
                }
                catch
                {
                    Write-Error "Failed to get group details  for project"
                    Write-Output $_.Exception.Message
                    $TelClient.TrackException($_.Exception)
                    $TelClient.Flush()
                }
                try
                {
                    foreach($group in $grouplist.value)
                    {
                        if(("[$($project.name)]\Build Administrators" -eq $group.principalName) -or ("[$($project.name)]\Endpoint Administrators" -eq $group.principalName))
                        {
                            $groupdescriptor = $group.descriptor
                            $url = "https://vssps.dev.azure.com/$($OrganizationName)/_apis/graph/memberships/$($userDescriptor)/$($groupdescriptor)?api-version=6.0-preview.1"
                            ## Set communication protol to TLS1.2
                            [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
                            $result= Invoke-RestMethod -Method PUT -Uri $url -ContentType 'application/json' -Headers @{Authorization = $credentials } -ErrorAction Continue
                            Add_Roleassignment_database -Roleassignment $group.principalName
                            $TelClient.TrackEvent("Added $($UserEmailAddress) to $($group.principalName)")
                            $TelClient.Flush() 
                        }
                    }
                    break
                }
                catch
                {
                    Write-Error "Failed to add user to the project"
                    Write-Output $_.Exception.Message
                    $TelClient.TrackException($_.Exception)
                    $TelClient.Flush()
                }
            }
        }
    }
    catch
    {

            Write-Error "Failed to get project details for organization"
            Write-Output $_.Exception.Message
            $TelClient.TrackException($_.Exception)
            $TelClient.Flush()
    }
}

####Function to log activity to sql database####
function Add_Roleassignment_database
{
    param(

        [string] $Roleassignment
    )

        try
        {              
            $SQLConnectionString = "Server=tcp:$($SQLServer),1433;Initial Catalog=$($SQLDataBase);Persist Security Info=False;User ID=$($SQLUserID);Password=$($SQLPassword);MultipleActiveResultSets=True;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
            $sqlCommand = New-Object System.Data.SqlClient.SqlCommand
            $sqlCommand.Connection = $SQLConnectionString
            [DateTime] $date= Get-Date -Format "yyyy-MM-dd HH:mm:ss"
            ## SQL Query
            $sqlCommand.CommandText = "SET NOCOUNT ON; " +
                "INSERT INTO dbo.ADOAccessLogs (SessionID,RequesterEmailAddress,OrganizationName,ProjectName,RequestType,AccessInitiationTime,IsActive, RoleType) " +
                "VALUES ('$sessionId','$UserEmailAddress','$OrgName','$ProjectName','$RequestType','$($date.ToUniversalTime())',1,'$Roleassignment')";
            # Run the query and get the scope ID back into $InsertedID
            $sqlCommand.Connection.Open()
            $sqlCommand.ExecuteScalar()
            $sqlCommand.Connection.Close()
        }
        catch
        {
            Write-Error "Failed to insert access logs to Database"
            Write-Output $_.Exception.Message
            $TelClient.TrackException($_.Exception)
            $TelClient.Flush()
            $SQLRetryCount++
            if($SQLRetryCount -lt 6)
            {
                Add_Roleassignment_database -Roleassignment $Roleassignment
            }
        }        
    
}


####Request type validation####
if( ($RequestType -eq "Process_Template_Change") -or ($RequestType -eq "Project_Creation"))
{
    try
    {
        ###Adding user to organization###
        Add_UsersTo_Org_PCA -OrganizationName $OrgName
        $TelClient.TrackEvent("Added $($UserEmailAddress) to $($OrgName) as Project Collection Administrators")
        $TelClient.Flush()
    }
    catch
    {
        Write-Error "Failed to users as Project Collection Administrators"
        Write-Output $_.Exception.Message
        $TelClient.TrackException($_.Exception)
        $TelClient.Flush()
    }
}
elseif( ($RequestType -ieq "Build_troubleshooting") -or ($RequestType -eq "Build_creation" ))
{
    if($ProjectName -eq $null)
    {
        Write-Error "Please provide Project details"
        $TelClient.TrackException("Project details is missing")
        $TelClient.Flush()
        break
    }
    try
    {
        ###Adding user to project###
        Add_UsersTo_Project -OrganizationName $OrgName -ProjectName $ProjectName
        $TelClient.TrackEvent("Added $($UserEmailAddress) to $($ProjectName)")
        $TelClient.Flush() 
    }
    catch
    {
        Write-Error "Failed while provding Build Administrator Permission"
        Write-Output $_.Exception.Message
        $TelClient.TrackException($_.Exception)
        $TelClient.Flush()
    }
}
else
{
    Write-Output "Please provide valid justification for ADO access"
    $TelClient.TrackException("Invalid justification provided for ADO access, email address : $($UserEmailAddress)" )
    $TelClient.Flush()
}

 

 

 

 

 

4. Create a Azure Sql server and database. Reference: https://docs.microsoft.com/en-us/azure/azure-sql/database/single-database-create-quickstart?tabs=azu...

5. Create a application insight resource. Reference: https://docs.microsoft.com/en-us/azure/azure-monitor/app/create-new-resource 

6. Store below credentials in Azure key vault. Reference: https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-portal

Secret: serviceAccountPAT, Value: Personal access token created at step 1

Secret: applicationInsightKey, Value: Instrumentation key created at step 5

Secret: SqlDatabaseName, Value: Sql details as created at step 4

Secret: SqlServerName, Value: Sql details as created at step 4

Secret: SqlAdminUserName, Value: Sql details as created at step 4

Secret: SqlAdminPassword, , Value: Sql details as created at step 4

 

7. Create a variable group in Azure DevOps and link all the secrets created at step 6 as variables. Reference: https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops&ta...

8. Create a release pipeline on Azure DevOps with pre-deployment enabled. This pre-deployment will be used to approve or deny request by administrator. Reference: https://docs.microsoft.com/en-us/learn/modules/create-release-pipeline/

9. Use below task in release pipeline to execute addUser.ps1 script

 

 

 

variables:
  UserDescriptorOrganization: '$(OrganizationName)'

steps:
- task: PowerShell@2
  displayName: 'PowerShell Script'
  inputs:
    targetType: filePath
    filePath: './$(System.DefaultWorkingDirectory)/_azureDevOpsJitAccess/addUser.ps1'
    arguments: '-OrgName $(OrganizationName) -RequestType $(RequestType) -UserEmailAddress $(EmailAddress) -LoggingTelemetryID $(applicationInsightKey) -PAT $(serviceAccountPAT) -ProjectName $(Project) -SQLPassword $(SqlAdminPassword) -SQLUserID $(SqlAdminUserName) -SQLDataBase $(SqlDatabaseName) -SQLServer $(SqlServerName) -UserDescriptorOrganization $(UserDescriptorOrganization)'

 

 

 

8. Add below variables as pipeline variable which will be used by user or executor to pass runtime variable. 

EmailAddress - This contain email id of user  whom just in time privilege access need to be enabled.

OrganizationName - Organization name where user is seeking privilege role.

Project - Project name where user is seeking access.

RequestType - This contain activity type which user want to perform and for which access is requested. Script as part of step 3, will check request type and based on that provide user with required permission.

UserDescriptorOrganization - This contain organization name where user is currently part of to extract user descriptor and accordingly add in destination/requested organization.

 

9. Create a script removeUser.ps1 to remove user after certain time. Below script will remove all users having permission more than 30min.

Note: Below script will read the database and fetch all users having access longer than 30 min and remove the same. To validate if user is removed, it will update IsActive column as 0 from 1.

 

 

Param
(

    [Parameter(Mandatory=$true,HelpMessage = "Application Insights details")]
    [string][ValidateNotNullOrEmpty()] $LoggingTelemetryID,

    [Parameter(Mandatory=$true)]
    [string][ValidateNotNullOrEmpty()] $PAT,

    [Parameter(Mandatory=$true)]
    [string][ValidateNotNullOrEmpty()] $SQLPassword,

    [Parameter(Mandatory=$true)]
    [string][ValidateNotNullOrEmpty()] $SQLUserID,

    [Parameter(Mandatory=$true)]
    [string][ValidateNotNullOrEmpty()] $SQLDataBase,

    [Parameter(Mandatory=$true)]
    [string][ValidateNotNullOrEmpty()] $SQLServer,

    [Parameter(Mandatory=$true)]
    [string][ValidateNotNullOrEmpty()] $UserDescriptorOrganization

)

###Initializing telemetry client and Varibales###
try
{
    $AppInsightsdllPath = "$PSScriptRoot\Microsoft.ApplicationInsights.dll"
    [Reflection.Assembly]::LoadFile($AppInsightsdllPath)   
    $TelClient = New-Object "Microsoft.ApplicationInsights.TelemetryClient"
    $TelClient.InstrumentationKey = $LoggingTelemetryID
    $credentials = "Basic " + [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$PAT"))
    $SQLConnectionString = "Server=tcp:$($SQLServer),1433;Initial Catalog=$($SQLDataBase);Persist Security Info=False;User ID=$($SQLUserID);Password=$($SQLPassword);MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
}
catch
{
    Write-Error "Failed to initialize ApplicationInsights"
    Write-Output $_.Exception.Message
}

####Get past 30 min active role data####
function Get-ActiveAssignment-Database
{
    try
    {   
        [DateTime] $date= Get-Date -Format "yyyy-MM-dd HH:mm:ss"
        $query = "SELECT * FROM ADOAccessLogs where IsActive = 1 and AccessInitiationTime < '$($date.AddMinutes(-30).ToUniversalTime())'"
        $Datatable = New-Object System.Data.DataTable
        $command = New-Object System.Data.SqlClient.SqlCommand
        $command.Connection = $SQLConnectionString
        $command.CommandText = $query
        $command.Connection.Open()
        $results = $command.ExecuteReader()
        $Datatable.Load($results)
        $command.Connection.Close()
        return $Datatable;

    }

    ####Catch SQL Exception####
    catch
    {
        Write-Error "Failed to get access logs from Database"
        Write-Output $_.Exception.Message
        $TelClient.TrackException($_.Exception)
        $TelClient.Flush()   
    }
}

####Function to get user descriptor which will be removed####
function Get-User-Descriptor
{
    param(
        
        [string] $UserEmailAddress
    )
    try
    {
        $ContinuationToken=$null
        do{

            ## Set communication protol to TLS1.2
            [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
            $usersList= Invoke-webrequest -Method Get -Uri "https://vssps.dev.azure.com/$($UserDescriptorOrganization)/_apis/graph/users?api-version=6.0-preview.1&subjectTypes=aad&continuationToken=$($ContinuationToken)" -Headers @{Authorization = $credentials } -ContentType 'application/json' -UseBasicParsing
            $APIContents = $usersList.Content | ConvertFrom-Json 
            foreach($user in $APIContents.value)
            {
                if($user.principalName -eq $UserEmailAddress)
                {                
                    return $user.descriptor
                }
            }
            $ContinuationToken = $usersList.Headers.'x-ms-continuationtoken'
            } while ($null -ne $ContinuationToken)
        }
    catch
    {
        Write-Error "Failed to get group details for the organization"
        Write-Output $_.Exception.Message
        $TelClient.TrackException($_.Exception)
        $TelClient.Flush()
    }
}


function Remove-AccessFor-Users
{
    param (
        [object]$ActiveAssignments
    )

    try
    {
        if($null -eq $ActiveAssignments)
        {
            Write-Output "No Active Role Assignments Found"
            $TelClient.TrackEvent("No Active Role Assignments Found")
            $TelClient.Flush()
            break            
        }

        foreach($ActiveAssignment in $ActiveAssignments)
        {
            if($ActiveAssignment.RoleType -match "Project Collection Administrators")
            {
                Remove-Access-From-Org -EmailAddress $ActiveAssignment.RequesterEmailAddress -OrgName $ActiveAssignment.OrganizationName -SessionID $ActiveAssignment.SessionID -RoleType $ActiveAssignment.RoleType
            }

            elseif(($ActiveAssignment.RoleType -match "Build Administrators") -or ($ActiveAssignment.RoleType -match "Endpoint Administrators") )
            {
                Remove-Access-From-Project -EmailAddress $ActiveAssignment.RequesterEmailAddress -OrgName $ActiveAssignment.OrganizationName -SessionID $ActiveAssignment.SessionID -RoleType $ActiveAssignment.RoleType -ProjectName $ActiveAssignment.ProjectName
            }

            else
            {
                Write-Error "Invaid RoleType : $($ActiveAssignment.RoleType)"
                $TelClient.TrackException("Invaid RoleType : $($ActiveAssignment.RoleType)")
                $TelClient.Flush()
                
            }
        }
    }

    catch
    {
        $TelClient.TrackException($_.Exception)
        $TelClient.Flush()
        
    }


}
function Remove-Access-From-Org 
{
    param (
        [string]$EmailAddress,
        [String]$OrgName,
        [String]$SessionID,
        [String]$RoleType
    )

    try
    {
        $userDescriptor= Get-User-Descriptor -UserEmailAddress $EmailAddress
        do
        {

            ## Set communication protol to TLS1.2
            [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
            $grouplist= Invoke-webrequest -Method Get -Uri "https://vssps.dev.azure.com/$($OrgName)/_apis/graph/groups?api-version=6.0-preview.1&continuationToken=$($ContinuationToken)" -Headers @{Authorization = $credentials } -ContentType 'application/json' -UseBasicParsing
            $ContinuationToken = $grouplist.Headers.'x-ms-continuationtoken'
            $APIContents = $grouplist.Content | ConvertFrom-Json 
            foreach($group in $APIContents.value)
            {
                try
                {
                    if("[$OrgName]\Project Collection Administrators" -eq $group.principalName)
                    {            
                        $groupdescriptor = $group.descriptor
                        $url = "https://vssps.dev.azure.com/$($OrgName)/_apis/graph/memberships/$($userDescriptor)/$($groupdescriptor)?api-version=6.0-preview.1"

                        ## Set communication protol to TLS1.2
                        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
                        Invoke-RestMethod -Method DELETE -Uri $url -ContentType 'application/json' -Headers @{Authorization = $credentials } -ErrorAction Continue -UseBasicParsing
                        Update_Roleassignment_database -Email $EmailAddress -SessionID $SessionID -RoleType $RoleType
                        $TelClient.TrackEvent("Added $($UserEmailAddress) to $($group.principalName)")
                        $TelClient.Flush()
                        $ContinuationToken=$null 
                        break
                    }
                }
                catch
                {
                    Write-Error "Failed to remove user $($EmailAddress) from   Project Collection Administrators"
                    Write-Output $_.Exception.Message
                    $TelClient.TrackException($_.Exception)
                    $TelClient.Flush()
            }
        }
        } while ($null -ne $ContinuationToken)

    }
    catch
    {
        Write-Error "Failed to get group details from Org : $(OrgName)"
        Write-Output $_.Exception.Message
        $TelClient.TrackException($_.Exception)
        $TelClient.Flush()
    
    }
} 

function Remove-Access-From-Project
{
    param (
        [string]$EmailAddress,
        [String]$OrgName,
        [String]$ProjectName,
        [String]$SessionID,
        [String]$RoleType
    )

    $userDescriptor = $userDescriptor= Get-User-Descriptor -UserEmailAddress $EmailAddress
    try
    {
        ## Set communication protol to TLS1.2
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $projectList = Invoke-RestMethod -Uri "https://dev.azure.com/$($OrgName)/_apis/projects?`$top=999&api-version=6.0" -Headers @{Authorization = $credentials } -Method Get -ContentType 'application/json'  
        foreach($project in $projectList.value)
        {
            if($ProjectName -eq $project.name)
            {
                try
                {
                    ## Set communication protol to TLS1.2
                    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
                    $projectDetails = Invoke-RestMethod -Uri "https://vssps.dev.azure.com/$($OrgName)/_apis/graph/descriptors/$($project.id)?api-version=5.0-preview.1" -Headers @{Authorization = $credentials } -Method Get -ContentType 'application/json' 
                    $GroupsUrl = "https://vssps.dev.azure.com/$($OrgName)/_apis/graph/groups?scopeDescriptor=$($projectDetails.value)&api-version=6.0-preview.1" 

                    ## Set communication protol to TLS1.2
                    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
                    $grouplist= Invoke-RestMethod -Uri $GroupsUrl -Headers @{Authorization = $credentials } -Method Get -ContentType 'application/json'
                }
                catch
                {
                    Write-Error "Failed to get group details  for project"
                    Write-Output $_.Exception.Message
                    $TelClient.TrackException($_.Exception)
                    $TelClient.Flush()
                }
                try
                {
                    foreach($group in $grouplist.value)
                    {
                        if(($RoleType -eq $group.principalName) -or ($RoleType -eq $group.principalName))
                        {
                            $groupdescriptor = $group.descriptor
                            $url = "https://vssps.dev.azure.com/$($OrgName)/_apis/graph/memberships/$($userDescriptor)/$($groupdescriptor)?api-version=6.0-preview.1"

                            ## Set communication protol to TLS1.2
                            [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
                            Invoke-RestMethod -Method DELETE -Uri $url -ContentType 'application/json' -Headers @{Authorization = $credentials } -ErrorAction Continue
                            $TelClient.TrackEvent("Removed $($UserEmailAddress) from  $($group.principalName)")
                            $TelClient.Flush() 

                            ## Updated status in DataBase
                            Update_Roleassignment_database -Email $EmailAddress -SessionID $SessionID -RoleType $RoleType

                        }
                    }
                    break
                }
                catch
                {
                    Write-Error "Failed to Delete user $($EmailAddress) from  the project : $($ProjectName) Group : $($RoleType)"
                    Write-Output $_.Exception.Message
                    $TelClient.TrackException($_.Exception)
                    $TelClient.Flush()
                }
            }
        }
    }
    catch
    {
        Write-Error "Failed to get project details for organization"
        Write-Output $_.Exception.Message
        $TelClient.TrackException($_.Exception)
        $TelClient.Flush()
    }
}

function Update_Roleassignment_database
{
    param (
        [string]$Email,
        [String]$SessionID,
        [String]$RoleType
    )

    try
    {
        $query = "UPDATE  ADOAccessLogs SET IsActive = 0 where SessionID='$($SessionID)' AND RoleType='$($RoleType)'"
        $command = New-Object System.Data.SqlClient.SqlCommand
        $command.Connection = $SQLConnectionString
        $command.CommandText = $query
        $command.Connection.Open()
        $command.ExecuteReader()
        $command.Connection.Close()
    }

    catch
    {
        Write-Error "Failed to update active status for User : $($Email) SessionID : $($SessionID)"
        Write-Output $_.Exception.Message
        $TelClient.TrackException($_.Exception)
        $TelClient.Flush()
        
    }

}
$ActiveUsers = $null
$ActiveUsers = Get-ActiveAssignment-Database | Sort-Object ID -Unique
$ActiveUsers
Remove-AccessFor-Users -ActiveAssignments $ActiveUsers

 

 

 

10. Create a build pipeline using below YAML. This will require variable group to be linked, created as part of step 7

 

 

schedules:
- cron: "*/10 * * * *"
  displayName: Daily build for every 30 min
  branches:
    include:
    - master
  always: true


pool:
  Image: 'windows-2019'


steps:
- task: PowerShell@2
  displayName: 'PowerShell Script'
  inputs:
    filePath: './removeUser.ps1'
    arguments: '-LoggingTelemetryID $(applicationInsightKey) -PAT $(serviceAccountPAT) -SQLPassword $(SqlAdminPassword) -SQLUserID $(SqlAdminUserName) -SQLDataBase $(SqlDatabaseName) -SQLServer $(SqlServerName) -UserDescriptorOrganization $(UserDescriptorOrganization)'

 

 

 

 

 

%3CLINGO-SUB%20id%3D%22lingo-sub-3062589%22%20slang%3D%22en-US%22%3EJust%20in%20time%20privilege's%20access%20to%20Azure%20DevOps%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-3062589%22%20slang%3D%22en-US%22%3E%3CP%3ETo%20perform%20certain%20actions%20on%20Azure%20DevOps%20including%2C%20process%20template%20changes%2C%20extension%20import%2C%20build%20modification%20etc.%20requires%20user%20to%20have%20privilege's%20scopes%20at%20either%20organization%20or%20project%20level.%20In%20large%20enterprises%20where%20Azure%20DevOps%20organizations%20are%20centrally%20managed%20or%20managed%20via%20service%20accounts%2C%20enabling%20permanent%20privilege%20access%20for%20group%20of%20members%20posses%20lot%20of%20security%20risk.%26nbsp%3BIn%20scenario's%20where%20organizations%20are%20created%20using%20service%20account%2C%20require%20user%20to%20login%20via%20same%20to%20perform%20privilege%20actions.%20This%20posses%20a%20security%20risk%20of%20sharing%20credentials%20with%20multiple%20users%20and%20traceability%20of%20action%20performed.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3ESince%20there%20is%20no%20out%20of%20box%20solution%20available%20to%20enable%20just%20in%20time%20access%20with%20privilege%20role%20alike%20%22Azure%20PIM%22%2C%20there%20is%20a%20custom%20approach%20can%20be%20used%20to%20enable%20just%20in%20time%20experience%20and%20control.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%3CSTRONG%3ETechnology%20involved%3A%3C%2FSTRONG%3E%3C%2FP%3E%0A%3CUL%3E%0A%3CLI%3EPowerShell%3C%2FLI%3E%0A%3CLI%3EAzure%20DevOps%20Api's%3C%2FLI%3E%0A%3CLI%3EAzure%20SQL%20server%3C%2FLI%3E%0A%3CLI%3EAzure%20DevOps%20pipeline%3C%2FLI%3E%0A%3C%2FUL%3E%0A%3CP%3E%3CSTRONG%3EApproach%3C%2FSTRONG%3E%3A%3C%2FP%3E%0A%3COL%3E%0A%3CLI%3EWrite%20a%20script%20which%20contains%20steps%20to%20add%20user%20to%20Azure%20DevOps%20organization%2Fproject%20based%20on%20input%3C%2FLI%3E%0A%3CLI%3ECreate%20a%20release%20pipeline(pipeline1)%20with%20pre-deployment%20gate%20enabled%3C%2FLI%3E%0A%3CLI%3EStore%20execution%20output%20in%20database%3C%2FLI%3E%0A%3CLI%3ECreate%20another%20script%20which%20will%20be%20used%20to%20fetch%20data%20from%20database%20and%20remove%20privilege%20access%20enabled%20by%20pipeline1.%3C%2FLI%3E%0A%3CLI%3ECreate%20another%20Azure%20DevOps%20pipeline(pipeline2)%20which%20will%20run%20every%2010%20min%20and%20execute%20script%20to%20remove%20user.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%3CSTRONG%3ESteps%3A%3C%2FSTRONG%3E%3C%2FP%3E%0A%3CP%3E1.%20Login%20to%20Azure%20DevOps%20using%20service%20account%20having%20owner%20access%20across%20Azure%20DevOps%20organization%20managed%20by%20team.%3C%2FP%3E%0A%3CP%3E2.%20Create%20a%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fdevops%2Forganizations%2Faccounts%2Fuse-personal-access-tokens-to-authenticate%3Fview%3Dazure-devops%26amp%3Btabs%3Dpreview-page%22%20target%3D%22_self%22%20rel%3D%22noopener%20noreferrer%22%3Epersonal%20access%20token%3C%2FA%3E%20with%20below%20scopes%20across%20%22All%20accessible%20organization%22%3C%2FP%3E%0A%3CP%3E%3CEM%3E%3CU%3Epermissions%3C%2FU%3E%3A%26nbsp%3Bvso.graph_manage%20vso.project.%3C%2FEM%3E%3C%2FP%3E%0A%3CP%3E3.%20Create%20addUser.ps1%20as%20below%3A%3C%2FP%3E%0A%3CP%3EThis%20script%20will%20add%20user%20to%20respective%20organization%2Fproject%20with%20required%20privilege%20role%20and%20enter%20the%20data%20within%20Azure%20Sql%20server.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-powershell%22%3E%3CCODE%3EParam%0A(%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true%2CHelpMessage%20%3D%20%22Org%20name%20for%20which%20access%20is%20requeseted%22)%5D%0A%20%20%20%20%5Bstring%5D%5BValidateNotNullOrEmpty()%5D%20%24OrgName%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true%2CHelpMessage%20%3D%20%22Operation%20for%20which%20request%20is%20raised%22)%5D%0A%20%20%20%20%5Bstring%5D%5BValidateNotNullOrEmpty()%5D%20%24RequestType%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true%2CHelpMessage%20%3D%20%22email%20address%20for%20which%20access%20should%20be%20provded%22)%5D%0A%20%20%20%20%24UserEmailAddress%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true%2CHelpMessage%20%3D%20%22Application%20Insights%20details%22)%5D%0A%20%20%20%20%5Bstring%5D%5BValidateNotNullOrEmpty()%5D%20%24LoggingTelemetryID%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5Bstring%5D%5BValidateNotNullOrEmpty()%5D%20%24PAT%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5Bstring%5D%5BValidateNotNullOrEmpty()%5D%20%24SQLPassword%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5Bstring%5D%5BValidateNotNullOrEmpty()%5D%20%24SQLUserID%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5Bstring%5D%5BValidateNotNullOrEmpty()%5D%20%24SQLDataBase%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5Bstring%5D%5BValidateNotNullOrEmpty()%5D%20%24SQLServer%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5Bstring%5D%5BValidateNotNullOrEmpty()%5D%20%24UserDescriptorOrganization%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24false%2CHelpMessage%20%3D%20%22Project%20name%20for%20which%20access%20is%20requeseted%22)%5D%0A%20%20%20%20%5Bstring%5D%20%24ProjectName%0A%0A)%0A%0A%23%23%23%23%23Creating%20session%20id%23%23%23%23%0Atry%0A%7B%0A%20%20%20%20%24sessionId%20%3D%20%5Bguid%5D%3A%3ANewGuid().GUID%0A%7D%0Acatch%0A%7B%0A%20%20%20%20Write-Error%20%22Failed%20to%20create%20session%20id%22%0A%20%20%20%20Write-Output%20%24_.Exception.Message%0A%7D%0A%0A%23%23%23Initializing%20telemetry%20client%23%23%23%0Atry%0A%7B%0A%20%20%20%20%24AppInsightsdllPath%20%3D%20%22%24PSScriptRoot%5CMicrosoft.ApplicationInsights.dll%22%0A%20%20%20%20%5BReflection.Assembly%5D%3A%3ALoadFile(%24AppInsightsdllPath)%20%20%20%0A%20%20%20%20%24TelClient%20%3D%20New-Object%20%22Microsoft.ApplicationInsights.TelemetryClient%22%0A%20%20%20%20%24TelClient.InstrumentationKey%20%3D%20%24LoggingTelemetryID%0A%20%20%20%20%24credentials%20%3D%20%22Basic%20%22%20%2B%20%5BSystem.Convert%5D%3A%3AToBase64String(%5BSystem.Text.Encoding%5D%3A%3AASCII.GetBytes(%22%3A%24PAT%22))%0A%20%20%20%20%24SQLRetryCount%20%3D%200%20%0A%7D%0Acatch%0A%7B%0A%20%20%20%20Write-Error%20%22Failed%20to%20initialize%20ApplicationInsights%22%0A%20%20%20%20Write-Output%20%24_.Exception.Message%0A%7D%0A%0A%23%23%23%23Function%20to%20get%20user%20descriptor%20which%20will%20be%20used%20in%20adding%20function%23%23%23%23%0Afunction%20Get_User_Descriptor%0A%7B%0A%20%20%20%20try%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%24ContinuationToken%3D%24null%0A%20%20%20%20%20%20%20%20do%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20Set%20communication%20protol%20to%20TLS1.2%0A%20%20%20%20%20%20%20%20%20%20%20%20%5BNet.ServicePointManager%5D%3A%3ASecurityProtocol%20%3D%20%5BNet.SecurityProtocolType%5D%3A%3ATls12%0A%20%20%20%20%20%20%20%20%20%20%20%20%24usersList%3D%20Invoke-webrequest%20-Method%20Get%20-Uri%20%22https%3A%2F%2Fvssps.dev.azure.com%2F%24(%24UserDescriptorOrganization)%2F_apis%2Fgraph%2Fusers%3Fapi-version%3D6.0-preview.1%26amp%3BsubjectTypes%3Daad%26amp%3BcontinuationToken%3D%24(%24ContinuationToken)%22%20-Headers%20%40%7BAuthorization%20%3D%20%24credentials%20%7D%20-ContentType%20'application%2Fjson'%20-UseBasicParsing%0A%20%20%20%20%20%20%20%20%20%20%20%20%24APIContents%20%3D%20%24usersList.Content%20%7C%20ConvertFrom-Json%20%0A%20%20%20%20%20%20%20%20%20%20%20%20foreach(%24user%20in%20%24APIContents.value)%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(%24user.principalName%20-eq%20%24UserEmailAddress)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%24user.descriptor%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%24ContinuationToken%20%3D%20%24usersList.Headers.'x-ms-continuationtoken'%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20while%20(%24ContinuationToken%20-ne%20%24null)%0A%20%20%20%20%20%20%20%20%7D%0A%0A%0A%20%20%20%20catch%0A%20%20%20%20%7B%0A%0A%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20get%20user%20descriptor%22%0A%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%7D%0A%7D%0A%0A%23%23%23%23%20Function%20to%20add%20user%20to%20Org%23%23%23%23%0A%0Afunction%20Add_Users%0A%7B%0A%20%20%20%20param%20(%0A%20%20%20%20%20%20%20%20%5Bstring%5D%24UserDescriptor%0A%20%20%20%20)%0A%0A%20%20%20%20try%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%24checkUser%3D%20Invoke-webrequest%20-Method%20Get%20-Uri%20%22https%3A%2F%2Fvssps.dev.azure.com%2F%24(%24OrgName)%2F_apis%2Fgraph%2Fusers%2F%24(%24UserDescriptor)%3Fapi-version%3D6.0-preview.1%22%20-Headers%20%40%7BAuthorization%20%3D%20%24credentials%20%7D%20-ContentType%20'application%2Fjson'%20-UseBasicParsing%20%20%20%20%20%0A%20%20%20%20%7D%0A%20%20%20%20catch%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20if(%24_.Exception.Message%20-match%20%22(401)%22)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Write-Error%20%22gdbldsvc%20don't%20have%20access%20to%20ADO%20%24(%24OrgName)%22%0A%20%20%20%20%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20elseif(%24_.Exception.Message%20-match%20%22(404)%22)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24UserBody%20%3D%20'%7B%22principalName%22%3A'%2B'%22'%2B%24UserEmailAddress%2B'%22%7D'%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24addUser%3D%20Invoke-webrequest%20-Method%20POST%20-Body%20%24UserBody%20-Uri%20%22https%3A%2F%2Fvssps.dev.azure.com%2F%24(%24OrgName)%2F_apis%2Fgraph%2Fusers%2F%24(%24UserDescriptor)%3Fapi-version%3D6.0-preview.1%22%20-Headers%20%40%7BAuthorization%20%3D%20%24credentials%20%7D%20-ContentType%20'application%2Fjson'%20-UseBasicParsing%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%24UserDescriptor%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20catch%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20add%20user%20to%20ADO%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20else%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20add%20users%20to%20ADO%20%24(%24OrgName)%22%0A%20%20%20%20%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%7D%0A%7D%0A%0A%23%23%23%23%20Function%20to%20add%20user%20to%20organization%23%23%23%23%0Afunction%20Add_UsersTo_Org_PCA%0A%7B%0A%20%20%20%20param%20(%0A%20%20%20%20%20%20%20%20%5Bstring%5D%24OrganizationName%0A%20%20%20%20)%0A%0A%20%20%20%20try%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%24userDescriptor%20%3D%20Get_User_Descriptor%0A%20%20%20%20%20%20%20%20Add_Users%20-UserDescriptor%20%24userDescriptor%0A%20%20%20%20%20%20%20%20do%0A%20%20%20%20%20%20%20%20%7B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20Set%20communication%20protol%20to%20TLS1.2%0A%20%20%20%20%20%20%20%20%20%20%20%20%5BNet.ServicePointManager%5D%3A%3ASecurityProtocol%20%3D%20%5BNet.SecurityProtocolType%5D%3A%3ATls12%0A%20%20%20%20%20%20%20%20%20%20%20%20%24grouplist%3D%20Invoke-webrequest%20-Method%20Get%20-Uri%20%22https%3A%2F%2Fvssps.dev.azure.com%2F%24(%24OrganizationName)%2F_apis%2Fgraph%2Fgroups%3Fapi-version%3D6.0-preview.1%26amp%3BcontinuationToken%3D%24(%24ContinuationToken)%22%20-Headers%20%40%7BAuthorization%20%3D%20%24credentials%20%7D%20-ContentType%20'application%2Fjson'%20-UseBasicParsing%0A%20%20%20%20%20%20%20%20%20%20%20%20%24ContinuationToken%20%3D%20%24grouplist.Headers.'x-ms-continuationtoken'%0A%20%20%20%20%20%20%20%20%20%20%20%20%24APIContents%20%3D%20%24grouplist.Content%20%7C%20ConvertFrom-Json%20%0A%20%20%20%20%20%20%20%20%20%20%20%20foreach(%24group%20in%20%24APIContents.value)%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(%22%5B%24OrgName%5D%5CProject%20Collection%20Administrators%22%20-eq%20%24group.principalName)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24groupdescriptor%20%3D%20%24group.descriptor%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24url%20%3D%20%22https%3A%2F%2Fvssps.dev.azure.com%2F%24(%24OrganizationName)%2F_apis%2Fgraph%2Fmemberships%2F%24(%24userDescriptor)%2F%24(%24groupdescriptor)%3Fapi-version%3D6.0-preview.1%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20Set%20communication%20protol%20to%20TLS1.2%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5BNet.ServicePointManager%5D%3A%3ASecurityProtocol%20%3D%20%5BNet.SecurityProtocolType%5D%3A%3ATls12%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24result%3D%20Invoke-RestMethod%20-Method%20PUT%20-Uri%20%24url%20-ContentType%20'application%2Fjson'%20-Headers%20%40%7BAuthorization%20%3D%20%24credentials%20%7D%20-ErrorAction%20Continue%20-UseBasicParsing%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Add_Roleassignment_database%20-Roleassignment%20%24group.principalName%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackEvent(%22Added%20%24(%24UserEmailAddress)%20to%20%24(%24group.principalName)%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24ContinuationToken%3D%24null%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20catch%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20users%20as%20Project%20Collection%20Administrators%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%20while%20(%24null%20-ne%20%24ContinuationToken)%0A%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%7D%0A%20%20%20%20catch%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20get%20group%20details%20for%20the%20organization%22%0A%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%7D%0A%7D%0A%0A%23%23%23%23Function%20to%20add%20user%20to%20project%23%23%23%23%0Afunction%20Add_UsersTo_Project%0A%7B%0A%20%20%20%20param%20(%0A%20%20%20%20%20%20%20%20%5Bstring%5D%24OrganizationName%2C%0A%20%20%20%20%20%20%20%20%5Bstring%5D%24ProjectName%0A%0A%20%20%20%20)%0A%0A%20%20%20%20%24userDescriptor%20%3D%20Get_User_Descriptor%0A%20%20%20%20Add_Users%20-UserDescriptor%20%24userDescriptor%20%0A%20%20%20%20try%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%23%23%20Set%20communication%20protol%20to%20TLS1.2%0A%20%20%20%20%20%20%20%20%5BNet.ServicePointManager%5D%3A%3ASecurityProtocol%20%3D%20%5BNet.SecurityProtocolType%5D%3A%3ATls12%0A%20%20%20%20%20%20%20%20%24projectList%20%3D%20Invoke-RestMethod%20-Uri%20%22https%3A%2F%2Fdev.azure.com%2F%24(%24OrganizationName)%2F_apis%2Fprojects%3F%60%24top%3D999%26amp%3Bapi-version%3D6.0%22%20-Headers%20%40%7BAuthorization%20%3D%20%24credentials%20%7D%20-Method%20Get%20-ContentType%20'application%2Fjson'%20%0A%20%20%20%20%20%20%20%20foreach(%24project%20in%20%24projectList.value)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24ProjectName%20-eq%20%24project.name)%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20Set%20communication%20protol%20to%20TLS1.2%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5BNet.ServicePointManager%5D%3A%3ASecurityProtocol%20%3D%20%5BNet.SecurityProtocolType%5D%3A%3ATls12%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24projectDetails%20%3D%20Invoke-RestMethod%20-Uri%20%22https%3A%2F%2Fvssps.dev.azure.com%2F%24(%24OrganizationName)%2F_apis%2Fgraph%2Fdescriptors%2F%24(%24project.id)%3Fapi-version%3D5.0-preview.1%22%20-Headers%20%40%7BAuthorization%20%3D%20%24credentials%20%7D%20-Method%20Get%20-ContentType%20'application%2Fjson'%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24GroupsUrl%20%3D%20%22https%3A%2F%2Fvssps.dev.azure.com%2F%24(%24OrganizationName)%2F_apis%2Fgraph%2Fgroups%3FscopeDescriptor%3D%24(%24projectDetails.value)%26amp%3Bapi-version%3D6.0-preview.1%22%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20Set%20communication%20protol%20to%20TLS1.2%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5BNet.ServicePointManager%5D%3A%3ASecurityProtocol%20%3D%20%5BNet.SecurityProtocolType%5D%3A%3ATls12%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24grouplist%3D%20Invoke-RestMethod%20-Uri%20%24GroupsUrl%20-Headers%20%40%7BAuthorization%20%3D%20%24credentials%20%7D%20-Method%20Get%20-ContentType%20'application%2Fjson'%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20catch%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20get%20group%20details%20%20for%20project%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20foreach(%24group%20in%20%24grouplist.value)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if((%22%5B%24(%24project.name)%5D%5CBuild%20Administrators%22%20-eq%20%24group.principalName)%20-or%20(%22%5B%24(%24project.name)%5D%5CEndpoint%20Administrators%22%20-eq%20%24group.principalName))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24groupdescriptor%20%3D%20%24group.descriptor%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24url%20%3D%20%22https%3A%2F%2Fvssps.dev.azure.com%2F%24(%24OrganizationName)%2F_apis%2Fgraph%2Fmemberships%2F%24(%24userDescriptor)%2F%24(%24groupdescriptor)%3Fapi-version%3D6.0-preview.1%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20Set%20communication%20protol%20to%20TLS1.2%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5BNet.ServicePointManager%5D%3A%3ASecurityProtocol%20%3D%20%5BNet.SecurityProtocolType%5D%3A%3ATls12%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24result%3D%20Invoke-RestMethod%20-Method%20PUT%20-Uri%20%24url%20-ContentType%20'application%2Fjson'%20-Headers%20%40%7BAuthorization%20%3D%20%24credentials%20%7D%20-ErrorAction%20Continue%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Add_Roleassignment_database%20-Roleassignment%20%24group.principalName%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackEvent(%22Added%20%24(%24UserEmailAddress)%20to%20%24(%24group.principalName)%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20catch%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20add%20user%20to%20the%20project%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20catch%0A%20%20%20%20%7B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20get%20project%20details%20for%20organization%22%0A%20%20%20%20%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%7D%0A%7D%0A%0A%23%23%23%23Function%20to%20log%20activity%20to%20sql%20database%23%23%23%23%0Afunction%20Add_Roleassignment_database%0A%7B%0A%20%20%20%20param(%0A%0A%20%20%20%20%20%20%20%20%5Bstring%5D%20%24Roleassignment%0A%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20try%0A%20%20%20%20%20%20%20%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%24SQLConnectionString%20%3D%20%22Server%3Dtcp%3A%24(%24SQLServer)%2C1433%3BInitial%20Catalog%3D%24(%24SQLDataBase)%3BPersist%20Security%20Info%3DFalse%3BUser%20ID%3D%24(%24SQLUserID)%3BPassword%3D%24(%24SQLPassword)%3BMultipleActiveResultSets%3DTrue%3BEncrypt%3DTrue%3BTrustServerCertificate%3DFalse%3BConnection%20Timeout%3D30%3B%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%24sqlCommand%20%3D%20New-Object%20System.Data.SqlClient.SqlCommand%0A%20%20%20%20%20%20%20%20%20%20%20%20%24sqlCommand.Connection%20%3D%20%24SQLConnectionString%0A%20%20%20%20%20%20%20%20%20%20%20%20%5BDateTime%5D%20%24date%3D%20Get-Date%20-Format%20%22yyyy-MM-dd%20HH%3Amm%3Ass%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20SQL%20Query%0A%20%20%20%20%20%20%20%20%20%20%20%20%24sqlCommand.CommandText%20%3D%20%22SET%20NOCOUNT%20ON%3B%20%22%20%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22INSERT%20INTO%20dbo.ADOAccessLogs%20(SessionID%2CRequesterEmailAddress%2COrganizationName%2CProjectName%2CRequestType%2CAccessInitiationTime%2CIsActive%2C%20RoleType)%20%22%20%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22VALUES%20('%24sessionId'%2C'%24UserEmailAddress'%2C'%24OrgName'%2C'%24ProjectName'%2C'%24RequestType'%2C'%24(%24date.ToUniversalTime())'%2C1%2C'%24Roleassignment')%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Run%20the%20query%20and%20get%20the%20scope%20ID%20back%20into%20%24InsertedID%0A%20%20%20%20%20%20%20%20%20%20%20%20%24sqlCommand.Connection.Open()%0A%20%20%20%20%20%20%20%20%20%20%20%20%24sqlCommand.ExecuteScalar()%0A%20%20%20%20%20%20%20%20%20%20%20%20%24sqlCommand.Connection.Close()%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20catch%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20insert%20access%20logs%20to%20Database%22%0A%20%20%20%20%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%20%20%20%20%20%20%20%20%24SQLRetryCount%2B%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24SQLRetryCount%20-lt%206)%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Add_Roleassignment_database%20-Roleassignment%20%24Roleassignment%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%20%20%20%0A%20%20%20%20%0A%7D%0A%0A%0A%23%23%23%23Request%20type%20validation%23%23%23%23%0Aif(%20(%24RequestType%20-eq%20%22Process_Template_Change%22)%20-or%20(%24RequestType%20-eq%20%22Project_Creation%22))%0A%7B%0A%20%20%20%20try%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%23%23%23Adding%20user%20to%20organization%23%23%23%0A%20%20%20%20%20%20%20%20Add_UsersTo_Org_PCA%20-OrganizationName%20%24OrgName%0A%20%20%20%20%20%20%20%20%24TelClient.TrackEvent(%22Added%20%24(%24UserEmailAddress)%20to%20%24(%24OrgName)%20as%20Project%20Collection%20Administrators%22)%0A%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%7D%0A%20%20%20%20catch%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20users%20as%20Project%20Collection%20Administrators%22%0A%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%7D%0A%7D%0Aelseif(%20(%24RequestType%20-ieq%20%22Build_troubleshooting%22)%20-or%20(%24RequestType%20-eq%20%22Build_creation%22%20))%0A%7B%0A%20%20%20%20if(%24ProjectName%20-eq%20%24null)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20Write-Error%20%22Please%20provide%20Project%20details%22%0A%20%20%20%20%20%20%20%20%24TelClient.TrackException(%22Project%20details%20is%20missing%22)%0A%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%20%20%20%20break%0A%20%20%20%20%7D%0A%20%20%20%20try%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%23%23%23Adding%20user%20to%20project%23%23%23%0A%20%20%20%20%20%20%20%20Add_UsersTo_Project%20-OrganizationName%20%24OrgName%20-ProjectName%20%24ProjectName%0A%20%20%20%20%20%20%20%20%24TelClient.TrackEvent(%22Added%20%24(%24UserEmailAddress)%20to%20%24(%24ProjectName)%22)%0A%20%20%20%20%20%20%20%20%24TelClient.Flush()%20%0A%20%20%20%20%7D%0A%20%20%20%20catch%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20while%20provding%20Build%20Administrator%20Permission%22%0A%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%7D%0A%7D%0Aelse%0A%7B%0A%20%20%20%20Write-Output%20%22Please%20provide%20valid%20justification%20for%20ADO%20access%22%0A%20%20%20%20%24TelClient.TrackException(%22Invalid%20justification%20provided%20for%20ADO%20access%2C%20email%20address%20%3A%20%24(%24UserEmailAddress)%22%20)%0A%20%20%20%20%24TelClient.Flush()%0A%7D%0A%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E4.%20Create%20a%20Azure%20Sql%20server%20and%20database.%20Reference%3A%26nbsp%3B%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fazure-sql%2Fdatabase%2Fsingle-database-create-quickstart%3Ftabs%3Dazure-portal%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fazure-sql%2Fdatabase%2Fsingle-database-create-quickstart%3Ftabs%3Dazure-portal%3C%2FA%3E%3C%2FP%3E%0A%3CP%3E5.%20Create%20a%20application%20insight%20resource.%20Reference%3A%26nbsp%3B%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fazure-monitor%2Fapp%2Fcreate-new-resource%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fazure-monitor%2Fapp%2Fcreate-new-resource%3C%2FA%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E6.%20Store%20below%20credentials%20in%20Azure%20key%20vault.%20Reference%3A%26nbsp%3B%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fkey-vault%2Fsecrets%2Fquick-create-portal%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fkey-vault%2Fsecrets%2Fquick-create-portal%3C%2FA%3E%3C%2FP%3E%0A%3CP%3ESecret%3A%20serviceAccountPAT%2C%20Value%3A%20Personal%20access%20token%20created%20at%20step%201%3C%2FP%3E%0A%3CP%3ESecret%3A%20applicationInsightKey%2C%20Value%3A%20Instrumentation%20key%20created%20at%20step%205%3C%2FP%3E%0A%3CP%3ESecret%3A%20SqlDatabaseName%2C%20Value%3A%20Sql%20details%20as%20created%20at%20step%204%3C%2FP%3E%0A%3CP%3ESecret%3A%20SqlServerName%2C%20Value%3A%20Sql%20details%20as%20created%20at%20step%204%3C%2FP%3E%0A%3CP%3ESecret%3A%20SqlAdminUserName%2C%20Value%3A%20Sql%20details%20as%20created%20at%20step%204%3C%2FP%3E%0A%3CP%3ESecret%3A%20SqlAdminPassword%2C%26nbsp%3B%2C%20Value%3A%20Sql%20details%20as%20created%20at%20step%204%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E7.%20Create%20a%20variable%20group%20in%20Azure%20DevOps%20and%20link%20all%20the%20secrets%20created%20at%20step%206%20as%20variables.%20Reference%3A%26nbsp%3B%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fdevops%2Fpipelines%2Flibrary%2Fvariable-groups%3Fview%3Dazure-devops%26amp%3Btabs%3Dclassic%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fdevops%2Fpipelines%2Flibrary%2Fvariable-groups%3Fview%3Dazure-devops%26amp%3Btabs%3Dclassic%3C%2FA%3E%3C%2FP%3E%0A%3CP%3E8.%20Create%20a%20release%20pipeline%20on%20Azure%20DevOps%20with%20pre-deployment%20enabled.%20This%20pre-deployment%20will%20be%20used%20to%20approve%20or%20deny%20request%20by%20administrator.%20Reference%3A%26nbsp%3B%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Flearn%2Fmodules%2Fcreate-release-pipeline%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Flearn%2Fmodules%2Fcreate-release-pipeline%2F%3C%2FA%3E%3C%2FP%3E%0A%3CP%3E9.%20Use%20below%20task%20in%20release%20pipeline%20to%20execute%20addUser.ps1%20script%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-yaml%22%3E%3CCODE%3Evariables%3A%0A%20%20UserDescriptorOrganization%3A%20'%24(OrganizationName)'%0A%0Asteps%3A%0A-%20task%3A%20PowerShell%402%0A%20%20displayName%3A%20'PowerShell%20Script'%0A%20%20inputs%3A%0A%20%20%20%20targetType%3A%20filePath%0A%20%20%20%20filePath%3A%20'.%2F%24(System.DefaultWorkingDirectory)%2F_azureDevOpsJitAccess%2FaddUser.ps1'%0A%20%20%20%20arguments%3A%20'-OrgName%20%24(OrganizationName)%20-RequestType%20%24(RequestType)%20-UserEmailAddress%20%24(EmailAddress)%20-LoggingTelemetryID%20%24(applicationInsightKey)%20-PAT%20%24(serviceAccountPAT)%20-ProjectName%20%24(Project)%20-SQLPassword%20%24(SqlAdminPassword)%20-SQLUserID%20%24(SqlAdminUserName)%20-SQLDataBase%20%24(SqlDatabaseName)%20-SQLServer%20%24(SqlServerName)%20-UserDescriptorOrganization%20%24(UserDescriptorOrganization)'%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E8.%20Add%20below%20variables%20as%20pipeline%20variable%20which%20will%20be%20used%20by%20user%20or%20executor%20to%20pass%20runtime%20variable.%26nbsp%3B%3C%2FP%3E%0A%3CP%3EEmailAddress%20-%20This%20contain%20email%20id%20of%20user%26nbsp%3B%20whom%20just%20in%20time%20privilege%20access%20need%20to%20be%20enabled.%3C%2FP%3E%0A%3CP%3EOrganizationName%20-%20Organization%20name%20where%20user%20is%20seeking%20privilege%20role.%3C%2FP%3E%0A%3CP%3EProject%20-%20Project%20name%20where%20user%20is%20seeking%20access.%3C%2FP%3E%0A%3CP%3ERequestType%20-%20This%20contain%20activity%20type%20which%20user%20want%20to%20perform%20and%20for%20which%20access%20is%20requested.%20Script%20as%20part%20of%20step%203%2C%20will%20check%20request%20type%20and%20based%20on%20that%20provide%20user%20with%20required%20permission.%3C%2FP%3E%0A%3CP%3EUserDescriptorOrganization%20-%20This%20contain%20organization%20name%20where%20user%20is%20currently%20part%20of%20to%20extract%20user%20descriptor%20and%20accordingly%20add%20in%20destination%2Frequested%20organization.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E9.%20Create%20a%20script%20removeUser.ps1%20to%20remove%20user%20after%20certain%20time.%20Below%20script%20will%20remove%20all%20users%20having%20permission%20more%20than%2030min.%3C%2FP%3E%0A%3CP%3ENote%3A%20Below%20script%20will%20read%20the%20database%20and%20fetch%20all%20users%20having%20access%20longer%20than%2030%20min%20and%20remove%20the%20same.%20To%20validate%20if%20user%20is%20removed%2C%20it%20will%20update%20IsActive%20column%20as%200%20from%201.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-powershell%22%3E%3CCODE%3EParam%0A(%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true%2CHelpMessage%20%3D%20%22Application%20Insights%20details%22)%5D%0A%20%20%20%20%5Bstring%5D%5BValidateNotNullOrEmpty()%5D%20%24LoggingTelemetryID%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5Bstring%5D%5BValidateNotNullOrEmpty()%5D%20%24PAT%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5Bstring%5D%5BValidateNotNullOrEmpty()%5D%20%24SQLPassword%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5Bstring%5D%5BValidateNotNullOrEmpty()%5D%20%24SQLUserID%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5Bstring%5D%5BValidateNotNullOrEmpty()%5D%20%24SQLDataBase%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5Bstring%5D%5BValidateNotNullOrEmpty()%5D%20%24SQLServer%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5Bstring%5D%5BValidateNotNullOrEmpty()%5D%20%24UserDescriptorOrganization%0A%0A)%0A%0A%23%23%23Initializing%20telemetry%20client%20and%20Varibales%23%23%23%0Atry%0A%7B%0A%20%20%20%20%24AppInsightsdllPath%20%3D%20%22%24PSScriptRoot%5CMicrosoft.ApplicationInsights.dll%22%0A%20%20%20%20%5BReflection.Assembly%5D%3A%3ALoadFile(%24AppInsightsdllPath)%20%20%20%0A%20%20%20%20%24TelClient%20%3D%20New-Object%20%22Microsoft.ApplicationInsights.TelemetryClient%22%0A%20%20%20%20%24TelClient.InstrumentationKey%20%3D%20%24LoggingTelemetryID%0A%20%20%20%20%24credentials%20%3D%20%22Basic%20%22%20%2B%20%5BSystem.Convert%5D%3A%3AToBase64String(%5BSystem.Text.Encoding%5D%3A%3AASCII.GetBytes(%22%3A%24PAT%22))%0A%20%20%20%20%24SQLConnectionString%20%3D%20%22Server%3Dtcp%3A%24(%24SQLServer)%2C1433%3BInitial%20Catalog%3D%24(%24SQLDataBase)%3BPersist%20Security%20Info%3DFalse%3BUser%20ID%3D%24(%24SQLUserID)%3BPassword%3D%24(%24SQLPassword)%3BMultipleActiveResultSets%3DFalse%3BEncrypt%3DTrue%3BTrustServerCertificate%3DFalse%3BConnection%20Timeout%3D30%3B%22%0A%7D%0Acatch%0A%7B%0A%20%20%20%20Write-Error%20%22Failed%20to%20initialize%20ApplicationInsights%22%0A%20%20%20%20Write-Output%20%24_.Exception.Message%0A%7D%0A%0A%23%23%23%23Get%20past%2030%20min%20active%20role%20data%23%23%23%23%0Afunction%20Get-ActiveAssignment-Database%0A%7B%0A%20%20%20%20try%0A%20%20%20%20%7B%20%20%20%0A%20%20%20%20%20%20%20%20%5BDateTime%5D%20%24date%3D%20Get-Date%20-Format%20%22yyyy-MM-dd%20HH%3Amm%3Ass%22%0A%20%20%20%20%20%20%20%20%24query%20%3D%20%22SELECT%20*%20FROM%20ADOAccessLogs%20where%20IsActive%20%3D%201%20and%20AccessInitiationTime%20%26lt%3B%20'%24(%24date.AddMinutes(-30).ToUniversalTime())'%22%0A%20%20%20%20%20%20%20%20%24Datatable%20%3D%20New-Object%20System.Data.DataTable%0A%20%20%20%20%20%20%20%20%24command%20%3D%20New-Object%20System.Data.SqlClient.SqlCommand%0A%20%20%20%20%20%20%20%20%24command.Connection%20%3D%20%24SQLConnectionString%0A%20%20%20%20%20%20%20%20%24command.CommandText%20%3D%20%24query%0A%20%20%20%20%20%20%20%20%24command.Connection.Open()%0A%20%20%20%20%20%20%20%20%24results%20%3D%20%24command.ExecuteReader()%0A%20%20%20%20%20%20%20%20%24Datatable.Load(%24results)%0A%20%20%20%20%20%20%20%20%24command.Connection.Close()%0A%20%20%20%20%20%20%20%20return%20%24Datatable%3B%0A%0A%20%20%20%20%7D%0A%0A%20%20%20%20%23%23%23%23Catch%20SQL%20Exception%23%23%23%23%0A%20%20%20%20catch%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20get%20access%20logs%20from%20Database%22%0A%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%24TelClient.Flush()%20%20%20%0A%20%20%20%20%7D%0A%7D%0A%0A%23%23%23%23Function%20to%20get%20user%20descriptor%20which%20will%20be%20removed%23%23%23%23%0Afunction%20Get-User-Descriptor%0A%7B%0A%20%20%20%20param(%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%5Bstring%5D%20%24UserEmailAddress%0A%20%20%20%20)%0A%20%20%20%20try%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%24ContinuationToken%3D%24null%0A%20%20%20%20%20%20%20%20do%7B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20Set%20communication%20protol%20to%20TLS1.2%0A%20%20%20%20%20%20%20%20%20%20%20%20%5BNet.ServicePointManager%5D%3A%3ASecurityProtocol%20%3D%20%5BNet.SecurityProtocolType%5D%3A%3ATls12%0A%20%20%20%20%20%20%20%20%20%20%20%20%24usersList%3D%20Invoke-webrequest%20-Method%20Get%20-Uri%20%22https%3A%2F%2Fvssps.dev.azure.com%2F%24(%24UserDescriptorOrganization)%2F_apis%2Fgraph%2Fusers%3Fapi-version%3D6.0-preview.1%26amp%3BsubjectTypes%3Daad%26amp%3BcontinuationToken%3D%24(%24ContinuationToken)%22%20-Headers%20%40%7BAuthorization%20%3D%20%24credentials%20%7D%20-ContentType%20'application%2Fjson'%20-UseBasicParsing%0A%20%20%20%20%20%20%20%20%20%20%20%20%24APIContents%20%3D%20%24usersList.Content%20%7C%20ConvertFrom-Json%20%0A%20%20%20%20%20%20%20%20%20%20%20%20foreach(%24user%20in%20%24APIContents.value)%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(%24user.principalName%20-eq%20%24UserEmailAddress)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%24user.descriptor%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%24ContinuationToken%20%3D%20%24usersList.Headers.'x-ms-continuationtoken'%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20while%20(%24null%20-ne%20%24ContinuationToken)%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20catch%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20get%20group%20details%20for%20the%20organization%22%0A%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%7D%0A%7D%0A%0A%0Afunction%20Remove-AccessFor-Users%0A%7B%0A%20%20%20%20param%20(%0A%20%20%20%20%20%20%20%20%5Bobject%5D%24ActiveAssignments%0A%20%20%20%20)%0A%0A%20%20%20%20try%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20if(%24null%20-eq%20%24ActiveAssignments)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Write-Output%20%22No%20Active%20Role%20Assignments%20Found%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackEvent(%22No%20Active%20Role%20Assignments%20Found%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%20%20%20%20%20%20%20%20break%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20foreach(%24ActiveAssignment%20in%20%24ActiveAssignments)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24ActiveAssignment.RoleType%20-match%20%22Project%20Collection%20Administrators%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Remove-Access-From-Org%20-EmailAddress%20%24ActiveAssignment.RequesterEmailAddress%20-OrgName%20%24ActiveAssignment.OrganizationName%20-SessionID%20%24ActiveAssignment.SessionID%20-RoleType%20%24ActiveAssignment.RoleType%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20elseif((%24ActiveAssignment.RoleType%20-match%20%22Build%20Administrators%22)%20-or%20(%24ActiveAssignment.RoleType%20-match%20%22Endpoint%20Administrators%22)%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Remove-Access-From-Project%20-EmailAddress%20%24ActiveAssignment.RequesterEmailAddress%20-OrgName%20%24ActiveAssignment.OrganizationName%20-SessionID%20%24ActiveAssignment.SessionID%20-RoleType%20%24ActiveAssignment.RoleType%20-ProjectName%20%24ActiveAssignment.ProjectName%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20else%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Error%20%22Invaid%20RoleType%20%3A%20%24(%24ActiveAssignment.RoleType)%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackException(%22Invaid%20RoleType%20%3A%20%24(%24ActiveAssignment.RoleType)%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20catch%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%7D%0A%0A%0A%7D%0Afunction%20Remove-Access-From-Org%20%0A%7B%0A%20%20%20%20param%20(%0A%20%20%20%20%20%20%20%20%5Bstring%5D%24EmailAddress%2C%0A%20%20%20%20%20%20%20%20%5BString%5D%24OrgName%2C%0A%20%20%20%20%20%20%20%20%5BString%5D%24SessionID%2C%0A%20%20%20%20%20%20%20%20%5BString%5D%24RoleType%0A%20%20%20%20)%0A%0A%20%20%20%20try%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%24userDescriptor%3D%20Get-User-Descriptor%20-UserEmailAddress%20%24EmailAddress%0A%20%20%20%20%20%20%20%20do%0A%20%20%20%20%20%20%20%20%7B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20Set%20communication%20protol%20to%20TLS1.2%0A%20%20%20%20%20%20%20%20%20%20%20%20%5BNet.ServicePointManager%5D%3A%3ASecurityProtocol%20%3D%20%5BNet.SecurityProtocolType%5D%3A%3ATls12%0A%20%20%20%20%20%20%20%20%20%20%20%20%24grouplist%3D%20Invoke-webrequest%20-Method%20Get%20-Uri%20%22https%3A%2F%2Fvssps.dev.azure.com%2F%24(%24OrgName)%2F_apis%2Fgraph%2Fgroups%3Fapi-version%3D6.0-preview.1%26amp%3BcontinuationToken%3D%24(%24ContinuationToken)%22%20-Headers%20%40%7BAuthorization%20%3D%20%24credentials%20%7D%20-ContentType%20'application%2Fjson'%20-UseBasicParsing%0A%20%20%20%20%20%20%20%20%20%20%20%20%24ContinuationToken%20%3D%20%24grouplist.Headers.'x-ms-continuationtoken'%0A%20%20%20%20%20%20%20%20%20%20%20%20%24APIContents%20%3D%20%24grouplist.Content%20%7C%20ConvertFrom-Json%20%0A%20%20%20%20%20%20%20%20%20%20%20%20foreach(%24group%20in%20%24APIContents.value)%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(%22%5B%24OrgName%5D%5CProject%20Collection%20Administrators%22%20-eq%20%24group.principalName)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24groupdescriptor%20%3D%20%24group.descriptor%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24url%20%3D%20%22https%3A%2F%2Fvssps.dev.azure.com%2F%24(%24OrgName)%2F_apis%2Fgraph%2Fmemberships%2F%24(%24userDescriptor)%2F%24(%24groupdescriptor)%3Fapi-version%3D6.0-preview.1%22%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20Set%20communication%20protol%20to%20TLS1.2%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5BNet.ServicePointManager%5D%3A%3ASecurityProtocol%20%3D%20%5BNet.SecurityProtocolType%5D%3A%3ATls12%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Invoke-RestMethod%20-Method%20DELETE%20-Uri%20%24url%20-ContentType%20'application%2Fjson'%20-Headers%20%40%7BAuthorization%20%3D%20%24credentials%20%7D%20-ErrorAction%20Continue%20-UseBasicParsing%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Update_Roleassignment_database%20-Email%20%24EmailAddress%20-SessionID%20%24SessionID%20-RoleType%20%24RoleType%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackEvent(%22Added%20%24(%24UserEmailAddress)%20to%20%24(%24group.principalName)%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24ContinuationToken%3D%24null%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20catch%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20remove%20user%20%24(%24EmailAddress)%20from%20%20%20Project%20Collection%20Administrators%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%20while%20(%24null%20-ne%20%24ContinuationToken)%0A%0A%20%20%20%20%7D%0A%20%20%20%20catch%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20get%20group%20details%20from%20Org%20%3A%20%24(OrgName)%22%0A%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%0A%20%20%20%20%7D%0A%7D%20%0A%0Afunction%20Remove-Access-From-Project%0A%7B%0A%20%20%20%20param%20(%0A%20%20%20%20%20%20%20%20%5Bstring%5D%24EmailAddress%2C%0A%20%20%20%20%20%20%20%20%5BString%5D%24OrgName%2C%0A%20%20%20%20%20%20%20%20%5BString%5D%24ProjectName%2C%0A%20%20%20%20%20%20%20%20%5BString%5D%24SessionID%2C%0A%20%20%20%20%20%20%20%20%5BString%5D%24RoleType%0A%20%20%20%20)%0A%0A%20%20%20%20%24userDescriptor%20%3D%20%24userDescriptor%3D%20Get-User-Descriptor%20-UserEmailAddress%20%24EmailAddress%0A%20%20%20%20try%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%23%23%20Set%20communication%20protol%20to%20TLS1.2%0A%20%20%20%20%20%20%20%20%5BNet.ServicePointManager%5D%3A%3ASecurityProtocol%20%3D%20%5BNet.SecurityProtocolType%5D%3A%3ATls12%0A%20%20%20%20%20%20%20%20%24projectList%20%3D%20Invoke-RestMethod%20-Uri%20%22https%3A%2F%2Fdev.azure.com%2F%24(%24OrgName)%2F_apis%2Fprojects%3F%60%24top%3D999%26amp%3Bapi-version%3D6.0%22%20-Headers%20%40%7BAuthorization%20%3D%20%24credentials%20%7D%20-Method%20Get%20-ContentType%20'application%2Fjson'%20%20%0A%20%20%20%20%20%20%20%20foreach(%24project%20in%20%24projectList.value)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24ProjectName%20-eq%20%24project.name)%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20Set%20communication%20protol%20to%20TLS1.2%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5BNet.ServicePointManager%5D%3A%3ASecurityProtocol%20%3D%20%5BNet.SecurityProtocolType%5D%3A%3ATls12%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24projectDetails%20%3D%20Invoke-RestMethod%20-Uri%20%22https%3A%2F%2Fvssps.dev.azure.com%2F%24(%24OrgName)%2F_apis%2Fgraph%2Fdescriptors%2F%24(%24project.id)%3Fapi-version%3D5.0-preview.1%22%20-Headers%20%40%7BAuthorization%20%3D%20%24credentials%20%7D%20-Method%20Get%20-ContentType%20'application%2Fjson'%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24GroupsUrl%20%3D%20%22https%3A%2F%2Fvssps.dev.azure.com%2F%24(%24OrgName)%2F_apis%2Fgraph%2Fgroups%3FscopeDescriptor%3D%24(%24projectDetails.value)%26amp%3Bapi-version%3D6.0-preview.1%22%20%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20Set%20communication%20protol%20to%20TLS1.2%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5BNet.ServicePointManager%5D%3A%3ASecurityProtocol%20%3D%20%5BNet.SecurityProtocolType%5D%3A%3ATls12%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24grouplist%3D%20Invoke-RestMethod%20-Uri%20%24GroupsUrl%20-Headers%20%40%7BAuthorization%20%3D%20%24credentials%20%7D%20-Method%20Get%20-ContentType%20'application%2Fjson'%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20catch%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20get%20group%20details%20%20for%20project%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20foreach(%24group%20in%20%24grouplist.value)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if((%24RoleType%20-eq%20%24group.principalName)%20-or%20(%24RoleType%20-eq%20%24group.principalName))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24groupdescriptor%20%3D%20%24group.descriptor%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24url%20%3D%20%22https%3A%2F%2Fvssps.dev.azure.com%2F%24(%24OrgName)%2F_apis%2Fgraph%2Fmemberships%2F%24(%24userDescriptor)%2F%24(%24groupdescriptor)%3Fapi-version%3D6.0-preview.1%22%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20Set%20communication%20protol%20to%20TLS1.2%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5BNet.ServicePointManager%5D%3A%3ASecurityProtocol%20%3D%20%5BNet.SecurityProtocolType%5D%3A%3ATls12%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Invoke-RestMethod%20-Method%20DELETE%20-Uri%20%24url%20-ContentType%20'application%2Fjson'%20-Headers%20%40%7BAuthorization%20%3D%20%24credentials%20%7D%20-ErrorAction%20Continue%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackEvent(%22Removed%20%24(%24UserEmailAddress)%20from%20%20%24(%24group.principalName)%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%20%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20Updated%20status%20in%20DataBase%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Update_Roleassignment_database%20-Email%20%24EmailAddress%20-SessionID%20%24SessionID%20-RoleType%20%24RoleType%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20catch%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20Delete%20user%20%24(%24EmailAddress)%20from%20%20the%20project%20%3A%20%24(%24ProjectName)%20Group%20%3A%20%24(%24RoleType)%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20catch%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20get%20project%20details%20for%20organization%22%0A%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%7D%0A%7D%0A%0Afunction%20Update_Roleassignment_database%0A%7B%0A%20%20%20%20param%20(%0A%20%20%20%20%20%20%20%20%5Bstring%5D%24Email%2C%0A%20%20%20%20%20%20%20%20%5BString%5D%24SessionID%2C%0A%20%20%20%20%20%20%20%20%5BString%5D%24RoleType%0A%20%20%20%20)%0A%0A%20%20%20%20try%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%24query%20%3D%20%22UPDATE%20%20ADOAccessLogs%20SET%20IsActive%20%3D%200%20where%20SessionID%3D'%24(%24SessionID)'%20AND%20RoleType%3D'%24(%24RoleType)'%22%0A%20%20%20%20%20%20%20%20%24command%20%3D%20New-Object%20System.Data.SqlClient.SqlCommand%0A%20%20%20%20%20%20%20%20%24command.Connection%20%3D%20%24SQLConnectionString%0A%20%20%20%20%20%20%20%20%24command.CommandText%20%3D%20%24query%0A%20%20%20%20%20%20%20%20%24command.Connection.Open()%0A%20%20%20%20%20%20%20%20%24command.ExecuteReader()%0A%20%20%20%20%20%20%20%20%24command.Connection.Close()%0A%20%20%20%20%7D%0A%0A%20%20%20%20catch%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20Write-Error%20%22Failed%20to%20update%20active%20status%20for%20User%20%3A%20%24(%24Email)%20SessionID%20%3A%20%24(%24SessionID)%22%0A%20%20%20%20%20%20%20%20Write-Output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20%24TelClient.TrackException(%24_.Exception)%0A%20%20%20%20%20%20%20%20%24TelClient.Flush()%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%7D%0A%0A%7D%0A%24ActiveUsers%20%3D%20%24null%0A%24ActiveUsers%20%3D%20Get-ActiveAssignment-Database%20%7C%20Sort-Object%20ID%20-Unique%0A%24ActiveUsers%0ARemove-AccessFor-Users%20-ActiveAssignments%20%24ActiveUsers%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E10.%20Create%20a%20build%20pipeline%20using%20below%20YAML.%20This%20will%20require%20variable%20group%20to%20be%20linked%2C%20created%20as%20part%20of%20step%207%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-yaml%22%3E%3CCODE%3Eschedules%3A%0A-%20cron%3A%20%22*%2F10%20*%20*%20*%20*%22%0A%20%20displayName%3A%20Daily%20build%20for%20every%2030%20min%0A%20%20branches%3A%0A%20%20%20%20include%3A%0A%20%20%20%20-%20master%0A%20%20always%3A%20true%0A%0A%0Apool%3A%0A%20%20Image%3A%20'windows-2019'%0A%0A%0Asteps%3A%0A-%20task%3A%20PowerShell%402%0A%20%20displayName%3A%20'PowerShell%20Script'%0A%20%20inputs%3A%0A%20%20%20%20filePath%3A%20'.%2FremoveUser.ps1'%0A%20%20%20%20arguments%3A%20'-LoggingTelemetryID%20%24(applicationInsightKey)%20-PAT%20%24(serviceAccountPAT)%20-SQLPassword%20%24(SqlAdminPassword)%20-SQLUserID%20%24(SqlAdminUserName)%20-SQLDataBase%20%24(SqlDatabaseName)%20-SQLServer%20%24(SqlServerName)%20-UserDescriptorOrganization%20%24(UserDescriptorOrganization)'%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-TEASER%20id%3D%22lingo-teaser-3062589%22%20slang%3D%22en-US%22%3E%3CP%3EAre%20you%20using%20service%20account%20to%20access%20Azure%20DevOps%3F%20Is%20that%20service%20account%20password%20available%20with%20multiple%20users%20within%20team%3F%20Are%20you%20tracking%20activity%20performed%20by%20individual%20user%20using%20service%20account%3F%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EThis%20possess%20security%20risk%20and%20breach%20of%20password.%20Just%20in%20time%20could%20be%20a%20possible%20solution%20to%20above%20problem%20statements.%20Follow%20below%20for%20more%20details.%3C%2FP%3E%3C%2FLINGO-TEASER%3E
Version history
Last update:
‎Jan 17 2022 05:14 AM
Updated by: