Monday, August 17, 2015

Custom DSC resource to copy files from Github

PowerShell DSC enables deploying and managing configuration data for software services and environment management very easy and convenient. Developers can create and make use of custom DSC resources to automate the daily tasks performed and distribute them for usage to the community.

To make DSC resources available in your environment, you need to have the resources available in the PSModulePath location in the computer that the resource has to be executed. If you need to use a resource from a location like GitHub for e.g., you need to download the resource and copy that to the local computers module path for usage. Or you can create a resource to do the same.

I've created a DSC resource to download files from a GitHub raw file url and copy that to the Module path in the local computer that the DSC resource executes.

enum Ensure
{
    Absent
    Present
}

[DscResource()]
class xGithubModule
{
    [DsCProperty(Key)]
    [System.String] $Url

    [DsCProperty(Mandatory)]
    [System.String] $Module

    [DsCProperty(Mandatory)]
    [Ensure] $Ensure

    [DsCProperty(NotConfigurable)]
    [Boolean] $IsValid

    [xGithubModule] Get()
    {      
        $this.IsValid = $false
        $fileName = $this.Url.Substring($this.Url.LastIndexOf('/'), $this.Url.Length - ($this.Url.LastIndexOf('/')))
        $moduleFolder = Join-Path 'C:\Program Files\WindowsPowerShell\Modules' $this.Module
               
        $fileExists = Test-Path (Join-Path $moduleFolder $fileName)

        if($this.Ensure -eq [Ensure]::Present)
        {
            if($fileExists)
            {
                $this.IsValid = $true
            }
        }
        else
        {
            if(-not $fileExists)
            {
                $this.IsValid = $true
            }
        }
        return $this
    }

    [void] Set()
    { 
        $modulePath = 'C:\Program Files\WindowsPowerShell\Modules'
        $fileName = $this.Url.Substring($this.Url.LastIndexOf('/'), $this.Url.Length - ($this.Url.LastIndexOf('/')))

        $moduleFolder = Join-Path 'C:\Program Files\WindowsPowerShell\Modules' $this.Module
        $filePath = Join-Path $moduleFolder $fileName               
     
        if($this.Ensure -eq [Ensure]::Present)
        { 
            Write-Verbose "Starting download file at location $($this.Url) to $filePath"

            $webClient = New-Object System.Net.WebClient
            $uri = New-Object System.Uri $this.Url
            $webClient.DownloadFile($uri, $filePath)          
        }
        else
        {          
            Remove-Item $filePath     
        }
    }

    [bool] Test()
    {
        $result = $this.Get()

        if($this.Ensure -eq [Ensure]::Present)
        {     
            if($result.IsValid)
            {
                Write-Verbose "The file from the Url $($this.Url) already exists in the modules folder"   
                return $true               
            }
            else
            {
                Write-Verbose "The file from the Url $($this.Url) does not exists in the modules folder. This will be downloaded"   
                return $false                  
            }
        }
        else
        {
            if($result.IsValid)
            {
                Write-Verbose "The file from the Url $($this.Url) does not exists in the modules folder"   
                return $true
            }
            else
            {
                Write-Verbose "The file from the Url $($this.Url) exists in the modules folder. This will be be removed"   
                return $false                
            }
        }
    }
}


You can now integrate this with Chef, and get your resources copied for the next run also.


No comments: