AzAiUtil.psm1
|
# CreateReleaseAnnotation is a powershell module originally derived from # https://github.com/Microsoft/ApplicationInsights-Home/blob/master/API/CreateReleaseAnnotation.ps1 function CreateReleaseAnnotation ( [parameter(Mandatory = $true)][string]$applicationId, [parameter(Mandatory = $true)][string]$apiKey, [parameter(Mandatory = $true)][string]$releaseName, [parameter(Mandatory = $false)]$releaseProperties, [parameter(Mandatory = $false)][DateTime]$eventDateTime ) { # Need powershell version 3 or greater for script to run $minimumPowershellMajorVersion = 3 if ($PSVersionTable.PSVersion.Major -lt $minimumPowershellMajorVersion) { Write-Host "Need powershell version $minimumPowershellMajorVersion or greater to create release annotation" return } $id = [GUID]::NewGuid() $bodyJson = CreateBodyAsJson($id, $releaseName, $eventDateTime, $releaseProperties) $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" $headers.Add("X-AIAPIKEY", $apiKey) set-variable -Name createAnnotationResult1 -Force -Scope Local -Value $null set-variable -Name createAnnotationResultDescription -Force -Scope Local -Value "" # get redirect link from fwlink $requestUrl = GetRequestUrlFromFwLink("http://go.microsoft.com/fwlink/?prd=11901&pver=1.0&sbp=Application%20Insights&plcid=0x409&clcid=0x409&ar=Annotations&sar=Create%20Annotation") if ($requestUrl -eq $null) { $output = "Failed to find the redirect link to create a release annotation" throw $output } $createAnnotationResult1, $createAnnotationResultDescription = InvokeCreateAnnotationRequest($requestUrl, $bodyJson, $headers) if ($createAnnotationResult1) { $output = "Failed to create an annotation with Id: {0}. Error {1}, Description: {2}." -f $id, $createAnnotationResult1, $createAnnotationResultDescription throw $output } $str = "Release annotation created. Id: {0}." -f $id Write-Host $str } # background info on how fwlink works: After you submit a web request, many sites redirect through a series of intermediate pages before you finally land on the destination page. # So when calling Invoke-WebRequest, the result it returns comes from the final page in any redirect sequence. Hence, I set MaximumRedirection to 0, as this prevents the call to # be redirected. By doing this, we get a resposne with status code 302, which indicates that there is a redirection link from the response body. We grab this redirection link and # construct the url to make a release annotation. # Here's how this logic is going to works # 1. Client send http request, such as: http://go.microsoft.com/fwlink/?LinkId=625115 # 2. FWLink get the request and find out the destination URL for it, such as: http://www.bing.com # 3. FWLink generate a new http response with status code “302” and with destination URL “http://www.bing.com”. Send it back to Client. # 4. Client, such as a powershell script, knows that status code “302” means redirection to new a location, and the target location is “http://www.bing.com” function GetRequestUrlFromFwLink($fwLink) { $request = Invoke-WebRequest -Uri $fwLink -MaximumRedirection 0 -UseBasicParsing -ErrorAction Ignore if ($request.StatusCode -eq "302") { return $request.Headers.Location } return $null } function InvokeCreateAnnotationRequest($url, $bodyJson, $headers) { $retries = 1 $success = $false while (!$success -and $retries -lt 6) { $location = "$url/applications/$applicationId/Annotations?api-version=2015-11" Write-Host "Invoke a web request for $location to create a new release annotation. Attempting $retries" set-variable -Name createResultStatus -Force -Scope Local -Value $null set-variable -Name createResultStatusDescription -Force -Scope Local -Value $null set-variable -Name result -Force -Scope Local try { $result = Invoke-WebRequest -Uri $location -Method Put -Body $bodyJson -Headers $headers -ContentType "application/json; charset=utf-8" -UseBasicParsing } catch { if ($_.Exception){ if($_.Exception.Response) { $createResultStatus = $_.Exception.Response.StatusCode.value__ $createResultStatusDescription = $_.Exception.Response.StatusDescription } else { $createResultStatus = "Exception" $createResultStatusDescription = $_.Exception.Message } } } if ($result -eq $null) { if ($createResultStatus -eq $null) { $createResultStatus = "Unknown" } if ($createResultStatusDescription -eq $null) { $createResultStatusDescription = "Unknown" } } else { $success = $true } if ($createResultStatus -eq 409 -or $createResultStatus -eq 404 -or $createResultStatus -eq 401) # no retry when conflict or unauthorized or not found { break } $retries = $retries + 1 sleep 1 } $createResultStatus $createResultStatusDescription return } function CreateBodyAsJson($id, $releaseName, $eventDateTime, $releaseProperties) { $currentTime = (Get-Date).ToUniversalTime() $requestBody = @{} $requestBody.Id = $id $requestBody.AnnotationName = $releaseName if ($eventDateTime -eq $null) { $requestBody.EventTime = $currentTime.GetDateTimeFormats("s")[0] # GetDateTimeFormats returns an array } else { # input must be between NOW and 90 days back maximum $maxDaysBack = $currentTime.AddDays(-90) if ($eventDateTime -lt $maxDaysBack -Or $eventDateTime -gt $currentTime) { $output = "-eventDateTime value must be between NOW and 90 days back maximum" throw $output } $requestBody.EventTime = $eventDateTime.GetDateTimeFormats("s")[0] } $requestBody.Category = "Deployment" if ($releaseProperties -eq $null) { $properties = @{} } else { $properties = $releaseProperties } $properties.Add("ReleaseName", $releaseName) $requestBody.Properties = ConvertTo-Json($properties) -Compress $bodyJson = [System.Text.Encoding]::UTF8.GetBytes(($requestBody | ConvertTo-Json)) return $bodyJson } |