commands.ps1

<#
.SYNOPSIS
Handle time measurements for execution
 
.DESCRIPTION
Function to enable the module to measure the execution time for any function
 
.PARAMETER Start
Switch to instruct the function that it should set a start mark for measurement
 
.PARAMETER End
Switch to instruct the function that it should stop the measurement and write the total time to the log / verbose stream
 
.EXAMPLE
Invoke-TimeSignal -Start
 
This will create the first entry in the time tabel.
This will enable the function to calculate the execution.
 
.EXAMPLE
Invoke-TimeSignal -End
 
This will instruct the function to lookup the start time for the calling function and do the calculation.
 
.NOTES
 
Author: M�tz Jensen (@splaxi)
 
#>

function Invoke-TimeSignal {
    [CmdletBinding(DefaultParameterSetName = 'Start')]
    param (
        [Parameter(Mandatory = $true, ParameterSetName = 'Start', Position = 1 )]
        [switch] $Start,
        
        [Parameter(Mandatory = $True, ParameterSetName = 'End', Position = 2 )]
        [switch] $End
    )
    $Time = (Get-Date)

    $Command = (Get-PSCallStack)[1].Command

    if($Start.IsPresent) {
        if($Script:TimeSignals.ContainsKey($Command)) {
            Write-PSFMessage -Level Verbose -Message "The command '$Command' is already taking part in time measurement."
        }
        else{
            $Script:TimeSignals.Add($Command, $Time)
        }
    }
    else{
        if($Script:TimeSignals.ContainsKey($Command)) {
            $TimeSpan = New-TimeSpan -End $Time -Start (($Script:TimeSignals)[$Command])

            Write-PSFMessage -Level Verbose -Message "Total time spent inside the function was $TimeSpan" -Target $TimeSpan -FunctionName $Command -Tag "TimeSignal"
            $Script:TimeSignals.Remove($Command)
        }
        else {
            Write-PSFMessage -Level Verbose -Message "The command '$Command' was never started to take part in time measurement."
        }
    }
}


<#
.SYNOPSIS
Add a tag to an Azure Resource
 
.DESCRIPTION
Add a tag to an Azure Resource
 
.PARAMETER ResourceGroupName
Name of the resource group that you want to work against
 
.PARAMETER TagName
Name of the tag that you want to apply to the resource
 
Default value is: "OrganizationName"
 
.PARAMETER TagValue
Value of the tag that you want to apply to the resource
 
.PARAMETER Name
Name of the resource that you want to work against
 
Support for wildcards like "DEV*"
 
.PARAMETER ApplyParentTags
Switch to instruct the cmdlet to pull the current tag collection
from the resource group and use that when applying on the resource
 
.PARAMETER WithoutTagOnly
Switch to instruct the cmdlet to only apply the tag to resources
with any tag details specified.
 
.EXAMPLE
Add-AzureRmTagToResource -ResourceGroupName "DEV" -TagValue "CustomerA"
 
This will add tag "OrganizationName" with the value "CustomerA" to all
resource found in the ResourceGroup named "DEV".
 
.EXAMPLE
Get-AzureRmSubscriptionExt -SubscriptionName "*DEV*" | Get-AzureRmResourceGroupExt -ResourceGroupName "*DEV*" |
 Add-AzureRmTagToResource -TagValue "CustomerA"
 
This will select the subscription named DEV and find the resource group name DEV,
and add the tag "OrganizationName" with the value "CustomerA" to all resources
in the resource group.
 
.EXAMPLE
Get-AzureRmSubscriptionExt -SubscriptionName "*DEV*" | Get-AzureRmResourceGroupExt -ResourceGroupName "*DEV*" |
 Add-AzureRmTagToResource -ApplyParentTags
 
This will select the subscription that matches the search *DEV*,
find the resource group that matches *DEV* in that subscription
and the tag collection from that ResourceGroup to all resources.
 
.NOTES
Author: M�tz Jensen (@splaxi)
#>

Function Add-AzureRmTagToResource {
    [CmdletBinding(DefaultParameterSetName = 'TagValue')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('ResourceGroup')]
        [string] $ResourceGroupName,

        [string] $TagName = "OrganizationName",

        [Parameter(Mandatory = $true, ParameterSetName = 'TagValue')]
        [string] $TagValue,

        [Alias('ResourceName')]
        [string] $Name = "*",

        [Parameter(Mandatory = $true, ParameterSetName = 'ParentTag')]
        [switch] $ApplyParentTags,

        [switch] $WithoutTagOnly

    )

    BEGIN {
    }

    PROCESS {
        $resGroup = Get-AzureRmResourceGroup -Name $ResourceGroupName
        
        $Tag = @{}

        Write-PSFMessage -Level Verbose -Message "Testing if we should apply parent tag (true) or not (false)." -Target ($ApplyParentTags.IsPresent)
        if ($ApplyParentTags.IsPresent) {
            $Tag = $resGroup.Tags
        }
        else {
            $null = $Tag.Add($TagName, $TagValue)
        }

        Write-PSFMessage -Level Verbose -Message "Testing if we should work on resources without tags (true) or all resources (false)." -Target ($WithoutTagOnly.IsPresent)
        if ($WithoutTagOnly.IsPresent) {
            $res = Get-AzureRmResource -ResourceGroupName $ResourceGroupName | Where-Object {$null -eq $_.tags -or $_.tags.Count -lt 1 -or $_.Tags.ContainsKey($TagName) -eq $false}
        }
        else {
            $res = Get-AzureRmResource -ResourceGroupName $ResourceGroupName
        }

        foreach ($item in $res) {
            if ($item.Name -notlike $Name) {continue}

            Write-PSFMessage -Level Verbose -Message "Adding tag on $($item.Name) ($($item.ResourceId))" -Target $Tag
            Set-AzureRmResource -ResourceId $item.ResourceId -Tag $Tag -Force
        }
    }

    END {}
}


<#
.SYNOPSIS
Add a tag to an Azure Resource Group
 
.DESCRIPTION
Add a tag to an Azure Resource Group
 
.PARAMETER ResourceGroupName
Name of the resource group that you want to work against
 
.PARAMETER TagName
Name of the tag that you want to apply to the resource
 
Default value is: "OrganizationName"
 
.PARAMETER TagValue
Value of the tag that you want to apply to the resource
 
.EXAMPLE
Add-AzureRmTagToResourceGroup -ResourceGroupName "DEV" -TagValue "CustomerA"
 
This will add tag "OrganizationName" with the value "CustomerA" to the
resource group named "DEV".
 
.EXAMPLE
Get-AzureRmSubscriptionExt -SubscriptionName "*DEV*" | Get-AzureRmResourceGroupExt -ResourceGroupName "*DEV*" |
 Add-AzureRmTagToResourceGroup -TagValue "CustomerA"
 
This will select the subscription that matches the *DEV* search,
find the resource group that matches *DEV* in that subscription
and add the tag "OrganizationName" with the value "CustomerA" to it.
 
.NOTES
Author: M�tz Jensen (@splaxi)
#>

Function Add-AzureRmTagToResourceGroup {
    [CmdletBinding(DefaultParameterSetName = 'TagValue')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('ResourceGroup')]
        [string] $ResourceGroupName,

        [string] $TagName = "OrganizationName",

        [Parameter(Mandatory = $true, ParameterSetName = 'TagValue')]
        [string] $TagValue
    )

    BEGIN {
    }

    PROCESS {
        $resGroup = Get-AzureRmResourceGroup -Name $ResourceGroupName

        $Tag = @{}
        $null = $Tag.Add($TagName, $TagValue)

        Write-PSFMessage -Level Verbose -Message "Adding tag on $ResourceGroupName ($($resGroup.ResourceId))" -Target $Tag
        Set-AzureRmResourceGroup -Tag $Tag -Id $resGroup.ResourceId
    }

    END {}
}

<#
.SYNOPSIS
Get Azure RM Resource
 
.DESCRIPTION
Get Azure RM Resource
 
.PARAMETER ResourceGroupName
Name of the resource group that you want to work against
 
.PARAMETER Name
Name of the resource that you want to work against
 
.EXAMPLE
Get-AzureRmResourceExt -ResourceGroupName "DEV"
 
This will get all resources from the resource group named DEV.
 
.EXAMPLE
Get-AzureRmSubscriptionExt -SubscriptionName "*dev*" | Get-AzureRmResourceGroupExt -ResourceGroupName "*DEV*"
 | Get-AzureRmResourceExt
 
This will select the subscription that matches the search *DEV*, find the resource group
that matches *DEV* in that subscription and get all resources from that.
 
.NOTES
Author: M�tz Jensen (@splaxi)
 
#>

Function Get-AzureRmResourceExt {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('ResourceGroup')]
        [string] $ResourceGroupName,

        [Alias('ResourceName')]
        [string] $Name = "*"
    )

    BEGIN {
    }

    PROCESS {
        $res = Get-AzureRmResource -ResourceGroupName $ResourceGroupName

        Write-PSFMessage -Level Verbose -Message "Filtering all resources that doesn't match the name" -Target $Name
        foreach ($item in $res) {
            if ($item.Name -notlike $Name) {continue}
            $item
        }
    }

    END {}
}

<#
.SYNOPSIS
Get Azure RM Resource
 
.DESCRIPTION
Get Azure RM Resource
 
.PARAMETER SubscriptionName
Name of the Azure subscription that you want to work against
 
.PARAMETER ResourceGroupName
Name of the resource group that you want to work against
 
.PARAMETER WithoutTagOnly
Switch to instruct the cmdlet to only list resource groups without any tag details
 
.EXAMPLE
Get-AzureRmResourceGroupExt -SubscriptionName "DEV" -ResourceGroupName "*DEV*"
 
This will get the resource group that contains the search *DEV* inside thesubscription named DEV.
 
.EXAMPLE
Get-AzureRmSubscriptionExt -SubscriptionName "*dev*" | Get-AzureRmResourceGroupExt -ResourceGroupName "*DEV*"
 
This will get the subscription that matches the search *DEV* and get the ResourceGroup that matches the search *DEV*.
 
.EXAMPLE
Get-AzureRmSubscriptionExt -SubscriptionName "*dev*" | Get-AzureRmResourceGroupExt -WithoutTagOnly
 
This will get the subscription that matches the search *DEV* and get all ResourceGroups that doesn't have a tag collection specified.
 
.NOTES
Author: M�tz Jensen (@splaxi)
#>

Function Get-AzureRmResourceGroupExt {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipelineByPropertyName = $true)]
        [string] $SubscriptionName,

        [Alias('Name')]
        [string] $ResourceGroupName = "*",

        [switch] $WithoutTagOnly
    )
    
    BEGIN {
        if ($SubscriptionName) {
            $sub = Get-AzureRmSubscription -SubscriptionName $SubscriptionName
            $null = Set-AzureRmContext -SubscriptionObject $sub
        }
    }

    PROCESS {
        
        Write-PSFMessage -Level Verbose -Message "Testing if we should work on resources without tags (true) or all resources (false)." -Target ($WithoutTagOnly.IsPresent)
        if ($WithoutTagOnly.IsPresent) {
            $resGroups = Get-AzureRmResourceGroup | Where-Object {$null -eq $_.tags -or $_.tags.Count -lt 1}
        }
        else {
            $resGroups = Get-AzureRmResourceGroup
        }

        Write-PSFMessage -Level Verbose -Message "Filtering all resource groups that doesn't match the name" -Target $ResourceGroup
        foreach ($item in $resGroups) {
            if ($item.Name -notlike $ResourceGroup) {continue}
            $item
        }
    }

    END {}

}


<#
.SYNOPSIS
Get subscription
 
.DESCRIPTION
Get subscription
 
.PARAMETER SubscriptionName
Name of the subscription you want to work against
 
Support for wildcards like "DEV*"
 
.EXAMPLE
Get-AzureRmSubscriptionExt -Name "*DEV*","*TEST*"
 
This will get all the subscriptions that matches the search *DEV* and *TEST*
 
.NOTES
Author: M�tz Jensen (@splaxi)
#>

Function Get-AzureRmSubscriptionExt {
    [CmdletBinding()]
    param(
        [Alias('Name')]
        [string[]] $SubscriptionName = "*"
    )

    BEGIN {
    }

    PROCESS {
        Write-PSFMessage -Level Verbose -Message "Prepping regex array search"
        for ($i = 0; $i -lt $SubscriptionName.Count; $i++) {
            $SubscriptionName[$i] = ".$($SubscriptionName[$i])."
        }
        
        $subs = Get-AzureRmSubscription

        $regRes = @($subs.name) -match ( $SubscriptionName -join "|")

        Write-PSFMessage -Level Verbose -Message "Filtering all subscriptions that doesn't match the name" -Target $SubscriptionName
        foreach ($item in $regRes) {
            $subs | Where-Object Name -eq $item | Select-Object
        }
    }

    END {}
    
}