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"
        }
    }
}