DSCResources/MSFT_xAzureStorageAccount/MSFT_xAzureStorageAccount.psm1

#region GET FUNCTION

function Get-TargetResource {
[CmdletBinding()]
[OutputType([Hashtable])]
param (
[Parameter(Mandatory)][string]$AffinityGroup,
[Parameter(Mandatory)][string]$StorageAccountName,
[string]$Container,
[string]$Folder,
[string]$Label
)
    $CurrentSubscription = Get-AzureSubscription -Current
    $CurrentSubscription.CurrentStorageAccountName = $StorageAccountName
    Write-Verbose "The Azure subscription ID is $($CurrentSubscription.SubscriptionID)"
    Write-Verbose "The Azure storage account is $($CurrentSubscription.CurrentStorageAccountName)"

    # Native Get cmdlet
    $Get = Get-AzureStorageAccount -StorageAccountName $StorageAccountName -ErrorAction SilentlyContinue
    if ($Get -ne $null -AND $Container -ne '') {
        $StorageKey = Get-AzureStorageKey -StorageAccountName $StorageAccountName
        $AzureStorageContext = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageKey.Primary -Protocol Https
        
        $GetContainer = Get-AzureStorageContainer -Name $Container -Context $AzureStorageContext -ErrorAction SilentlyContinue | % Name
        
        if ($Folder){
            $GetFolder = Get-Item $Folder -ErrorAction SilentlyContinue | % FullName
            }
        }

    # Build Hashtable from cmdlet values
    @{
        'Ensure' = If ($Get.StorageAccountName -eq $StorageAccountName) {'Present'} Else {'Absent'}
        'AffinityGroup' = $Get.AffinityGroup
        'StorageAccountName' = $Get.StorageAccountName
        'Container' = $GetContainer
        'Folder' = $GetFolder
        'Label' = $Get.Label
    }

 }

# Get-TargetResource 'TestVMWestUS1' 'testvmstorage1' -Container 'scriptextensionfiles' -folder 'c:\Azure\scriptextensionfiles' -Verbose
# Expectation is a hashtable with properties of the storage account, if it exists.

#endregion



#region SET FUNCTION

function Set-TargetResource {
[CmdletBinding()]
param(
[ValidateSet('Present','Absent')]
[string]$Ensure = 'Present',
[Parameter(Mandatory)][string]$AffinityGroup,
[Parameter(Mandatory)][string]$StorageAccountName,
[string]$Container,
[string]$Folder,
[string]$Label
)

    switch ($Ensure) {
        'Present' {
            # Native Test for name conflict
            $CurrentSubscription = Get-AzureSubscription -Current
            Write-Verbose "The Azure subscription ID is $($CurrentSubscription.SubscriptionID)"
            $TestAzureStorageName = Test-AzureName -Name $StorageAccountName -Storage

            # Test storage account name for Azure requirements, lowercase, no special characters, and between 3 and 24 characters
            $AzureStorageNameRequirements = ($StorageAccountName -cmatch ‘^[a-z\d]+$’)
            if ($AzureStorageNameRequirements -eq $False) {
                Write-Error 'The Storage Account Name does not meet requirements of 3-24 characters, lower case letters, and numbers.'
                }

            # Validate whether New or Set is required
            $Get = Get-TargetResource -AffinityGroup $AffinityGroup -StorageAccountName $StorageAccountName -Container $Container -Folder $Folder -Label $Label -ErrorAction SilentlyContinue 

            if ($Get.StorageAccountName -eq $StorageAccountName) {
                # Storage already exists. Verify Configuration with native Set cmdlet
                $CurrentSubscription = Get-AzureSubscription -Current
                Write-Verbose "The Azure subscription ID is $($CurrentSubscription.SubscriptionID)"
                Set-AzureStorageAccount -StorageAccountName $StorageAccountName -Label $Label
                
                # Assign current storage account name
                Set-AzureSubscription -SubscriptionName $CurrentSubscription.SubscriptionName -CurrentStorageAccountName $StorageAccountName
                $CurrentSubscription = Get-AzureSubscription -Current
                Write-verbose "Azure Storage Account Name: $($CurrentSubscription.CurrentStorageAccountName)"
                
                # Create Storage Context
                $StorageKey = Get-AzureStorageKey -StorageAccountName $StorageAccountName
                $AzureStorageContext = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageKey.Primary

                # If Container does not exist, re-create it
                if ($Get.Container -notcontains $Container) {
                    Write-Verbose "Creating container: $Container"
                    New-AzureStorageContainer -Name $Container -Context $AzureStorageContext
                    }

                # If files should be uploaded and are newer locally, update files
                if ($Folder) {
                    foreach ($File in (Get-ChildItem -Path $Folder)) {
                        $Blob = Get-AzureStorageBlob -Context $AzureStorageContext -Container $Container -Blob $File.Name -ErrorAction SilentlyContinue
                        if (!$Blob -OR $File.LastWriteTime -gt $Blob.LastModified.DateTime) {
                            Write-Verbose "Uploading file: $($File.FUllName)"
                            Set-AzureStorageBlobContent -Context $AzureStorageContext -Container $Container -File $File.FullName -Force
                            }
                        }
                    }
                }
            else {
                # Creating storage account using native New cmdlet
                if ($TestAzureStorageName -eq $False){
                    Write-Verbose "Creating Storage Account `"$StorageAccountName`" in Microsoft Azure."
                    Write-Verbose 'Please be patient as the operation completes.'
                    $CurrentSubscription = Get-AzureSubscription -Current
                    Write-Verbose "The Azure subscription ID is $($CurrentSubscription.SubscriptionID)"
                    New-AzureStorageAccount -StorageAccountName $StorageAccountName -Label $Label -AffinityGroup $AffinityGroup
                    
                    # Assign current storage account name
                    Set-AzureSubscription -SubscriptionName $CurrentSubscription.SubscriptionName -CurrentStorageAccountName $StorageAccountName
                    $CurrentSubscription = Get-AzureSubscription -Current
                    Write-verbose "Azure Storage Account Name: $($CurrentSubscription.CurrentStorageAccountName)"

                    # Wait for creation to finish
                    $Status = (Get-AzureStorageAccount -StorageAccountName $StorageAccountName).StorageAccountStatus
                    While ($Status -ne 'Created') {
                        start-sleep 3
                        $Status = (Get-AzureStorageAccount -StorageAccountName $StorageAccountName).StorageAccountStatus
                        }

                    # Create Storage Context
                    $StorageKey = Get-AzureStorageKey -StorageAccountName $StorageAccountName
                    $AzureStorageContext = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageKey.Primary

                    # Create container
                    Write-Verbose "Creating container: $Container"
                    New-AzureStorageContainer -Name $Container -Context $AzureStorageContext
                    
                    # Upload files if needed
                    if ($Folder) {
                        foreach ($File in (Get-ChildItem -Path $Folder)) {
                            Write-Verbose "Uploading file: $File"
                            Set-AzureStorageBlobContent -Context $AzureStorageContext -Container $Container -File $File.FullName -Force
                            }
                        }

                  if ($TestAzureStorageName -ne $False) {
                        # Test failed due to conflict or the name was invalid
                        Write-Error "Unable to create Storage Account, the name `"$StorageAccountName`" is invalid or already in use"
                        }
                }
            }
        }

        'Absent' {
            $CurrentSubscription = Get-AzureSubscription -Current
            Write-Verbose "The Azure subscription ID is $($CurrentSubscription.SubscriptionID)"
                               
            # Create Storage Context
            $StorageKey = Get-AzureStorageKey -StorageAccountName $StorageAccountName
            $AzureStorageContext = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageKey.Primary -Protocol Https

            # Remove each item in containers
            $Containers = Get-AzureStorageContainer -Context $AzureStorageContext
            foreach ($ContainerItem in $Containers) {
                Write-Verbose "Removing Container `"$($ContainerItem.Name)`""
                $LeaseStatus = $ContainerItem.CloudBlobContainer.Properties.LeaseStatus
                #Wait for Remove operation to complete
                While ($LeaseStatus -eq 'Locked') {
                    Start-Sleep 5
                    $LeaseStatus = (Get-AzureStorageContainer -Name $ContainerItem.Name -Context $AzureStorageContext).CloudBlobContainer.Properties.LeaseStatus
                    }
                # Remove containers
                Remove-AzureStorageContainer -Context $AzureStorageContext -Name $ContainerItem.Name -Force
                }
            # Remove Storage Account
            Remove-AzureStorageAccount -StorageAccountName $StorageAccountName
            }
        }
    }

# Set-TargetResource 'Present' 'TestVMWestUS1' 'testvmstorage1' -Container 'scriptextensionfiles' -folder 'c:\Azure\scriptextensionfiles' -Verbose
# Expectation is the storage account will be created, set, or removed. Validate using Get-AzureStorageAccount.

#endregion



#region TEST FUNCTION

function Test-TargetResource {
[CmdletBinding()]
[OutputType([Boolean])]
param(
[ValidateSet('Present','Absent')]
[string]$Ensure = 'Present',
[Parameter(Mandatory)][string]$AffinityGroup,
[Parameter(Mandatory)][string]$StorageAccountName,
[string]$Container,
[string]$Folder,
[string]$Label
)
    # Output from Get-TargetResource
    $Get = Get-TargetResource -AffinityGroup $AffinityGroup -StorageAccountName $StorageAccountName -ErrorAction SilentlyContinue 

    $CurrentAccountSet = (Get-AzureSubscription -Current).CurrentStorageAccountName -eq $StorageAccountName

    # Compare dictionary and hash table
    switch ($Ensure) {
        'Present'{
            $bool = $true
            $bool = $CurrentAccountSet
            }
        'Absent'{
            $bool = $false
            $bool = !$CurrentAccountSet
            }
        }

    @('AffinityGroup','StorageAccountName','Container','Folder','Local') | % {
    if ($PSBoundParameters[$_] -ne $Get[$_]) {
            switch ($Ensure) {
                'Present'{$bool = $false}
                'Absent'{$bool = $true}
                }
            write-verbose "$($_): $($PSBoundParameters[$_]) -ne `"$($Get[$_])`""
            }
        }

    $bool
    }

# Test-TargetResource 'Present' 'TestVMWestUS1' 'testvmstorage1' -Container 'scriptextensionfiles' -folder 'c:\Azure\scriptextensionfiles' -Verbose
# Expectation is True or False based on whether the storage account has been deployed, depending on Present/Absent.

#endregion

Export-ModuleMember -function *-TargetResource