使用Powershell查询Azure AD以查找哪些用户可以访问Azure中的不同资源

时间:2019-07-12 11:10:39

标签: azure powershell azure-active-directory azure-functions azure-powershell

概述

我想要一种查询Azure AD的方法,并返回分配给Azure中不同资源组的Azure AD组的列表。

当前解决方案

当前,我有一个Powershell脚本作为服务原理运行,并通过Azure进行身份验证,然后它将获得当前的订阅。基于此搜索已登录的用户,并返回分配给该用户的所有安全组。然后根据AD组分配给的所有资源组进行检查,这将返回登录用户可以访问的资源组中VM的列表。

这确实有效,但是运行大约需要10分钟。每个订阅我们有100个资源组,而且速度很慢。

我粘贴了以下代码,并删除了所有私人信息。

问题

  • 了解一种使脚本运行更快的方法-最多30秒。
  • 是否有更有效的方法来运行专门为此目的设计的脚本或命令。

我正在使用Az Powershell 2.4.0库创建代码。

function userLogin($azureAplicationId, $azureAppPassword) 
{
    $azureTenantId= ""
    $azurePassword = ConvertTo-SecureString $azureAppPassword -AsPlainText -Force
    $psCred = New-Object System.Management.Automation.PSCredential($azureAplicationId , $azurePassword)
    Connect-AzAccount -Credential $psCred -TenantId $azureTenantId  -ServicePrincipal 
}

function userRGAccessCheck($RG)
{
    $resoruceGroupChoice = Read-Host -Prompt "Enter Resource Group Name "
}

function userRTAccessCheck($RName)
{
    $resoruceNameChoice = Read-Host -Prompt "Enter VM Name "
}


$subAccess = Read-Host -Prompt "Enter Subscription, Press (1) OR (2): `n(1) Microsoft Azure Enterprise Non-Production `n(2) Microsoft Azure Enterprise Production`n"

if ($subAccess -eq 1)
{

    $azureAplicationId =""
    $azureAppPassword = ""
    userLogin -azureAplicationId $azureAplicationId -azureAppPassword $azureAppPassword
    #userRGAccessCheck -RG $reresoruceGroupChoice

} elseif ($subAccess -eq 2)
{

    $azureAplicationId =""
    $azureAppPassword = ""
    userLogin -azureAplicationId $azureAplicationId -azureAppPassword $azureAppPassword
    #userRGAccessCheck -RG $reresoruceGroupChoice
    #userRTAccessCheck -RName $resoruceNameChoice 

} else
{
    Write-Host "Please Enter 1 OR 2"
}


# Arrays for app
$groupArray = @()
$ADAccessGroupArray = @()
$resourceGroupArray = @()


$userObjectID = "USER_OBJECT_ID"

# Get AD User Groups and list of resource groups
$groupArray += (Get-AzADGroup -SearchString 'SS_*' | Select-Object -ExpandProperty Id)


foreach($group in $groupArray)
{
    if(Get-AzADGroupMember -GroupObjectId $group | Where-Object {$_.Id -eq $userObjectID})
    {
        $ADAccessGroupArray += $group  
        Write-Host "User has access to group: " $group
    } else
    {
        Write-Host "User does not have access to group: " $group
    }
}


# Get a list of resource groups
$resourceGroupArray += Get-AzResourceGroup | Select-Object -ExpandProperty ResourceGroupName


# Check if the AD group has been assigned to the resource group
foreach ($resourceGroupName in $resourceGroupArray)
{

    foreach ($ADAccessGroup in $ADAccessGroupArray)
    {
      if(Get-AzRoleAssignment -ResourceGroupName $resourceGroupName | Where-Object {$_.ObjectId -eq $ADAccessGroup})
        {
           Write-Host "User has access to group: " $resourceGroupName

        }
    }
}

$groupArray = $null
$ADAccessGroupArray = $null
$resourceGroupArray = $null

预先感谢

1 个答案:

答案 0 :(得分:1)

我进行了一些修改,应该会有所帮助。

function userLogin($azureAplicationId, $azureAppPassword) 
{
    $azureTenantId= ""
    $azurePassword = ConvertTo-SecureString $azureAppPassword -AsPlainText -Force
    $psCred = New-Object System.Management.Automation.PSCredential($azureAplicationId , $azurePassword)
    Connect-AzAccount -Credential $psCred -TenantId $azureTenantId  -ServicePrincipal 
}

function userRGAccessCheck($RG)
{
    $resoruceGroupChoice = Read-Host -Prompt "Enter Resource Group Name "
}

function userRTAccessCheck($RName)
{
    $resoruceNameChoice = Read-Host -Prompt "Enter VM Name "
}


$subAccess = Read-Host -Prompt "Enter Subscription, Press (1) OR (2): `n(1) Microsoft Azure Enterprise Non-Production `n(2) Microsoft Azure Enterprise Production`n"

if ($subAccess -eq 1)
{

    $azureAplicationId =""
    $azureAppPassword = ""
    userLogin -azureAplicationId $azureAplicationId -azureAppPassword $azureAppPassword
    #userRGAccessCheck -RG $reresoruceGroupChoice

} elseif ($subAccess -eq 2)
{

    $azureAplicationId =""
    $azureAppPassword = ""
    userLogin -azureAplicationId $azureAplicationId -azureAppPassword $azureAppPassword
    #userRGAccessCheck -RG $reresoruceGroupChoice
    #userRTAccessCheck -RName $resoruceNameChoice 

} else
{
    Write-Host "Please Enter 1 OR 2"
}


# Arrays for app
$groupArray = @()
$ADAccessGroupArray = @() -as [System.Collections.Arraylist] # Using Arraylist type
$resourceGroupArray = @()


$userObjectID = "USER_OBJECT_ID"

# Get AD User Groups and list of resource groups
$groupArray = (Get-AzADGroup -SearchString 'SS_*' | Select-Object -ExpandProperty Id) # Removed += because it is unnecessary


foreach($group in $groupArray)
{
    if((Get-AzADGroupMember -GroupObjectId $group).where({$_.Id -eq $userObjectID},'First')) # Used where method
    {
        $null = $ADAccessGroupArray.Add($group)  # Add group to arraylist and suppress output. Removed += because it is a slow operation here.
        Write-Host "User has access to group: " $group
    } else
    {
        Write-Host "User does not have access to group: " $group
    }
}


# Get a list of resource groups
$resourceGroupArray = Get-AzResourceGroup | Select-Object -ExpandProperty ResourceGroupName # Removed += because it is unnecessary


# Check if the AD group has been assigned to the resource group
foreach ($resourceGroupName in $resourceGroupArray)
{

      if((Get-AzRoleAssignment -ResourceGroupName $resourceGroupName).where({$_.ObjectId -in $ADAccessGroupArray},'First')) # used where method
        {
           Write-Host "User has access to group: " $resourceGroupName

        }
}

$groupArray = $null
$ADAccessGroupArray = $null
$resourceGroupArray = $null

我在更改的行中添加了注释。以下是更改的摘要:

  1. 我将$ADAccessGroupArray设置为arraylist类型。这样我们就可以访问固有的Add()方法来对其进行更新。如果我们使用不可变的数组,则必须创建一个新数组以添加更多条目。更新数组的一种方法是使用+=,随着数组大小的增加,这是一种非常低效的操作。
    • 通常,+=并不是最有效的方法。有时这是可以忽略的操作,但是除非您知道它可以忽略,否则我会避免这样做。
    • 我从其他数组分配中删除了+=,因为当您将变量设置为返回数组的命令输出时,它们不是必需的。结果将是不包含+=的数组。在某些情况下,您的命令返回一个值,然后您的变量可能不会成为数组。可以使用,一元运算符或提前声明数组来解决此问题。
  2. 我用Where-Object方法代替了where()where-object(和where())不仅在完成任何操作之前都等待LHS操作完成,而且还会在返回结果之前先对所有流水线项目进行枚举。使用where()方法,我们可以访问模式。在您的两种情况下,我都使用'First'模式,以便where()一旦找到第一个条件匹配项就将停止处理。如果您有1000个对象的列表,并且匹配项在该列表的上半部之内,这将非常有用。
  3. 我删除了foreach $resourceGroupArray循环内的嵌套foreach循环。这可以通过更新下一个where()条件以使用-in运算符来实现。 -in使您可以在一个集合中找到一个项目,这就是您为每个组所做的工作。因此,我们将Get-AzRoleAssignment的呼叫次数从ResourceGroups x Groups减少到ResourceGroups。这里应该可以节省大量时间。