Wednesday, November 8, 2017

Adding the azure automation DSC using powershell

Sample DSC configuration

Configuration hybrid {
    param(

[Parameter(Mandatory=$true)]
[string] $CommonModuleVersion,

[Parameter(Mandatory=$true)]
[string] $ConfigKeyVaultName,

[Parameter(Mandatory=$true)]
[string] $SendGridAutomationAccountName,

[Parameter(Mandatory=$true)]
[string] $SendGridAutomationAccountRG
    )

Import-DscResource –ModuleName 'PSDesiredStateConfiguration'

    Node localhost {
Script ARMModule {
SetScript = {
Set-PSRepository -InstallationPolicy Trusted -Name PSGallery
Get-InstalledModule AzureRM* | Uninstall-Module -AllVersions -Force
Install-Module AzureRM -Force
}
TestScript = {
Set-PSRepository -InstallationPolicy Trusted -Name PSGallery
$currentModules = Get-Module AzureRM -ListAvailable | Sort-Object Version -Descending
if (!$currentModules) { return $false }

$currentModule = $currentModules[0]
$repoModule = Find-Module AzureRM
if ($repoModule.Version -ne $currentModule.Version) { return $false }

$missingModules = Find-Module AzureRM -IncludeDependencies | % { if ((Get-Module $_.Name -ListAvailable).Version -notcontains $_.Version) { $_.Name} }
!$missingModules
}
GetScript = {
@{ Version = (Get-Module AzureRM -ListAvailable | Sort-Object Version -Descending)[0].Version }
}         
}

Environment ConfigKeyVaultVariable
{
Ensure = "Present"
Name = "ConfigKeyVault"
Value = $ConfigKeyVaultName
}

Environment SendGridAutomationAccountNameVariable
{
Ensure = "Present"
Name = "SendGridAutomationAccountName"
Value = $SendGridAutomationAccountName
}

Environment SendGridAutomationAccountRGVariable
{
Ensure = "Present"
Name = "SendGridAutomationAccountRG"
Value = $SendGridAutomationAccountRG
}


Environment CommonModuleVersionEnvironmentVariable
{
Ensure = "Present"
Name = "CommonModuleVersion"
Value = $CommonModuleVersion

}



Script CommonModule {
SetScript = {
$tempFile = [System.IO.Path]::GetTempFileName() + ".zip"
Invoke-WebRequest -Uri $env:CommonModuleUri -OutFile $tempFile
Expand-Archive -LiteralPath $tempFile -DestinationPath "$($env:ProgramFiles)\WindowsPowerShell\Modules\Common\" -Force
Remove-Item $tempFile
}
TestScript = {
$module = Get-Module Common -ListAvailable
if (!$module) { return $false };
$module.Version.ToString() -eq [Environment]::GetEnvironmentVariable("CommonModuleVersion","Machine")
}
GetScript = {
@{ Version = (Get-Module Common -ListAvailable).Version }
}
DependsOn = "[Environment]CommonModuleVersionEnvironmentVariable"
}

}
}


Use the Import-AzureRmAutomationDscConfiguration and Start-AzureRmAutomationDscCompilationJob command to import the compile the above configuration

Install hybrid worker group using powershell


Param (

[String] $WorkspaceId,
[String] $WorkspaceKey,
[String] $HybridRunbookWorkerGroupName,
[String] $AutomationAccountEndPointURL,
[String] $AutomationAccountToken

)




# Referencing existing OMS Workspace and Automation Account

# Check for the MMA on the machine
try {

    $mma = New-Object -ComObject 'AgentConfigManager.MgmtSvcCfg'
 
    Write-Output "Configuring the MMA..."
    $mma.AddCloudWorkspace($WorkspaceID, $WorkspaceKey)
    $mma.ReloadConfiguration()

} catch {
    # Download the Microsoft monitoring agent
    Write-Output "Downloading and installing the Microsoft Monitoring Agent..."

    $Source = "http://download.microsoft.com/download/4/C/0/4C0C3A9A-E732-44B6-8955-6BD57B4866AA/MMASetup-AMD64.exe"

    $Destination = "$env:temp\MMASetup.exe"

    $null = Invoke-WebRequest -uri $Source -OutFile $Destination
    $null = Unblock-File $Destination

    # Change directory to location of the downloaded MMA
    cd $env:temp

    # Install the MMA
    $Command = "/C:setup.exe /qn ADD_OPINSIGHTS_WORKSPACE=1 OPINSIGHTS_WORKSPACE_ID=$WorkspaceID" + " OPINSIGHTS_WORKSPACE_KEY=$WorkspaceKey " + " AcceptEndUserLicenseAgreement=1"
    .\MMASetup.exe $Command

}

# Sleep until the MMA object has been registered
Write-Output "Waiting for agent registration to complete..."

# Timeout = 180 seconds = 3 minutes
$i = 18

do {
 
    # Check for the MMA folders
    try {
        # Change the directory to the location of the hybrid registration module
        cd "$env:ProgramFiles\Microsoft Monitoring Agent\Agent\AzureAutomation"
        $version = (ls | Sort-Object LastWriteTime -Descending | Select -First 1).Name
        cd "$version\HybridRegistration"

        $HybridRegistrationPath = "$env:ProgramFiles\Microsoft Monitoring Agent\Agent\AzureAutomation\$version\HybridRegistration"

        # Import the module
        Import-Module $HybridRegistrationPath\HybridRegistration.psd1

        # Mark the flag as true
        $hybrid = $true
    } catch{

        $hybrid = $false

    }
    # Sleep for 10 seconds
    Start-Sleep -s 10
    $i--

} until ($hybrid -or ($i -le 0))

if ($i -le 0) {
    Write-output "The HybridRegistration module was not found. Please ensure the Microsoft Monitoring Agent was correctly installed."
}

# Register the hybrid runbook worker
Write-Output "Registering the hybrid runbook worker..."
Add-HybridRunbookWorker -Name $HybridRunbookWorkerGroupName -EndPoint $AutomationAccountEndPointURL -Token $AutomationAccountToken


    #Web Platform Installer URL
    $WPISource = "https://download.microsoft.com/download/C/F/F/CFF3A0B8-99D4-41A2-AE1A-496C08BEB904/WebPlatformInstaller_amd64_en-US.msi"

    #Web Platform Binary Location
    $WPIDestination = "$env:temp\WebPlatformInstaller_amd64_en-US.msi"

    do
    { Invoke-WebRequest -uri $WPISource -OutFile $WPIDestination
    Write-Output "Web Platform Installer is downloaded"
Unblock-File $WPIDestination
 
    #Change directory to location of the downloaded Web Platform Installer
    cd $env:temp
 
    #Install Web Platform Installer
    $WPICommand = Start-Process $env:temp\WebPlatformInstaller_amd64_en-US.msi '/qn' -PassThru | Wait-Process;
    Write-Output "Web Platform Installer is successfully installed"
    sleep 5
 
    $WPIPathCheck = Test-Path "C:\Program Files\Microsoft\Web Platform Installer\WebpiCmd-x64.exe"
    }while($WPIPathCheck -ne "True")



    #Installation of Azure Service Fabric
    do
    {$WPIPath = "C:\Program Files\Microsoft\Web Platform Installer\"
cd $WPIPath
 
    $AzureSDKCommand = .\WebpiCmd.exe /Install /Products:MicrosoftAzure-ServiceFabric-CoreSDK /AcceptEULA /Log:C:/Packages/Plugins/Microsoft.Compute.CustomScriptExtension/1.9/WebpiCmd.log
Write-Output "Azure Service Fabric Core SDK is successfully installed"
 
    sleep 5
 
    $ServiceFabricPathCheck = Test-Path "C:\Program Files\Microsoft Service Fabric\bin\ServiceFabric\ServiceFabric.psd1"
    }while($ServiceFabricPathCheck -ne "True")

 
    #Installation of Azure Service Fabric SDK
    $Destination = "$env:temp"
    #Service Fabric SDK Installer URL
    $ServiceFabricSDKSource = Invoke-WebRequest -uri "https://download.microsoft.com/download/2/9/E/29E129A2-5C20-46A6-83EB-A4958097DC2E/MicrosoftServiceFabricSDK.2.7.198.msi" -OutFile "$Destination\MicrosoftServiceFabricSDK.2.7.198.msi"
    Write-Output "Azure Service Fabric SDK is downloaded"
Unblock-File "$Destination\MicrosoftServiceFabricSDK.2.7.198.msi"

    do
    { 
    #Install Azure Service Fabric SDK
    $AzureSDKCommand = Start-Process $Destination\MicrosoftServiceFabricSDK.2.7.198.msi '/qn' -PassThru | Wait-Process;
    $errcheck = $?
    if($errcheck){
    Write-Output "Azure Service Fabric SDK is successfully installed"
    }

    sleep 5

    $ServiceFabricSDKPathCheck = Test-Path "C:\Program Files\Microsoft SDKs\Service Fabric\Tools\PSModule\ServiceFabricSDK\ServiceFabricSDK.psm1"
    }while($ServiceFabricSDKPathCheck -ne "True")



    #Installation of Azure Powershell
    $Destination = "C:\Packages\Plugins\Microsoft.Compute.CustomScriptExtension\1.9"
    #Azure Powershell Installer URL
    $AzurePSSource = Invoke-WebRequest -uri "http://aka.ms/azure-powershellget" -OutFile "$Destination\azure-powershell.4.3.1.msi"
    Write-Output "Azure Powershell is downloaded"
Unblock-File "$Destination\azure-powershell.4.3.1.msi"

    #Check Azure RM PS Module Location
    $AzurePSPathCheck = Test-Path "C:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ResourceManager\AzureResourceManager\AzureRM.Compute\AzureRM.Compute.psd1"
    while($AzurePSPathCheck -ne "True"){
 
    #Install Azure Powershell
    $AzurePSCommand = Start-Process msiexec.exe '/I C:\Packages\Plugins\Microsoft.Compute.CustomScriptExtension\1.9\azure-powershell.4.3.1.msi /quiet /passive /norestart' -WindowStyle Hidden

    exit
    }

Creating azure scheduler using powershell


$sub = Select-AzureRmSubscription -SubscriptionId $SubscriptionId

function createSchedulerJob {
param(
[Parameter(Mandatory=$true)]
[String] $SchedulerResourceGroup,

[Parameter(Mandatory=$true)]
[String] $SchedulerCollectionName,

[Parameter(Mandatory=$true)]
[String] $ScheduleJobParam,

[Parameter(Mandatory=$true)]
[String] $AutomationAccountRG,

[Parameter(Mandatory=$true)]
[String] $AutomationAccountName
)

$runbookName, $schedulerJobName, $schedulerInterval, $schedulerFrequency, $schedulerStartTime = $ScheduleJobParam.Split(";")
$schedulerStartTimeDay, $schedulerStartTimeHHMM = $schedulerStartTime.Split("-")
$schedulerStartTimeHour, $schedulerStartTimeMinute = $schedulerStartTimeHHMM.Split(":")

$webhookName = "$runbookName-Webhook"
$HybridWorkerGroup = "HybridWorkerGroup"
$webhookExpiryTime = (Get-Date).AddYears(5)

$job = Get-AzureRmSchedulerJob -ResourceGroupName $SchedulerResourceGroup -JobCollectionName $SchedulerCollectionName -JobName $schedulerJobName -ErrorAction SilentlyContinue
$webhook = Get-AzureRmAutomationWebhook -Name $webhookName -ResourceGroupName $AutomationAccountRG -AutomationAccountName $AutomationAccountName -ErrorAction SilentlyContinue

if ($job -eq $null -or ($webhook -ne $null -and $webhook.ExpiryTime -lt (Get-Date).AddYears((1)))){
if ($webhook -ne $null)
{
$null = Remove-AzureRmAutomationWebhook -ResourceGroupName $AutomationAccountRG  -AutomationAccountName $AutomationAccountName -Name $webhookName
}
}

$webhook = Get-AzureRmAutomationWebhook -Name $webhookName -ResourceGroupName $AutomationAccountRG -AutomationAccountName $AutomationAccountName -ErrorAction SilentlyContinue
if ($webhook -eq $null)
{

$webhook = New-AzureRmAutomationWebhook -Name $webhookName -RunbookName $runbookName -ResourceGroupName $AutomationAccountRG -AutomationAccountName $AutomationAccountName -IsEnabled $true -ExpiryTime $webhookExpiryTime -Force

$webhookRes = Get-AzureRmResource -ResourceGroupName $AutomationAccountRG -ResourceType 'Microsoft.Automation/automationAccounts/webhooks' -ResourceName "$AutomationAccountName/$webhookName"
$webhookRes.Properties.runOn = $HybridWorkerGroup
Set-AzureRmResource -ResourceId $webhookRes.ResourceId -Properties $webhookRes.Properties -Force
   

$schedulerJobParam = @{ResourceGroupName=$SchedulerResourceGroup;
JobCollectionName=$SchedulerCollectionName;
JobName=$schedulerJobName;
Method='POST';
Uri=$($webhook.WebhookURI);
Interval=$schedulerInterval;
Frequency=$schedulerFrequency}
$schedulerDateTimeParam = @{}

if ($schedulerFrequency -eq "Day" -and $schedulerInterval -eq "1" -and $schedulerStartTimeDay -eq "AllDay") {
$calcStartTime = (Get-Date).Date.AddDays(1).AddHours($schedulerStartTimeHour).AddMinutes($schedulerStartTimeMinute)
$schedulerDateTimeParam = @{StartTime="$calcStartTime"}
}
elseif ($schedulerFrequency -ne "Hour" -and $schedulerFrequency -ne "Minute") {           
$date = Get-Date
while ($Date.DayOfWeek -ne $schedulerStartTimeDay) {$date = $date.AddDays(1)}
$calcStartTime = ($date.Date).AddHours($schedulerStartTimeHour).AddMinutes($schedulerStartTimeMinute)
$schedulerDateTimeParam = @{StartTime="$calcStartTime"}
}
            else {
                $schedulerDateTimeParam = @{StartTime=$(Get-Date)}
            }
$schedulerJobParam += $schedulerDateTimeParam

if ($job -eq $null)
{

New-AzureRmSchedulerHttpJob @schedulerJobParam
}
else
{

Set-AzureRmSchedulerHttpJob @schedulerJobParam
}
}
else
{
Log-Information "Webhook($webhookName) already exists, skipping scheduler job creation"
}
}
#endregion function to create JobScheduler & Webhook


$null=Set-AutomationVariable -Name "AutomationAccount" -Value $AutomationAccountName -ResourceGroupName $AutomationAccountRG -AutomationAccountName $AutomationAccountName
$null=Set-AutomationVariable -Name "AutomationResourceGroup" -Value $AutomationAccountRG -ResourceGroupName $AutomationAccountRG -AutomationAccountName $AutomationAccountName

createSchedulerJob -SchedulerResourceGroup $SchedulerResourceGroup -SchedulerCollectionName $SchedulerCollectionName -scheduleJobParam $SchedulerParamPaaSComplianceCheck `
   -AutomationAccountRG $AutomationAccountRG -AutomationAccountName $AutomationAccountName

Add the alerts to the azure paas services

function Get-IsAlertNotSameasConfigured {
param(
[PSCustomObject]$existingRule,
        [PSCustomObject]$configuredAlertDataSource
)
 
if(($existingRule.DataSource.MetricName -eq $configuredAlertDataSource.metric) -and ($existingRule.Operator -eq $configuredAlertDataSource.operator) -and ($existingRule.Threshold -eq $configuredAlertDataSource.threshold) -and ($existingRule.TimeAggregation -eq $configuredAlertDataSource.timeAggregationOperator) -and ($existingRule.WindowsSize -eq $configuredAlertDataSource.windowSize))
    {
        return $true
    }
    else
    {
        return $false
    }

}


$resoureName = "Testing123girish"
$resourceGroupName = "Testing123girish"

$resource = Get-AzureRmResource  -ResourceGroupName $resourceGroupName -ResourceName $resoureName
$existingRules = Get-AzureRmAlertRule -ResourceGroup $resourceGroupName -TargetResourceId $resource.ResourceId -DetailedOutput
$configuredAlerts = (Get-Content -Raw -Path C:\Users\v-gigoud\Desktop\xslt\alert.json | ConvertFrom-Json).alerts 
if($existingRules -eq $null)
{
    $metricDefintions = Get-AzureRmMetricDefinition -ResourceId $resource.ResourceId
    foreach($configuredAlert in $configuredAlerts)
    {
        $metricPresent= $false
        foreach($metricDefintion in $metricDefintions)
        {
            if($metricDefintion.Name.LocalizedValue -contains $configuredAlert.metric)
            {
                 $metricPresent= $true
            }

        }
        if(!$metricPresent)
        {
            write-host "Metrics $($configuredAlert.metric) Not found for this resource, Skipping adding the alert rule"
        }
        else
        {
             write-host "Metrics $($configuredAlert.metric) found for this resource, Adding the alert rule"
             $actionEmail = New-AzureRmAlertRuleEmail -CustomEmail myname@company.com
           
            Add-AzureRmMetricAlertRule -Name ($configuredAlert.metric + $configuredAlert.operator + $configuredAlert.threshold) `
            -ResourceGroup $resourceGroupName `
            -Location $resource.Location `
            -TargetResourceId $resource.ResourceId `
            -MetricName $configuredAlert.metric`
            -Operator $configuredAlert.operator `
            -Threshold $configuredAlert.threshold `
            -WindowSize $configuredAlert.windowSize `
            -TimeAggregationOperator $configuredAlert.timeAggregationOperator `
            -Description ($configuredAlert.metric) `
            -Actions $actionEmail
           
        }

    }

}
else
{
    write-host "The existing rules will be checked with the configuration specified"
    foreach($existingRule in $existingRules)
    {
        write-host "The configuration alerts will be checked for existing rule $($existingRule.Name)"
        $metricFound = $false
        foreach($configuredAlert in $configuredAlerts)
        {
           if(Get-IsAlertNotSameasConfigured $existingRule.Properties.Condition  $configuredAlert)
           {
               $metricFound = $true
               break
           }
           else
           {
                if($metricFound -eq $true)
                {
                     write-host "The alerts are already present $($existingRule.Name)"
                }
                else
                {
                    $metricDefintions = Get-AzureRmMetricDefinition -ResourceId $resource.ResourceId
                    foreach($configuredAlert in $configuredAlerts)
                    {
                        $metricPresent= $false
                        foreach($metricDefintion in $metricDefintions)
                        {
                            if($metricDefintion.Name.LocalizedValue -contains $configuredAlert.metric)
                            {
                                 $metricPresent= $true
                            }

                        }
                        if(!$metricPresent)
                        {
                            write-host "Metrics $($configuredAlert.metric) Not found for this resource, Skipping adding the alert rule"
                        }
                        else
                        {
                             write-host "Metrics $($configuredAlert.metric) found for this resource, Adding the alert rule"
                             $actionEmail = New-AzureRmAlertRuleEmail -CustomEmail myname@company.com
           
                            Add-AzureRmMetricAlertRule -Name ($configuredAlert.metric + $configuredAlert.operator + $configuredAlert.threshold) `
                            -ResourceGroup $resourceGroupName `
                            -Location $resource.Location `
                            -TargetResourceId $resource.ResourceId `
                            -MetricName $configuredAlert.metric`
                            -Operator $configuredAlert.operator `
                            -Threshold $configuredAlert.threshold `
                            -WindowSize $configuredAlert.windowSize `
                            -TimeAggregationOperator $configuredAlert.timeAggregationOperator `
                            -Description ($configuredAlert.metric) `
                            -Actions $actionEmail
           
                        }

                    }
                                   
                }
            }
        }
       
    }
}

Saturday, October 28, 2017

Adding the service principle connection for automation account in azure

 $connectionName = "AzureRunAsConnection"
        $global:servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
        Add-AzureRmAccount `
            -ServicePrincipal `
            -TenantId $servicePrincipalConnection.TenantId `
            -ApplicationId $servicePrincipalConnection.ApplicationId `
        -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint | Write-Verbose

How to create a hash for a string value in powershell



#MD5 output is 128bits=16bytes
#Output is always 22 characters long

$bytesFromInput = [System.Text.UTF8Encoding]::UTF8.GetBytes($InputString)
        $sha1= [System.Security.Cryptography.MD5]::Create()
        $bytesToOutput= $sha1.ComputeHash($bytesFromInput)
        [System.Convert]::ToBase64String($bytesToOutput).ToLower().Replace('+','0').Replace('/','0').Replace('=','')

How to lock object in powershell similar to c#


$hashTable = @{}
    Lock-Object -InputObject $hashTable.SyncRoot -ScriptBlock {
        $hashTable.Add("Key", "Value")
    }



function Lock-Object
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [AllowEmptyString()]
        [AllowEmptyCollection()]
        [object]
        $InputObject,

        [Parameter(Mandatory = $true, Position = 1)]
        [scriptblock]
        $ScriptBlock
    )

    # Since we're dot-sourcing the caller's script block, we'll use Private scoped variables within this function to make sure
    # the script block doesn't do anything fishy (like changing our InputObject or lockTaken values before we get a chance to
    # release the lock.)

    Set-Variable -Scope Private -Name __inputObject -Value $InputObject -Option ReadOnly -Force
    Set-Variable -Scope Private -Name __scriptBlock -Value $ScriptBlock -Option ReadOnly -Force
    Set-Variable -Scope Private -Name __threadID -Value ([System.Threading.Thread]::CurrentThread.ManagedThreadId) -Option ReadOnly -Force
    Set-Variable -Scope Private -Name __lockTaken -Value $false

    if ($__inputObject.GetType().IsValueType)
    {
        $params = @{
            Message      = "Lock object cannot be a value type."
            TargetObject = $__inputObject
            Category     = [System.Management.Automation.ErrorCategory]::InvalidArgument
            ErrorId      = 'CannotLockValueType'
        }

        Write-Error @params
        return
    }

    try
    {
        Write-Verbose "Thread ${__threadID}: Requesting lock on $__inputObject"
        [System.Threading.Monitor]::Enter($__inputObject)
        $__lockTaken = $true
        Write-Verbose "Thread ${__threadID}: Lock taken on $__inputObject"

        . $__scriptBlock
    }
    catch
    {
        $params = @{
            Exception    = $_.Exception
            Category     = [System.Management.Automation.ErrorCategory]::OperationStopped
            ErrorId      = 'InvokeWithLockError'
            TargetObject = New-Object psobject -Property @{
                ScriptBlock = $__scriptBlock
                InputObject = $__inputObject
            }
        }

        Write-Error @params
        return
    }
    finally
    {
        if ($__lockTaken)
        {
            Write-Verbose "Thread ${__threadID}: Releasing lock on $__inputObject"
            [System.Threading.Monitor]::Exit($__inputObject)
            Write-Verbose "Thread ${__threadID}: Lock released on $__inputObject"
        }
    }
}

How to invoke a child build definition from powershell using VSTS

Get the buildid(parent and child) of the build defintions and use the powershell script to invoke the build from powershell


$buildQueUri = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/builds?api-version=2.0"


$parameters = @{
"system.debug" = $env:SYSTEM_DEBUG
"deploymentEnvironment" = $deploymentEnvironment
"region" = $regions
"deploymentPaths" =  $deploymentPaths
"parentBuildID" = $buildId
"requestedBy" = $requestedBy
}|ConvertTo-Json -Compress

$body = @{
"definition" = @{ "id" = $childBuildId }
"requestedFor" = @{ "id" = $env:BUILD_REQUESTEDFORID }
"sourceBranch" = $sourceBranch
"sourceVersion" = $sourceVersion
"parameters" = $parameters
}|ConvertTo-Json -Compress

$buildResponse = Invoke-RestMethod -Method Post -Uri $buildQueUri -Headers $headers -Body $body -ContentType 'application/json' -ErrorAction Stop

Saturday, October 7, 2017

Getting Azure advisor details from powershell using REST API

            
$advisorName = "Azure Advisor";            
function Invoke-AzureManagementPostMethod {            
             
 process {            
            
    $ClientId = "3fb00cf8-b7a6-42e0-bfdd-ae703499a52c"            
    $ClientSecret = "40v/urtrK+QLZzU5LalL75iNJ5wv9I4EUkygbM+6EtQ="            
                
    $TenantId = (Get-AzureRmContext).Tenant.Id            
    $Resource = "https://management.azure.com/"            
     $authData = Invoke-RestMethod -Method Post `
   -Uri "https://login.windows.net/$TenantId/oauth2/token?api-version=1.0" `
   -Body @{ "grant_type"="client_credentials"; "resource"=$Resource; "client_id"=$ClientId; "client_secret"=$ClientSecret; } `
   -ContentType "application/x-www-form-urlencoded"            
  $headers = @{"Authorization"="Bearer $($authData.access_token)"}            
  return $headers            
 }            
}            
            
function Get-AzureAdvisorRecommendations {            
param(            
    [Parameter(Mandatory=$true)][String]$SubscriptionId            
)            
            
    $method = "GET"            
    $URI = "https://management.azure.com/subscriptions/$SubscriptionId/providers/Microsoft.Advisor/recommendations?api-version=2017-03-31"            
    $managementHeaders = Invoke-AzureManagementPostMethod            
    $allRecommendations = Invoke-RestMethod -Uri $URI -Method $method -Headers $managementHeaders             
    $resourcegroupRecommendations=@{}             
            
    foreach($recommendation in $allRecommendations.Value | where { $_.properties.category -in ("HighAvailability", "Performance", "Cost")} )            
    {            
        $values = $recommendation.id.Split('/')            
        $resourceGroup = $values[4]            
        $resourceName = $values[8]            
        $recommendation = @{            
            Resource          =  $resourceName            
            Source            =  $advisorName                    
            Policy            =  $recommendation.properties.shortDescription.problem                     
            Severity          =  $recommendation.properties.impact                    
            Recommendation    =  $recommendation.properties.shortDescription.solution            
            Message           =  ""            
        }             
        $recommendationObject = New-Object PSObject -Property $recommendation            
        if($resourcegroupRecommendations.ContainsKey($resourceGroup))            
        {            
            $recommendationpreviousObject = $resourcegroupRecommendations.Get_Item($resourceGroup)            
            $resourcegroupRecommendations["$resourceGroup"] = $recommendationpreviousObject,$recommendationObject            
        }            
        else            
        {            
            $resourcegroupRecommendations.Add($resourceGroup, $recommendationObject)            
        }             
    }             
    $resourcegroupRecommendations            
                
}            
            
            
$output = Get-AzureAdvisorRecommendations (Get-AzureRmContext).Subscription.Id

Azure Key vault

Creating Key Vault and keys and secret

New-AzureRmKeyVault -VaultName 'ContosoKeyVault' -ResourceGroupName 'ContosoResourceGroup' -Location 'East Asia'

$key = Add-AzureKeyVaultKey -VaultName 'ContosoKeyVault' -Name 'ContosoFirstKey' -Destination 'Software'

$secretvalue = ConvertTo-SecureString 'Pa$$w0rd' -AsPlainText -Force

$secret = Set-AzureKeyVaultSecret -VaultName 'ContosoKeyVault' -Name 'SQLPassword' -SecretValue $secretvalue

Integration with Azure active directory

Applications that use a key vault must authenticate by using a token from Azure Active Directory. To do this, the owner of the application must first register the application in their Azure Active Directory

Authorize the application to use the key or secret

Set-AzureRmKeyVaultAccessPolicy -VaultName 'ContosoKeyVault' -ServicePrincipalName 8f8c4bbd-485b-45fd-98f7-ec6300b7b4ed -PermissionsToKeys decrypt,sign

Set-AzureRmKeyVaultAccessPolicy -VaultName 'ContosoKeyVault' -ServicePrincipalName 8f8c4bbd-485b-45fd-98f7-ec6300b7b4ed -PermissionsToSecrets Get

Regenerate the Keys

$regenerationPeriod = [System.Timespan]::FromDays(1)
$parameters = @{
VaultName = $keyVaultName
AccountResourceId = $storageAccountId
AccountName = "mystoragetest1"
ActiveKeyName = "key1"
RegenerationPeriod = $regenerationPeriod
}
Add-AzureKeyVaultManagedStorageAccount @parameters

Get-AzureKeyVaultManagedStorageAccount

Update-AzureKeyVaultManagedStorageAccountKey

Accessing the Keys from the web application


https://docs.microsoft.com/en-us/azure/key-vault/key-vault-use-from-web-application

Saturday, September 23, 2017

Generating html pages using XSLT and powershell

Powershell to create HTML files from XSLT template

$xslPath = "C:\Users\ggoudar\Desktop\xslt\template.xslt"
$outputStream = New-Object -TypeName "System.IO.MemoryStream"
$arglist = New-Object -TypeName "System.Xml.Xsl.XsltArgumentList"
$XslTransform  = New-Object -TypeName "System.Xml.Xsl.XslCompiledTransform"
$reader  = New-Object -TypeName "System.IO.StreamReader" -ArgumentList $outputStream
$XslTransform.Load($xslPath)
[xml]$XmlDocument = Get-content "C:\Users\ggoudar\Desktop\xslt\data.xml"
$XslTransform.Transform($XmlDocument,$arglist,$outputStream)
$outputStream.Position = 0L
$transformed =  $reader.ReadToEnd()
$tempFile = "$([System.IO.Path]::GetTempPath())$([Guid]::NewGuid()).html"
$null = Out-File -NoClobber -FilePath $tempFile -InputObject $transformed -Force

XSLT file for generating the summary report

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
  <xsl:output method="html" indent="no"/>
  <xsl:template match="/">
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta name="description" content="" />
        <meta name="author" content="" />
        <meta charset="utf-8" />
        <title>Report</title>
        <style type="text/css">
        </style>
      </head>
      <body>
        <div class="container-fluid">
          <div class="row">
            <div class="col-sm-10 col-sm-offset-1 col-md-10 col-md-offset-1 main">
              <div class="panel panel-primary">
                <div class="panel-heading">
                  Summary - IRM
                </div>
                <div class="panel-body">
                  <xsl:for-each select="Report/Subscription">
                    <table class="table table-striped">
                      <tbody>
                        <tr>
                          <td>
                            <xsl:value-of select="@Name"/>
                            <xsl:apply-templates select="ResourceGroup"/>
                          </td>
                        </tr>
                      </tbody>
                    </table>
                  </xsl:for-each>
                </div>
              </div>
            </div>
          </div>
        </div>
      </body>
    </html>
  </xsl:template>
  <xsl:template match="ResourceGroup">
    <xsl:variable name="nodes" select="node()"/>
    <table class="table table-striped">
      <tbody>
        <tr>
          <td>
            <xsl:for-each select="@Name">
              <xsl:value-of select="." />
              <xsl:call-template name="DisplayResourceDetails">
                <xsl:with-param name="nodes" select = "$nodes" />
              </xsl:call-template>
            </xsl:for-each>
          </td>
        </tr>
      </tbody>
    </table>
  </xsl:template>
  <xsl:template name = "DisplayResourceDetails" >
    <xsl:param name = "nodes" />
    <table class="table table-striped">
      <thead>
        <tr>
          <th>Resource Type</th>
          <th>Non-Compliant Resources</th>
          <th>Errors</th>
        </tr>
      </thead>
      <tbody>
        <xsl:for-each select="$nodes">
          <tr>
            <td>
              <xsl:value-of select="@Name"/>
            </td>
            <td>
              <xsl:value-of select="count(Resource/Policy[ValidationResult=0])"/>
            </td>
            <td>
              <xsl:value-of select="count(Resource/Policy[ValidationResult=2])"/>
            </td>
          </tr>
        </xsl:for-each>
      </tbody>
    </table>
  </xsl:template>
</xsl:stylesheet>


XSLT file for generating the detailed report


<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
  <xsl:output method="html" indent="no"/>

  <xsl:template match="/">
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta name="description" content="" />
        <meta name="author" content="" />
        <meta charset="utf-8" />
        <title>Report</title>
        <style type="text/css">
        </style>
      </head>
      <body>
        <div class="container-fluid">
          <div class="row">
            <div class="col-sm-10 col-sm-offset-1 col-md-10 col-md-offset-1 main">
              <div class="panel panel-primary">
                <div class="panel-heading">
                  Report Information
                </div>
                <div class="panel-body">
                  <table class="table table-striped">
                    <tbody>
                      <tr>
                        <th>Date :</th>
                        <td>
                          <xsl:value-of select="/Report/Subscription/@Date" />
                        </td>
                      </tr>
                      <tr>
                        <th>Subscription :</th>
                        <td>
                          <xsl:value-of select="/Report/Subscription/@Name" />
                        </td>
                      </tr>
                      <tr>
                        <th>Resource Group :</th>
                        <td>
                          <xsl:value-of select="/Report/Subscription/ResourceGroup/@Name" />
                        </td>
                      </tr>
                    </tbody>
                  </table>
                </div>
              </div>
            </div>
          </div>
          <div class="row">
            <div class="col-sm-10 col-sm-offset-1 col-md-10 col-md-offset-1 main">
              <div class="panel panel-primary">
                <div class="panel-heading">
                  Summary
                </div>
                <table class="table table-striped">
                  <thead>
                    <tr>
                      <th>Resource</th>
                      <th>Resource Type</th>
                      <th>Non-Compliant Rules</th>
                      <th>Errors</th>
                    </tr>
                  </thead>
                  <tbody>
                    <xsl:for-each select="Report/Subscription/ResourceGroup/ResourceType">
                      <xsl:call-template name="DisplayResourceTyperHeader">
                        <xsl:with-param name="nodes" select = "Resource" />
                        <xsl:with-param name="resourceName" select = "@Name" />
                      </xsl:call-template>
                    </xsl:for-each>
                  </tbody>
                </table>
              </div>
            </div>
          </div>
          <xsl:for-each select="Report/Subscription/ResourceGroup/ResourceType">
            <xsl:call-template name="DisplayResourceTypeDetails">
              <xsl:with-param name="nodes" select = "Resource" />
              <xsl:with-param name="resourceName" select = "@Name" />
            </xsl:call-template>
          </xsl:for-each>
        </div>
      </body>
    </html>
  </xsl:template>
  <xsl:template name = "DisplayResourceTyperHeader" >
    <xsl:param name = "nodes" />
    <xsl:param name = "resourceName" />
    <xsl:for-each select="$nodes">
      <tr>
        <td>
          <xsl:value-of select="@Name" />
        </td>
        <td>
          <xsl:value-of select="$resourceName" />
        </td>
        <td>
          <xsl:value-of  select="count(Policy[ValidationResult=0])"/>
        </td>
        <td>
          <xsl:value-of  select="count(Policy[ValidationResult=2])"/>
        </td>
      </tr>
    </xsl:for-each>
  </xsl:template>
  <xsl:template name = "DisplayResourceTypeDetails" >
    <xsl:param name = "nodes" />
    <xsl:param name = "resourceName" />
    <xsl:for-each select="$nodes">
      <div class="row" id="{generate-id(@Name)}">
        <div class="col-sm-10 col-sm-offset-1 col-md-10 col-md-offset-1 main">
          <div class="panel panel-primary">
            <div class="panel-heading">
              <b>
                <xsl:value-of select="@Name" />
              </b>
            </div>
            <div class="panel-body">
              <div class="table-responsive">
                <table class="table table-striped">
                  <thead>
                    <tr>
                      <th>Policy</th>
                      <th>Severity</th>
                      <th>Recommendation</th>
                      <th>Message</th>
                    </tr>
                  </thead>
                  <tbody>
                    <xsl:for-each select="Policy">
                      <tr>
                        <td>
                          <xsl:value-of select="@Name" />
                        </td>
                        <td>
                          <xsl:value-of select="Severity" />
                        </td>
                        <td>
                          <xsl:value-of select="Recommendation" />
                        </td>
                        <td>
                          <xsl:value-of select="Message" />
                        </td>
                      </tr>
                    </xsl:for-each>
                  </tbody>
                </table>
              </div>
            </div>
          </div>
        </div>
      </div>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>


XML file 


<?xml version="1.0" encoding="utf-8"?>
<Report>
  <Subscription Name="Subscription1" Date="19-09-2017 14:31">
    <ResourceGroup Name="ResourceGroup1">
      <ResourceType Name = "Microsoft.Web/sites">
<Resource Name="TestResource">
 <Policy Name="testing">
<Message>Message1</Message>
<Recommendation>It is recommended to choose 64-bit platform to handle more load</Recommendation>
<Severity>Medium</Severity>
<Source>Framework</Source>
<ValidationResult>0</ValidationResult>
 </Policy>
 <Policy Name="testing">
<Message>Message2</Message>
<Recommendation>It is recommended to choose 64-bit platform to handle more load</Recommendation>
<Severity>Medium</Severity>
<Source>Framework</Source>
<ValidationResult>0</ValidationResult>
 </Policy>
            </Resource>
<Resource Name="TestResource9">
 <Policy Name="testing123">
<Message>Message3 </Message>
<Recommendation>It is recommended to choose 64-bit platform to handle more load</Recommendation>
<Severity>Medium</Severity>
<Source>Framework</Source>
<ValidationResult>0</ValidationResult>
<ValidationResultText>Not Compliant</ValidationResultText>               
 </Policy>
            </Resource>
      </ResourceType>
      <ResourceType Name = "Microsoft.ServiceFabric/Cluster">
<Resource Name="TestResource1">
 <Policy Name="testing123456">
<Message>Message4</Message>
<Recommendation>It is recommended to choose 64-bit platform to handle more load</Recommendation>
<Severity>Medium</Severity>
<Source>Framework</Source>
<ValidationResult>2</ValidationResult>
<ValidationResultText>Not Compliant</ValidationResultText>               
 </Policy>
            </Resource>
      </ResourceType>
    </ResourceGroup>
    <ResourceGroup Name="ResourceGroup2">
      <ResourceType Name = "Microsoft.Web/sites">
<Resource Name="TestResource2">
 <Policy Name="testing12390">
<Message>Expected: 'False'. Received: </Message>
<Recommendation>It is recommended to choose 64-bit platform to handle more load</Recommendation>
<Severity>Medium</Severity>
<Source>Framework</Source>
<ValidationResult>2</ValidationResult>
<ValidationResultText>Not Compliant</ValidationResultText>               
 </Policy>
            </Resource>
      </ResourceType>
      <ResourceType Name = "Microsoft.ServiceFabric/Cluster">
<Resource Name="TestResource3">
 <Policy Name="testing12312">
<Message>Expected: 'False'. Received: </Message>
<Recommendation>It is recommended to choose 64-bit platform to handle more load</Recommendation>
<Severity>Medium</Severity>
<Source>Framework</Source>
<ValidationResult>2</ValidationResult>
<ValidationResultText>Not Compliant</ValidationResultText>               
 </Policy>
            </Resource>
      </ResourceType>
    </ResourceGroup>
  </Subscription>
  <Subscription Name="Subscription2">
    <ResourceGroup Name = "ResourceGroup3">
      <ResourceType Name = "Microsoft.Web/sites">
<Resource Name="TestResource4">
 <Policy Name="testing123">
<Message>Expected: 'False'. Received: </Message>
<Recommendation>It is recommended to choose 64-bit platform to handle more load</Recommendation>
<Severity>Medium</Severity>
<Source>Framework</Source>
<ValidationResult>0</ValidationResult>
<ValidationResultText>Not Compliant</ValidationResultText>               
 </Policy>
            </Resource>
      </ResourceType>
      <ResourceType Name = "Microsoft.ServiceFabric/Cluster">
<Resource Name="TestResource5">
 <Policy Name="testing123">
<Message>Expected: 'False'. Received: </Message>
<Recommendation>It is recommended to choose 64-bit platform to handle more load</Recommendation>
<Severity>Medium</Severity>
<Source>Framework</Source>
<ValidationResult>2</ValidationResult>
<ValidationResultText>Not Compliant</ValidationResultText>               
 </Policy>
            </Resource>
      </ResourceType>
    </ResourceGroup>
    <ResourceGroup Name = "ResourceGroup4">
      <ResourceType Name = "Microsoft.Web/sites">
<Resource Name="TestResource6">
 <Policy Name="testing123">
<Message>Expected: 'False'. Received: </Message>
<Recommendation>It is recommended to choose 64-bit platform to handle more load</Recommendation>
<Severity>Medium</Severity>
<Source>Framework</Source>
<ValidationResult>2</ValidationResult>
<ValidationResultText>Not Compliant</ValidationResultText>               
 </Policy>
            </Resource>
      </ResourceType>
      <ResourceType Name = "Microsoft.ServiceFabric/Cluster">
<Resource Name="TestResource7">
 <Policy Name="testing123">
<Message>Expected: 'False'. Received: </Message>
<Recommendation>It is recommended to choose 64-bit platform to handle more load</Recommendation>
<Severity>Medium</Severity>
<Source>Framework</Source>
<ValidationResult>0</ValidationResult>
<ValidationResultText>Not Compliant</ValidationResultText>               
 </Policy>
            </Resource>
      </ResourceType>
    </ResourceGroup>
  </Subscription>
</Report>






Thursday, September 21, 2017

Rest API call to TFS to get the changeset details from the build


Getting the changeset details from VSTS

Enable the setting "Allow script to access OAuth token" in the VSTS team system and run the following powershell commands


$buildId = $env:BUILD_BUILDID

$headers = @{Authorization=("Bearer {0}" -f $env:SYSTEM_ACCESSTOKEN)}

$buildInfoUri = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/builds/$($buildId)?api-version=2.0"

$buildInfo = Invoke-RestMethod -Method Get -Uri $buildInfoUri -Headers $headers 

$sourceVersion = $buildInfo.sourceVersion

$changesetUrl = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)/_apis/tfvc/changesets/$($sourceVersion)/changes?api-version=2.0"

$changeset = Invoke-RestMethod -Method Get -Uri $changesetUrl -Headers $headers 

Sunday, September 17, 2017

How to trigger a azure web job from a web hook using powershell



$xmlProfile = [xml](Get-AzureRMWebAppPublishingProfile -ResourceGroupName "delete" -Name"testwebgirish" -OutputFile test.xml)
$userName = $xmlProfile.publishData.publishProfile[0].userName.Tostring()
$userPWD = $xmlProfile.publishData.publishProfile[0].userPWD.Tostring()
$url = $webJobs.url
$index = $url.IndexOf('triggeredwebjobs')
$webJobUrl = $url.Substring(0,$index+ "triggeredwebjobs/"
$webHookUrl = $webJobUrl + $webJobs.name + "/run"
$request = [System.Net.WebRequest]::Create($webHookUrl)
#$pair = "$userName"+":"+$userPWD+"
$auth =[System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($userName+":"+$userPWD))
$request.Method = "POST"
$request.ContentLength = 0;
$request.Headers["Authorization"] = "Basic " + $auth
$response = $request.GetResponse()
$responsestream = $response.GetResponseStream();
[System.IO.StreamReader] $streamReader = New-Object System.IO.StreamReader -argumentList$responsestream;
[string] $results = $streamReader.ReadToEnd();