DSCResources/OctopusProjects/OctopusProjects.psm1


function Get-TargetResource
{
    [CmdletBinding()]
    [OutputType([System.Collections.Hashtable])]
    param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusURL,

        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusAPIKey,

        [parameter(Mandatory = $true)]
        [System.String]
        $ProjectTR,

        [parameter(Mandatory = $true)]
        [System.String]
        $ProjectEnv
    )

    #Write-Verbose "Use this cmdlet to deliver information about command processing."

    #Write-Debug "Use this cmdlet to write debug information while troubleshooting."


    <#
    $returnValue = @{
        OctopusURL = [System.String]
        OctopusAPIKey = [System.String]
        ProjectTR = [System.String]
        ProjectEnv = [System.String]
    }
 
    $returnValue
    #>

}


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

        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusAPIKey,

        [parameter(Mandatory = $true)]
        [System.String]
        $ProjectTR,

        [parameter(Mandatory = $true)]
        [System.String]
        $ProjectEnv
    )

    #Write-Verbose "Use this cmdlet to deliver information about command processing."

    #Write-Debug "Use this cmdlet to write debug information while troubleshooting."

    #Include this line if the resource requires a system reboot.
    #$global:DSCMachineStatus = 1


    Begin
    {
        $IISExistingWebSites = Get-Website | Select-Object -ExpandProperty name
        New-Alias -Name Octo -Value "C:\Temp\OctopusTools\Octo.exe" -Force
        
        $ProjectsList = Get-OctopusProjectsIISWebSiteNames -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey -ProjectTR $ProjectTR -ProjectEnv $ProjectEnv | Select-Object -ExpandProperty Octopus.Action.IISWebSite.WebSiteName
        $IISProjectID =  Get-IISWebSiteNamesandProjects -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey -ProjectTR $ProjectTR -ProjectEnv $ProjectEnv
        $ProjectIDIISnames= Get-ProjectIDandNames -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey
        }
        Process
        {
        $websites = @()
        foreach ($website in $IISExistingWebSites) {
            if ($website -ne "Default Web Site"){
                    $websites += $website
                }
        }

        #### Finds out the missing projects###
        Write-Verbose "Comparing project list" -Verbose
        $ProjectsMissing = Compare-Object $ProjectsList $websites | Where  SideIndicator -EQ "<=" | Select-Object -ExpandProperty InputObject
        If ($ProjectsMissing -gt 0) {
                    
        Write-Verbose "Setting Up the following Projects: $ProjectsMissing" -Verbose
                    
        foreach ($OctopusProject in $ProjectsMissing) {
        Write-Verbose "creating Missing project ID and Missing Project Names" -Verbose

        $MissingProjectID =  $IISProjectID.get_item($OctopusProject)
        $MissingProjectName = $ProjectIDIISnames.get_item($MissingProjectID)

        Write-Verbose "Starting to deploy projects" -Verbose

        $OctoAlias = Get-Alias octo |Select-Object -ExpandProperty Definition

        Write-Verbose "Set location to C:\Temp\OctopusTools\" -Verbose

        Push-Location "C:\Temp\OctopusTools\"

        Invoke-AndAssert { & .\Octo.exe deploy-release --project $MissingProjectName --version=latest --deployto $ProjectEnv --specificmachines=$env:computername --server $OctopusURL --apiKey $OctopusAPIKey}
        }
        
        } Else {Write-Verbose -Message 'Nothing to deploy' -Verbose}


    }
    End
    {
        Start-Sleep -Seconds 5

        $IISWebsites = Get-Website | Select-Object -ExpandProperty name
                    
        Write-Verbose "Websites/Projects running on this node: $IISWebsites "
    }
















}


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

        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusAPIKey,

        [parameter(Mandatory = $true)]
        [System.String]
        $ProjectTR,

        [parameter(Mandatory = $true)]
        [System.String]
        $ProjectEnv
    )

    #Write-Verbose "Use this cmdlet to deliver information about command processing."

    #Write-Debug "Use this cmdlet to write debug information while troubleshooting."


    <#
    $result = [System.Boolean]
     
    $result
    #>




        Write-Verbose -Message 'Testing if octo.exe exist'
        If (!(Test-Path -Path "C:\Temp\OctopusTools\Octo.exe")) {
        Write-Verbose -Message 'Octo.exe tool does not exist' -Verbose
        Write-Verbose "Downloading latest Octopus Tools from $CommandLineToolsURL to $CommandLineToolsPath"
        Get-OctopusCommandLineTools $CommandLineToolsURL $CommandLineToolsPath
        } Else {
        Write-Verbose 'Octo.exe exists'}
        $IISExistingWebSites = Get-Website | Select-Object -ExpandProperty name
        New-Alias -Name Octo -Value "C:\Temp\OctopusTools\Octo.exe" -Force
        $ProjectsList = Get-OctopusProjectsIISWebSiteNames -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey -ProjectTR $ProjectTR -ProjectEnv $ProjectEnv | Select-Object -ExpandProperty Octopus.Action.IISWebSite.WebSiteName
        $IISProjectID =  Get-IISWebSiteNamesandProjects -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey -ProjectTR $ProjectTR -ProjectEnv $ProjectEnv
        $ProjectIDIISnames= Get-ProjectIDandNames -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey


                    
        $websites = @()
        foreach ($website in $IISExistingWebSites) {
            if ($website -ne "Default Web Site"){
                    $websites += $website
                }
        }
         #### Finds out the missing projects###
        Write-Verbose "Comparing project list 2" -Verbose
        $ProjectsMissing = Compare-Object $ProjectsList $websites | Where  SideIndicator -EQ "<=" | Select-Object -ExpandProperty InputObject
        Write-Verbose -Message "projects missing $ProjectsMissing"

        Write-Verbose -Message 'tested if something missing01'

        If ($ProjectsMissing -gt 0) {return $false}
        else {Write-Verbose -Message 'Node has all necesary projects running. Nothing to deploy'
        return $true}

        Write-Verbose -Message 'tested if something missing'

}






function Get-EnvironmentID
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([Hashtable])]
    Param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusURL,

        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusAPIKey

    )

    Write-Verbose -Message 'Building environment name and environment ID hash table' -Verbose
    

    $Environments = Invoke-RestMethod $OctopusURL/api/environments -Headers @{ "X-Octopus-ApiKey" = $OctopusAPIKey } | Select -ExpandProperty Items

    $Environments | Select-Object Name, ID | % { $EnvironmentHashTable = @{} } { $EnvironmentHashTable[$_.Name] = $_.ID}

    return $EnvironmentHashTable
}

#Get-EnvironmentID -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey

#$EnvironmentID.get_item("PROD")

function Get-EnvironmentTarget
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([Hashtable])]
    Param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusURL,

        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusAPIKey
    )

Write-Verbose -Message 'Building environment name and Project ID target roles hash table' -Verbose

Write-verbose "Retrieving projects"
$Projects = Invoke-RestMethod $OctopusURL/api/projects -Headers @{ "X-Octopus-ApiKey" = $OctopusAPIKey } | Select -ExpandProperty Items
Write-verbose "Building deployment process API list"
$DeploymentProcesses=$Projects.links.DeploymentProcess

#Write-Host "Building project ID and target roles hash table"
foreach ($Processes in $DeploymentProcesses) {


$ProjectNameTargetHash = @{}

$ProjectID = (Invoke-RestMethod -Method Get -Uri "$OctopusURL/$Processes" -Header @{ "X-Octopus-ApiKey" = $OctopusAPIKey }) | select -expand ProjectID

$ProjectTargetRole = (Invoke-RestMethod -Method Get -Uri "$OctopusURL/$Processes" -Header @{ "X-Octopus-ApiKey" = $OctopusAPIKey }).Steps.Properties | select -expand Octopus.Action.TargetRoles -First 1

$ProjectNameTargetHash.Add($ProjectID, $ProjectTargetRole)

$ProjectTargerHash += $ProjectNameTargetHash

    
}



# Project ID targer Hash tabale
return $ProjectTargerHash
}

#Get-EnvironmentTarget -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey





function Get-ProjectIDEnvironment
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([Hashtable])]
    Param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusURL,

        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusAPIKey   

    )

Write-Verbose -Message 'Building project ID and environment ID hash table' -Verbose


$Projects = Invoke-RestMethod $OctopusURL/api/projects -Headers @{ "X-Octopus-ApiKey" = $OctopusAPIKey } | Select -ExpandProperty Items
$DeploymentProcesses=$Projects.links.DeploymentProcess


foreach ($Processes in $DeploymentProcesses) {

$ProjectNameEnvironmentsHash = @{}

$ProjectID = (Invoke-RestMethod -Method Get -Uri "$OctopusURL/$Processes" -Header @{ "X-Octopus-ApiKey" = $OctopusAPIKey }) | select -expand ProjectID
$ProjectEnvironment = (Invoke-RestMethod -Method Get -Uri "$OctopusURL/$Processes" -Header @{ "X-Octopus-ApiKey" = $OctopusAPIKey }).Steps.Actions.Environments | sort -Unique

$ProjectNameEnvironmentsHash.Add($ProjectID, $ProjectEnvironment)

$ProjectEnvironmentHash += $ProjectNameEnvironmentsHash
    
}

return $ProjectEnvironmentHash

}


#Get-ProjectIDEnvironment -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey




function Get-OctopusProjectsIISWebSiteNames
{

    Param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusURL,

        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusAPIKey,

        [parameter(Mandatory = $true)]
        [System.String]
        $ProjectTR,

        [parameter(Mandatory = $true)]
        [System.String]
        $ProjectEnv  

    )

    
        $EnvironmentID = Get-EnvironmentID -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey
        $EnvironmentTarget = Get-EnvironmentTarget -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey 
        $ProjectIDEnvironment = Get-ProjectIDEnvironment -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey

        $Projects = Invoke-RestMethod $OctopusURL/api/projects -Headers @{ "X-Octopus-ApiKey" = $OctopusAPIKey } | Select -ExpandProperty Items
        $DeploymentProcesses=$Projects.links.DeploymentProcess

foreach ($Processes in $DeploymentProcesses) {



$ProjectID = (Invoke-RestMethod -Method Get -Uri "$OctopusURL/$Processes" -Header @{ "X-Octopus-ApiKey" = $OctopusAPIKey }) | select -expand ProjectID
$Projects = Invoke-RestMethod $OctopusURL/api/projects -Headers @{ "X-Octopus-ApiKey" = $OctopusAPIKey } | Select -ExpandProperty Items
$DeploymentProcesses=$Projects.links.DeploymentProcess

If ($ProjectIDEnvironment.Item($ProjectID) -contains $EnvironmentID.Item($ProjectEnv) -and $EnvironmentTarget.Item($ProjectID) -contains $ProjectTR ) { 

(Invoke-RestMethod -Method Get -Uri "$OctopusURL/$Processes" -Header @{ "X-Octopus-ApiKey" = $OctopusAPIKey }).Steps.Actions.Properties | select Octopus.Action.IISWebSite.WebSiteName

} #else {write-host "$IISWebSiteName will be skipped"}


}





}

#Get-OctopusProjectsIISWebSiteNames -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey -ProjectTR $ProjectTR -ProjectEnv $ProjectEnv



function Get-IISWebSiteNamesandProjects
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([int])]
    Param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusURL,

        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusAPIKey,

        [parameter(Mandatory = $true)]
        [System.String]
        $ProjectTR,

        [parameter(Mandatory = $true)]
        [System.String]
        $ProjectEnv  
    )

    Begin
    {
    $EnvironmentIDHash = Get-EnvironmentID -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey

    }
    Process
    {
    $Projects = Invoke-RestMethod $OctopusURL/api/projects/all -Headers @{ "X-Octopus-ApiKey" = $OctopusAPIKey } 
    $ProjectList=$Projects.name
    $DeploymentProcesses = $Projects.links.DeploymentProcess

    Write-Verbose 'starting foreach loop'-Verbose

    foreach ($Process in $DeploymentProcesses){
    

            $Steps=Invoke-RestMethod $OctopusURL/$Process -Headers @{ "X-Octopus-ApiKey" = $OctopusAPIKey }  | Select-Object -ExpandProperty Steps
            
            $StepRole = $steps.properties | Select-Object -ExpandProperty Octopus.Action.TargetRoles | Select-Object -First 1 -Verbose
            
            $Actions=Invoke-RestMethod $OctopusURL/$Process -Headers @{ "X-Octopus-ApiKey" = $OctopusAPIKey }  | Select-Object -ExpandProperty Steps

            $Environments = $Actions.actions.environments | Sort-Object -Unique
            
            Write-Verbose 'foreach loop before if statement' 

                            if ($Environments -contains  $EnvironmentIDHash.get_item($ProjectEnv) -and $StepRole -contains $ProjectTR ) {
                            $table = @{}
            
                            Write-Verbose 'running if statement'

                            $IISName = (Invoke-RestMethod -Method Get -Uri "$OctopusURL/$Process" -Header @{ "X-Octopus-ApiKey" = $OctopusAPIKey }).Steps.Actions.Properties | select Octopus.Action.IISWebSite.WebSiteName

                            $WebSiteName = $IISName | Select-Object -ExpandProperty Octopus.Action.IISWebSite.WebSiteName

                            #Write-Output $WebSiteName

                            $ProjectID = (Invoke-RestMethod -Method Get -Uri "$OctopusURL/$Process" -Header @{ "X-Octopus-ApiKey" = $OctopusAPIKey }).ProjectID

                            #Write-Output $ProjectID
            
            
                            $table.add($WebSiteName, $ProjectID)
                            $Table01 += $table
                            
                            Continue
            

                            } else { Write-Verbose  'Failed' -Verbose  }


          # $Table01 | Write-Output

      


            #return $Table01


    }

    return $Table01 

    }

}


#Get-IISWebSiteNamesandProjects -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey -ProjectTR $ProjectTR -ProjectEnv $ProjectEnv



function Get-ProjectIDandNames
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([Hashtable])]
    Param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusURL,

        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusAPIKey
        

    )

Write-Verbose -Message 'Building project ID and Project name hash table' -Verbose


$Projects = Invoke-RestMethod $OctopusURL/api/projects -Headers @{ "X-Octopus-ApiKey" = $OctopusAPIKey } | Select -ExpandProperty Items
$SelfProjects=$Projects.links.self


foreach ($Self in $SelfProjects) {

$ProjectIDNameHash = @{}

$ProjectID = (Invoke-RestMethod -Method Get -Uri "$OctopusURL/$Self" -Header @{ "X-Octopus-ApiKey" = $OctopusAPIKey }) | select -expand ID
$ProjectName = (Invoke-RestMethod -Method Get -Uri "$OctopusURL/$Self" -Header @{ "X-Octopus-ApiKey" = $OctopusAPIKey }) | select -expand Name

$ProjectIDNameHash.Add($ProjectID, $ProjectName)

$ProjectIDNameHashTable += $ProjectIDNameHash
    
}

return $ProjectIDNameHashTable

}

#Get-ProjectIDandNames -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey






function Set-OctopusProjects
{
    [CmdletBinding()]
    [OutputType([int])]
    Param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusURL,

        [parameter(Mandatory = $true)]
        [System.String]
        $OctopusAPIKey,

        [parameter(Mandatory = $true)]
        [System.String]
        $ProjectTR,

        [parameter(Mandatory = $true)]
        [System.String]
        $ProjectEnv
    )

    Begin
    {
        $IISExistingWebSites = Get-Website | Select-Object -ExpandProperty name
        Set-Location "C:\Temp\OctopusTools\"

        $ProjectsList = Get-OctopusProjectsIISWebSiteNames -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey -ProjectTR $ProjectTR -ProjectEnv $ProjectEnv | Select-Object -ExpandProperty Octopus.Action.IISWebSite.WebSiteName
        $IISProjectID =  Get-IISWebSiteNamesandProjects -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey -ProjectTR $ProjectTR -ProjectEnv $ProjectEnv
        $ProjectIDIISnames= Get-ProjectIDandNames -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey
        }
        Process
        {
        $websites = @()
        foreach ($website in $IISExistingWebSites) {
            if ($website -ne "Default Web Site"){
                    $websites += $website
                }
        }

        #### Finds out the missing projects###
        Write-Verbose "Comparing project list" -Verbose
        $ProjectsMissing = Compare-Object $ProjectsList $websites | Where  SideIndicator -EQ "<=" | Select-Object -ExpandProperty InputObject
        If ($ProjectsMissing -gt 0) {
                    
        Write-Verbose "Setting Up the following Projects: $ProjectsMissing" -Verbose
                    
        foreach ($OctopusProject in $ProjectsMissing) {

        $MissingProjectID =  $IISProjectID.get_item($OctopusProject)
        $MissingProjectName = $ProjectIDIISnames.get_item($MissingProjectID)

        Invoke-AndAssert { & .\Octo.exe deploy-release --project $MissingProjectName --version=latest --deployto $ProjectEnv --specificmachines=$env:computername --server $OctopusURL --apiKey $OctopusAPIKey}
        }
        $IISWebsites = Get-Website | Select-Object -ExpandProperty name
                    
        Write-Verbose "Websites/Projects running on this node: $IISWebsites "
        } Else {Write-Verbose -Message 'Nothing to deploy' -Verbose}


    }
    End
    {
    }
}


#Set-OctopusProjects -OctopusURL $OctopusURL -OctopusAPIKey $OctopusAPIKey -ProjectTR $ProjectTR -ProjectEnv $ProjectEnv


function Invoke-AndAssert {
    param ($block) 
  
    & $block | Write-Verbose
    if ($LASTEXITCODE -ne 0 -and $LASTEXITCODE -ne $null) 
    {
        throw "Command returned exit code $LASTEXITCODE"
    }
}


function Request-File 
{
    param (
        [string]$url,
        [string]$saveAs
    )
 
    Write-Verbose "Downloading $url to $saveAs"
    $downloader = new-object System.Net.WebClient
    $downloader.DownloadFile($url, $saveAs)
}




function Get-OctopusCommandLineTools
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([int])]
    Param
    (
        # Param1 help description
        $Param1,

        # Param2 help description
        $Param2
    )

    Begin
    {
        $CommandLineToolsURL = "https://octopus.com/downloads/latest/CommandLineTools"
        $CommandLineToolsPath = "$($env:SystemDrive)\temp\OctopusTools.zip"
        $CommandLineToolsPathUnZipped = "$($env:SystemDrive)\Temp\OctopusTools\octo.exe"
    
    }
    Process
    {
        
    Write-Verbose "Beginning Tentacle installation" -Verbose
  
    mkdir "$env:SystemDrive\temp" -ErrorAction SilentlyContinue

    
    if (!(test-path $CommandLineToolsPath)) {
        Write-Verbose "Downloading latest Octopus Tentacle MSI from $CommandLineToolsURL to $CommandLineToolsPath"
        Request-File $CommandLineToolsURL $CommandLineToolsPath
    }
    
    if(!(Test-Path $CommandLineToolsPathUnZipped)){
    Expand-Archive -Path $CommandLineToolsPath -DestinationPath "$env:SystemDrive\temp\OctopusTools" -Verbose}
    
    }
    
}




Export-ModuleMember -Function *-TargetResource