Skip to content

Instantly share code, notes, and snippets.

@JPRuskin
Last active July 21, 2021 09:56
Show Gist options
  • Select an option

  • Save JPRuskin/7585519c090823026580f9df0731a1e8 to your computer and use it in GitHub Desktop.

Select an option

Save JPRuskin/7585519c090823026580f9df0731a1e8 to your computer and use it in GitHub Desktop.
function Get-DeploymentTiming {
param(
[Parameter(Mandatory)]
[string]$ResourceGroupName,
[string]$DeploymentName
)
begin {
$Context = Get-AzContext
if (-not $script:Token -or $Token.ExpiresOn.LocalDateTime -lt [DateTime]::Now) {
$script:Token = Get-AzAccessToken
}
}
process {
$Headers = @{
Headers = @{
Authorization = "Bearer $($Token.Token)"
}
}
$UriBase = -join @(
"https://management.azure.com/subscriptions/"
$Context.Subscription.Id
"/resourcegroups/"
$ResourceGroupName
"/deployments/"
$DeploymentName
"/operations/"
"{{OperationId}}"
"?api-version=2021-04-01"
)
foreach ($Operation in Get-AzResourceGroupDeploymentOperation -ResourceGroupName $ResourceGroupName -DeploymentName $DeploymentName) {
$Operation = (Invoke-RestMethod @Headers -Uri ($UriBase -replace '{{OperationId}}', $Operation.OperationId)).Properties
[PSCustomObject]@{
ResourceGroupName = $ResourceGroupName
type = $Operation.TargetResource.resourceType
name = $Operation.TargetResource.resourceName
provisioningOperation = $Operation.provisioningOperation
provisioningState = $Operation.provisioningState
timestamp = $Operation.timestamp
Duration = [Xml.XmlConvert]::ToTimeSpan($Operation.duration)
statusCode = $Operation.statusCode
}
}
}
}
function Get-KeyVaultUpdates {
param(
[Parameter(Mandatory)]
[string]$ResourceGroupName,
[string]$VaultName = (Get-AzKeyVault -ResourceGroupName $ResourceGroupName).VaultName
)
begin {
$CurrentUserUpn = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile.DefaultContext.Account.Id
if (($UserPermission = (Get-AzKeyVault -VaultName $VaultName).AccessPolicies.Where{
$_.DisplayName -like "*$($CurrentUserUpn)*" -and $_.PermissionsToSecrets -notcontains 'get'
}) -or -not $UserPermission) {
Write-Verbose "Required permissions missing on KeyVault '$($VaultName)' - adding 'get' permission for user '$($CurrentUserUpn)'."
$RequiredPermissions = @('Get') + @($UserPermission.PermissionsToSecrets)
try {
Set-AzKeyVaultAccessPolicy -VaultName $VaultName -UserPrincipalName $CurrentUserUpn -PermissionsToSecrets $RequiredPermissions.Where{$_} -ErrorAction Stop
} catch {
Write-Error -Message "You don't have access to this KeyVault`n$_" -ErrorAction Stop
}
}
}
process {
foreach ($Type in @('vm','nexus','ccm','jenkins')) {
if ($Secret = Get-AzKeyVaultSecret -VaultName $VaultName -Name "$($Type)Password") {
[PSCustomObject]@{
ResourceGroupName = $ResourceGroupName
type = "Microsoft.KeyVault/vaults/secrets"
name = $Secret.Name
provisioningOperation = "Create"
provisioningState = "Succeeded"
timestamp = $Secret.Updated
Duration = [Xml.XmlConvert]::ToTimeSpan("PT1S")
statusCode = "OK"
}
}
}
}
}
function New-TimeChart {
[CmdletBinding(DefaultParameterSetName="Objects")]
param(
[Parameter(Mandatory, ParameterSetName = "Group")]
[string]$ResourceGroupName = $Event[0].ResourceGroup,
[Parameter(Mandatory, ValueFromPipeline, ParameterSetName = "Objects")]
[PSObject[]]$Event = @(
Get-DeploymentTiming -ResourceGroupName $ResourceGroupName -DeploymentName TestingDeployment
Get-KeyVaultUpdates -ResourceGroupName $ResourceGroupName
),
[string]$OutFile = (Join-Path $env:Temp "Deployment-$($Event[0].Timestamp).png")
)
begin {
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms.DataVisualization
$Chart = [System.Windows.Forms.DataVisualization.Charting.Chart]::new()
$Chart.Width = 2560
$Chart.Height = 1440
$Chart.ChartAreas.Add([System.Windows.Forms.DataVisualization.Charting.ChartArea]::new())
$Chart.Series.Add([System.Windows.Forms.DataVisualization.Charting.Series]::new('StartSeries'))
$Chart.Series['StartSeries'].ChartType = "StackedBar"
$Chart.Series['StartSeries'].Color = "White"
$Chart.Series.Add([System.Windows.Forms.DataVisualization.Charting.Series]::new('ProjectDuration'))
$Chart.Series['ProjectDuration'].ChartType = "StackedBar"
$Chart.Series['ProjectDuration'].Color = "Green"
$Chart.Series['ProjectDuration'].BorderColor = "Black"
$Chart.Series['ProjectDuration'].BorderWidth = 2
$Chart.ChartAreas[0].AxisY.Minimum = 100000
$Chart.ChartAreas[0].AxisY.Maximum = 0
$Chart.ChartAreas[0].AxisX.MajorGrid.Enabled = $false
$Chart.ChartAreas[0].AxisX.Interval = 1
$Chart.ChartAreas[0].AxisY.MajorGrid.Enabled = $false
$Chart.ChartAreas[0].AxisY.LabelStyle.Format = "HH:mm"
$Chart.ChartAreas[0].AxisY.IntervalType = "Minutes"
$Chart.ChartAreas[0].AxisY.Interval = 1
$null = $Chart.Titles.Add("Deployment - $ResourceGroupName")
}
process {
foreach ($Timing in $Event.Where{$_.Name} | Sort-Object {$_.TimeStamp - $_.Duration}) {
$EventStart = $Timing.Timestamp - $Timing.Duration
if ($EventStart.AddMinutes(-1).ToOaDate() -lt $Chart.ChartAreas[0].AxisY.Minimum) {
Write-Verbose "Setting Minimum to $($EventStart.ToOaDate())"
$Chart.ChartAreas[0].AxisY.Minimum = $EventStart.AddMinutes(-1).ToOaDate()
}
if ($Timing.Timestamp.ToOaDate() -gt $Chart.ChartAreas[0].AxisY.Maximum) {
Write-Verbose "Setting Maximum to $($Timing.Timestamp.ToOaDate())"
$Chart.ChartAreas[0].AxisY.Maximum = $Timing.Timestamp.ToOaDate()
}
$null = $Chart.Series["StartSeries"].Points.AddXY($Timing.Name, $EventStart)
$null = $Chart.Series["ProjectDuration"].Points.AddXY($Timing.Name, $Timing.Duration.TotalDays)
}
}
end {
$Chart.DataBind()
$Chart.SaveImage($OutFile, 'png')
if (-not $PSBoundParameters.ContainsKey("OutFile")) {
Get-Item $OutFile
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment