DSCResources/ArcGIS_RemoteFile/ArcGIS_RemoteFile.psm1


function Invoke-DownloadFile($url, $targetFile)
{
   try {
        Start-BitsTransfer -Source $url -Destination $targetFile
   }
   catch {
       # Exception could happen if the bits service is not running
       $uri = New-Object "System.Uri" "$url"
       $request = [System.Net.HttpWebRequest]::Create($uri)
       $request.set_Timeout(15000) #15 second timeout
       $response = $request.GetResponse()
       if(-not ($responseContentLength -lt 1024))
       {
          $totalLength = [System.Math]::Floor($response.get_ContentLength()/1024)
       }
       else
       {
          $totalLength = [System.Math]::Floor(1024/1024)
       }

       $responseStream = $response.GetResponseStream()
       $targetStream = New-Object -TypeName System.IO.FileStream -ArgumentList $targetFile, Create
       $buffer = new-object byte[] 10KB
       $count = $responseStream.Read($buffer,0,$buffer.length)
       $downloadedBytes = $count
       while ($count -gt 0)
       {
           $targetStream.Write($buffer, 0, $count)
           $count = $responseStream.Read($buffer,0,$buffer.length)
           $downloadedBytes = $downloadedBytes + $count
       }

       #Write-Progress -activity "Finished downloading file '$($url.split('/') | Select-Object -Last 1)'"

       $targetStream.Flush()
       $targetStream.Close()
       $targetStream.Dispose()
       $responseStream.Dispose()
   }
}

function Get-TargetResource
{
    [CmdletBinding()]
    [OutputType([System.Collections.Hashtable])]
    param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $Url
    )
    
    $returnValue = @{
        Url = $Url
    }

    $returnValue    
}


function Set-TargetResource
{
    [CmdletBinding()]
    param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $Url,

        [System.String]
        $DestinationPath,
        
        [Parameter(Mandatory=$true)]
        [System.Boolean]
        $UseAzureFiles,

        [Parameter(Mandatory=$False)]
        [System.Management.Automation.PSCredential]
        $AFSCredential,

        [Parameter(Mandatory=$false)]
        [System.String]
        $AFSEndpoint,

        [System.Boolean]
        $Force,

        [ValidateSet("Present","Absent")]
        [System.String]
        $Ensure
    )

    if(-not($DestinationPath)) {
        throw 'Destination Path not provided'
    }

    if($Ensure -ieq 'Present') {
          $DestinationFolder = Split-Path $DestinationPath -Parent    
          if(-not(Test-Path $DestinationFolder)){
            Write-Verbose "Creating Directory $DestinationFolder"
            New-Item $DestinationFolder -ItemType directory
          }          
          if($url.StartsWith('http', [System.StringComparison]::InvariantCultureIgnoreCase)) {
              Write-Verbose "Downloading file $url to $DestinationPath"
              Invoke-DownloadFile -url $url -targetFile $DestinationPath
          }else {
                if($UseAzureFiles){
                    $AvailableDriveLetter = AvailableDriveLetter
                    New-PSDrive -Name $AvailableDriveLetter -PSProvider FileSystem -Root $AFSEndpoint -Credential $AFSCredential -Persist
                    $FileSharePath = "$($AvailableDriveLetter):\\$($url)"
                    Write-Verbose "Copying file $FileSharePath to $DestinationPath"
                    Copy-Item -Path $FileSharePath -Destination $DestinationPath -Force
                    Remove-PSDrive -Name $AvailableDriveLetter
                }else{
                    Write-Verbose "Copying file $url to $DestinationPath"
                    Copy-Item -Path $url -Destination $DestinationPath -Force
                }
          }
    }
    elseif($Ensure -ieq 'Absent') {        
        if($DestinationPath  -and  (Test-Path $DestinationPath))
        {
            Remove-Item -Path $DestinationPath -Force:$Force
        }
    }    

}


function Test-TargetResource
{
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $Url,

        [System.String]
        $DestinationPath,
        
        [Parameter(Mandatory=$true)]
        [System.Boolean]
        $UseAzureFiles,

        [Parameter(Mandatory=$False)]
        [System.Management.Automation.PSCredential]
        $AFSCredential,

        [Parameter(Mandatory=$false)]
        [System.String]
        $AFSEndpoint,

        [System.Boolean]
        $Force,

        [ValidateSet("Present","Absent")]
        [System.String]
        $Ensure
    )

    
    $result = $false
    if($DestinationPath  -and  (Test-Path $DestinationPath))
    {
        $result = $true
    }    
    if($Ensure -ieq 'Present') {
           if($result) {
               if($url.StartsWith('http', [System.StringComparison]::InvariantCultureIgnoreCase)) {
                   # File Exists locally. Check the remote location
                   Write-Verbose 'File Exists locally. Check if the remote URL has Changed using Last-Modified Header'
                   $HasRemoteFileChanged = $true
                   $response = $null
                   try { 
                        $response = Invoke-WebRequest -Uri $Url -UseBasicParsing -UseDefaultCredentials -TimeoutSec 15 -Method Head -ErrorAction Ignore 
                   }
                   catch{ 
                       $HasRemoteFileChanged = $false 
                   }
                   if($response) {
                        [DateTime]$RemoteFileLastModTime = $response.Headers['Last-Modified']                    
                        if($RemoteFileLastModTime -le (Get-Item -Path $DestinationPath).CreationTime) {
                            $HasRemoteFileChanged = $false
                        }                    
                   }
                   if($HasRemoteFileChanged) {
                     # File has changed - needs to be downloaded again
                     $result = $false
                   }
               } else {
                    if(-not($UseAzureFiles)){
                        if((Get-Item -Path $Url).LastWriteTime -gt (Get-Item -Path $DestinationPath).CreationTime) {
                            # File has changed - needs to be copied again
                            $result = $false
                        }
                    }else{
                        $result = $false
                    }
               }
           }
           $result   
    }
    elseif($Ensure -ieq 'Absent') {        
        (-not($result))
    }    
}

Function AvailableDriveLetter ()
{
    param ([char]$ExcludedLetter)
    $Letter = [int][char]'C'
    $i = @()
    #getting all the used Drive letters reported by the Operating System
    $(Get-PSDrive -PSProvider filesystem) | ForEach-Object{$i += $_.name}
    #Adding the excluded letter
    $i+=$ExcludedLetter
    while($i -contains $([char]$Letter)){$Letter++}
    Return $([char]$Letter)
}


Export-ModuleMember -Function *-TargetResource