Trigger-PolicyEvaluation.ps1

<#PSScriptInfo
 
.VERSION 1.0
 
.GUID efd1a650-e9e6-4cd3-beca-cc0e940cc672
 
.AUTHOR jbritt@microsoft.com
 
.COMPANYNAME Microsoft
 
.COPYRIGHT Microsoft
 
.TAGS
 
.LICENSEURI
 
.PROJECTURI
https://github.com/JimGBritt/AzurePolicy/tree/master/AzureMonitor/Scripts
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
May 01, 2019
    Initial
#>


<#
.SYNOPSIS
  Use this script to trigger the Azure Policy Evaluation API
      
.DESCRIPTION
  This script takes a SubscriptionID and optionally a ResourceGroup as parameters, allows you to also specify an interval
  for how many seconds you want to delay before checking status of the policy evaluation (default is 20 seconds)
 
  Based on the API documented here: https://docs.microsoft.com/en-us/azure/governance/policy/how-to/get-compliance-data#evaluation-triggers
 
.PARAMETER SubscriptionId
    The subscriptionID of the Azure Subscription that contains the policies to evaluate
 
.PARAMETER ResourceGroupName
    If desired, use a resourcegroup in addition to SubscriptionID to narrow in on a scope of ResourceGroup to evaluate policy compliance
 
.PARAMETER Interval
    Specify an interval in seconds (default is 20) to check for status of trigger - loops until complete.
 
.EXAMPLE
  .\Trigger-PolicyEvaluation.ps1 -SubscriptionId "fd2323a9-2324-4d2a-90f6-7e6c2fe03512" -ResourceGroup "RGName" interval 25
  Trigger evaluation against the scope of a Resource Group, with a specified subscriptionID with an interval of 25 seconds
 
.EXAMPLE
  .\Trigger-PolicyEvaluation.ps1 -SubscriptionId "fd2323a9-2324-4d2a-90f6-7e6c2fe03512"
  Trigger evaluation against the scope of a subscriptionID
 
.EXAMPLE
  .\Trigger-PolicyEvaluation.ps1
  Prompt for a subscriptionId from a menu listing of all available subscriptions within the context of the logged in user.
  Trigger evaluation against the scope of a subscriptionID selected.
 
.NOTES
   AUTHOR: Jim Britt Senior Program Manager - Azure CAT
   LASTEDIT: May 01, 2019
 
May 01, 2019
   Initial
 
.LINK
    This script posted to and discussed at the following locations:
    https://github.com/JimGBritt/AzurePolicy/tree/master/AzureMonitor/Scripts
#>


param
(
    # Provide SubscriptionID to bypass subscription listing
    [Parameter(Mandatory = $False)]
    [guid]$SubscriptionId,

    # Add a ResourceGroup name to reduce scope from entire Azure Subscription to RG
    [Parameter(Mandatory = $False)]
    [string]$ResourceGroupName,

    # An interval in seconds to check that trigger was successful
    [Parameter(Mandatory = $False)]
    [int]$interval = 20

)
# Function used to build numbers in selection tables for menus
function Add-IndexNumberToArray (
    [Parameter(Mandatory=$True)]
    [array]$array
    )
{
    for($i=0; $i -lt $array.Count; $i++) 
    { 
        Add-Member -InputObject $array[$i] -Name "#" -Value ($i+1) -MemberType NoteProperty 
    }
    $array
}
function BuildBody
(
    [parameter(mandatory=$True)]
    [string]$method
)
{
    $BuildBody = @{
    Headers = @{
        Authorization = "Bearer $($token.AccessToken)"
        'Content-Type' = 'application/json'
    }
    Method = $Method
    UseBasicParsing = $true
    }
    $BuildBody
}  
# Login to Azure - if already logged in, use existing credentials.
Write-Host "Authenticating to Azure..." -ForegroundColor Cyan
try
{
    $AzureLogin = Get-AzSubscription
    $currentContext = Get-AzContext
    $token = $currentContext.TokenCache.ReadItems() | Where-Object {$_.tenantid -eq $currentContext.Tenant.Id} 
    if($Token.ExpiresOn -lt $(get-date))
    {
        "Logging you out due to cached token is expired for REST AUTH. Re-run script"
        $null = Disconnect-AzAccount        
    } 
}
catch
{
    $null = Login-AzAccount
    $AzureLogin = Get-AzSubscription
    $currentContext = Get-AzContext
    $token = $currentContext.TokenCache.ReadItems() | Where-Object {$_.tenantid -eq $currentContext.Tenant.Id} 

}

If($AzureLogin -and !($SubscriptionID))
{
    [array]$SubscriptionArray = Add-IndexNumberToArray (Get-AzSubscription) 
    [int]$SelectedSub = 0

    # use the current subscription if there is only one subscription available
    if ($SubscriptionArray.Count -eq 1) 
    {
        $SelectedSub = 1
    }
    # Get SubscriptionID if one isn't provided
    while($SelectedSub -gt $SubscriptionArray.Count -or $SelectedSub -lt 1)
    {
        Write-host "Please select a subscription from the list below"
        $SubscriptionArray | Select-Object "#", Id, Name | Format-Table
        try
        {
            $SelectedSub = Read-Host "Please enter a selection from 1 to $($SubscriptionArray.count)"
        }
        catch
        {
            Write-Warning -Message 'Invalid option, please try again.'
        }
    }
    if($($SubscriptionArray[$SelectedSub - 1].Name))
    {
        $SubscriptionName = $($SubscriptionArray[$SelectedSub - 1].Name)
    }
    elseif($($SubscriptionArray[$SelectedSub - 1].SubscriptionName))
    {
        $SubscriptionName = $($SubscriptionArray[$SelectedSub - 1].SubscriptionName)
    }
    write-verbose "You Selected Azure Subscription: $SubscriptionName"
    
    if($($SubscriptionArray[$SelectedSub - 1].SubscriptionID))
    {
        [guid]$SubscriptionID = $($SubscriptionArray[$SelectedSub - 1].SubscriptionID)
    }
    if($($SubscriptionArray[$SelectedSub - 1].ID))
    {
        [guid]$SubscriptionID = $($SubscriptionArray[$SelectedSub - 1].ID)
    }
}
Write-Host "Selecting Azure Subscription: $($SubscriptionID.Guid) ..." -ForegroundColor Cyan
$Null = Select-AzSubscription -SubscriptionId $SubscriptionID.Guid

$PostBody = BuildBody -method "POST"
#Establish URI to gather resources
$Subscription = $(Get-AzContext).Subscription.id 

If($SubscriptionId -and !($ResourceGroupName))
{
    write-host "No Resourcegroup provided as a parameter ... triggering against subscription: $SubscriptionId" -ForegroundColor Yellow
    $RESOURCEID = "/subscriptions/$Subscription"
}
elseif ($ResourceGroupName)
{
    write-host "ResourceGroup provided ... triggering against resource group name:$ResourceGroupName" -ForegroundColor Yellow
    $RESOURCEID = "/subscriptions/$Subscription/$ResourceGroup"

}
$PostURI = "https://management.azure.com/$RESOURCEID/providers/Microsoft.PolicyInsights/policyStates/latest/triggerEvaluation?api-version=2018-07-01-preview"

try
{
    $PostRAW = $(Invoke-WebRequest -uri $PostURI @PostBody).Rawcontent
    Write-Host "Submitted Policy Evaluation Trigger Request" -foregroundcolor Yellow
}
catch 
{
    "Error"
    exit
}

$PostArray = $PostRaw.Split("`n")
[string]$LocationVar = $($PostArray|Select-String -SimpleMatch "Location")
$GetURI = $($LocationVar.Split(" ",2))[1]
$GetBody = BuildBody -method "GET"

$GetResults = Invoke-WebRequest -uri $GetURI @GetBody
while($GetResults.StatusCode -ne 200)
{
   $GetResults = Invoke-WebRequest -uri $GetURI @GetBody
   Write-Host "Status code $($GetResults.Statuscode) returned on query. Still in progress...waiting $interval seconds to requery" 
   start-sleep $interval
}

Write-Host "Successfully Triggered a Policy Evaluation Request" -foregroundcolor Cyan