Cartwheel.SSIS - Copy.psm1


<# Imports Cartwheel.IO :
    functions: Format-XML, Clean-XML
#>

 Class Manifest
    {
        [guid]$Id
        [string]$ProjectName
        [string]$ProjectDirectory
        [string]$ProjectFileLocation
        [string]$XML
        [version]$Version       
        [bool]$Error

        Manifest ( [string]$ProjectDirectory)
                     {
                     $this.ProjectDirectory = $ProjectDirectory
                     $this.AddManifest()
                     }

        hidden AddManifest()
        {

        #find the project file in here
        $ProjectFile = Get-ChildItem -Path $this.ProjectDirectory -Filter "*.dtproj" -ErrorAction SilentlyContinue -Force   
        $item = $ProjectFile.FullName
        $this.ProjectFileLocation = $item



        # if we didn't get an error trying to find the file...
        if($item){
          
            [xml]$xmldata = get-content $item
            [System.Xml.XmlElement]$manifest = $xmldata.Project.DeploymentModelSpecificContent.Manifest
            
            $this.Id = (($manifest.Project.Properties.Property | where {$_.Name -eq "ID"})."#Text")
            $this.ProjectName = (($manifest.Project.Properties.Property | where {$_.Name -eq "Name"})."#Text")
            $VersionMajor =( ($manifest.Project.Properties.Property | where {$_.Name -eq "VersionMajor"})."#Text")
            $VersionMinor = (($manifest.Project.Properties.Property | where {$_.Name -eq "VersionMinor"})."#Text")
            $VersionBuild =( ($manifest.Project.Properties.Property | where {$_.Name -eq "VersionBuild"})."#Text")
            $this.Version = [System.Version]::Parse("$VersionMajor.$VersionMinor.$VersionBuild")
                         
            # update for project name bug
            $ProjectNode = $manifest.Project.Properties.Property | where {$_.Name -eq 'Name'} 
            $newname = [System.IO.Path]::GetFileNameWithoutExtension($item)
            $ProjectNode.set_InnerXML($newname) 

            $this.XML = Format-XML $manifest.InnerXml    
           
        }    
        else
        {
            $this.Error = $true

        }#end addmanifest


    }

    }

 function New-Manifest{
        param([string]$ProjectDirectory)
        return [Manifest]::new("C:\Users\derek.mckee\Source\Repos\Cartwheel.SSIS.UnitTesting\Cartwheel.SSIS.UnitTesting")
    }

<# HELPER GETS #>
function Get-ProjectFolders{
    [CmdletBinding()]
    param(            
        [Parameter(Mandatory = $true)]
        [string]$SourceFolder # this is our vsts source location
    )


    $Folders = New-Object System.Collections.ArrayList
     $projects = Get-ChildItem -Path $SourceFolder -Filter "*.dtproj" -ErrorAction SilentlyContinue -Force -Recurse |? { $_.FullName -notmatch '\\obj\\|\\bin\\' }
     foreach($project in $projects)
        {
   
           $a =Split-Path -Path $project.FullName
           $Folders.Add($a) > $null
        }

        return $Folders




}

function Get-Configuration{
    # Currently only supports project configs and standard folder layouts
    [CmdletBinding()]
    param(            
        [Parameter(Mandatory = $true)]
        [string]$ProjectDirectory,
        [Parameter(Mandatory = $true)]
        [string]$ConfigurationValue

    )
    # Grab our file
        $ProjectFile = Get-ChildItem -Path $ProjectDirectory -Filter "*.dtproj" -ErrorAction SilentlyContinue -Force        
        $item = $ProjectFile.FullName
        [xml]$xmldata = get-content $item
        $ParameterConfiguration = $xmldata.Project.Configurations.Configuration


     # get our established config that we are building
     $configuration = $ParameterConfiguration | where {$_.Name -eq $ConfigurationValue} #dev,debug,prod,etc


     $dict = @{}
    # loop our entries and create
    foreach($entry in $configuration.Options.ParameterConfigurationValues.ConfigurationSetting)
    {
         $entryName = $entry.Name
         $valueproperty=$entry.Value

         $dict.Add($entryName,$valueproperty."#Text")

    }

    return $dict

}


<# HELPER ADDS #>
function Add-Manifest {
    [CmdletBinding()]
    param(            
        [Parameter(Mandatory = $true)]
        [string]$ProjectDirectory,
        [Parameter(Mandatory = $true)]
        [string]$ProjectConfiguration
    )
    
    

        Add-Type -AssemblyName System.IO


        # create return object
         $info = @{
          "Project"="";
          "ProjectName" ="";
          "VersionMajor" ="";
          "VersionMinor" ="";
          "VersionBuild" ="";
          "FileLocation" = "";
          "XML" ="" ;
          "Error" = "";
          "OutDir" = ""
          "OutFile" = ""
        }



        #find the project file in here
        $ProjectFile = Get-ChildItem -Path $ProjectDirectory -Filter "*.dtproj" -ErrorAction SilentlyContinue -Force        
        $item = $ProjectFile.FullName
        $info.FileLocation = $item
        
   
        # if we didn't get an error trying to find the file...
        if(!$ItemErr){
            
            [xml]$xmldata = get-content $item
            [System.Xml.XmlElement]$manifest = $xmldata.Project.DeploymentModelSpecificContent.Manifest
            
            $info.ProjectName = (($manifest.Project.Properties.Property | where {$_.Name -eq "Name"})."#Text")
            $info.VersionMajor =( ($manifest.Project.Properties.Property | where {$_.Name -eq "VersionMajor"})."#Text")
            $info.VersionMinor = (($manifest.Project.Properties.Property | where {$_.Name -eq "VersionMinor"})."#Text")
            $info.VersionBuild =( ($manifest.Project.Properties.Property | where {$_.Name -eq "VersionBuild"})."#Text")

            
            # update for project name bug
            $ProjectNode = $manifest.Project.Properties.Property | where {$_.Name -eq 'Name'} 
            $newname = [System.IO.Path]::GetFileNameWithoutExtension($item)
            $ProjectNode.set_InnerXML($newname) 

            $info.XML = Format-XML $manifest.InnerXml    
            
            $OutputDirectory = "$ProjectDirectory\bin\$ProjectConfiguration\ispac"
            $binpath = "$ProjectDirectory\bin\"
            $info.OutDir = $OutputDirectory
            
            $testPath = Test-Path -PathType Container -path $binpath  -ErrorVariable ItemErr -ErrorAction SilentlyContinue ;
            
            if($testPath) {
                Get-ChildItem $binpath -Recurse -Force
                Remove-Item -Recurse -Force $binpath
            }
            New-Item -ItemType Directory -Force -Path $OutputDirectory
            $info.OutFile = "$OutputDirectory\@Project.manifest"
            
            $info.XML | Out-File $info.OutFile
            return $info
        }    
        else
        {
            $info.Error = "err: $ItemErr"
            return $info
        }

        #>

    return $info


}

function Add-Packages{
[CmdletBinding()]
    param(            
        [Parameter(Mandatory = $true)]
        [string]$ProjectDirectory,
        [Parameter(Mandatory = $true)]
        [string]$Bin
    )

        # Add-Manifest must be run first, we expect a clear bin dir from this (Re-Build ALL)
        $PackageFiles = Get-ChildItem -Path $ProjectDirectory -Filter "*.dtsx" -ErrorAction SilentlyContinue -Force  -Recurse      

        foreach($PackageFile in $PackageFiles)
        {
                    $item = $PackageFile.FullName
                    
                    Copy-Item -Path $item  -Destination $Bin ï¿½Recurse  -Force -Confirm:$False
        }
 
    

    
}

function Add-ConnectionManager{
[CmdletBinding()]
    param(            
        [Parameter(Mandatory = $true)]
        [string]$ProjectDirectory,
        [Parameter(Mandatory = $true)]
        [string]$Bin
    )

        # Add-Manifest must be run first, we expect a clear bin dir from this (Re-Build ALL)
        $PackageFiles = Get-ChildItem -Path $ProjectDirectory -Filter "*.conmgr" -ErrorAction SilentlyContinue -Force  -Recurse      

        foreach($PackageFile in $PackageFiles)
        {
                    $item = $PackageFile.FullName
                    
                    Copy-Item -Path $item  -Destination $Bin ï¿½Recurse  -Force -Confirm:$False
        }
 
    

    
}

function Add-Parameters{
[CmdletBinding()]
    param(            
        [Parameter(Mandatory = $true)]
        [string]$ProjectDirectory,
        [Parameter(Mandatory = $true)]
        [string]$Bin,
        [Parameter(Mandatory = $true)]
        [string]$ConfigurationValue
    )
        $configuration = Get-Configuration $ProjectDirectory $ConfigurationValue
        # Add-Manifest must be run first, we expect a clear bin dir from this (Re-Build ALL)
        $PackageFiles = Get-ChildItem -Path $ProjectDirectory -Filter "*.params" -ErrorAction SilentlyContinue -Force  -Recurse      
        $item = $PackageFiles[0].FullName # there will only ever be one of these

        
        # this section is a find/replace for the config value from the project file into the parms file
         [xml]$xmldata = get-content $item 
         $configurations = $xmldata.Parameters.Parameter 

         foreach($entry in $configurations)
         {
             $lookup=""
             $entryName = $entry.Name
             $valueproperty=$entry.Properties.Property | where {$_.Name -eq 'Value'}

             $lookup =  $configuration["Project::$entryName"]
         
             if($lookup -ne $null)
             {
                $newvalue = Clean-XML $lookup
                $valueproperty.set_InnerXML($newvalue)
             }
         
         }
        # end seciton

        # now copy the item over
         $out = format-XML $xmldata
         $out| Out-File "$Bin\Project.params"
        #Copy-Item -Path $item -Destination $Bin �Recurse -Force -Confirm:$False
     

        
    

    
}

function Add-ContentTypes{
[CmdletBinding()]
    param(            
        [Parameter(Mandatory = $true)]
        [string]$ProjectDirectory,
        [Parameter(Mandatory = $true)]
        [string]$Bin
    )

       $data = "<?xml version=""1.0"" encoding=""utf-8""?><Types xmlns=""http://schemas.openxmlformats.org/package/2006/content-types""><Default Extension=""dtsx"" ContentType=""text/xml"" /><Default Extension=""conmgr"" ContentType=""text/xml"" /><Default Extension=""params"" ContentType=""text/xml"" /><Default Extension=""manifest"" ContentType=""text/xml"" /></Types>"
 
       $data | Out-File -LiteralPath "$Bin\[Content_Types].xml" -Encoding "UTF8"

    
}

function Add-Ispac{
[CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$ProjectDirectory,            
        [Parameter(Mandatory = $true)]
        [string]$Bin
    )
    Add-Type -AssemblyName System.IO.Compression.FileSystem  > $null
    $parent = Split-Path -Path $Bin 
    $name = Split-Path -Path $ProjectDirectory -leaf 
    $ispac = "$parent\$name.ispac"
    [io.compression.zipfile]::CreateFromDirectory($Bin, $ispac)
    
    #clean up
    Get-ChildItem $Bin -Recurse -Force > $null
    Remove-Item -Recurse -Force $Bin  > $null

    return $ispac
}



<# HELPER ADDS on 7/25 #>
function Get-SSISDataType{
[CmdletBinding()]    
    Param(
       [string]$id
    )

$dataTypes = @{ "3"="Boolean";
                "6"="Byte";
                "16"="Datetime";
                "15"="Decimal";
                "14"="Double";
                "7"="Int16";
                "9"="Int32";
                "11"="Int64";
                "5"="SByte";
                "13"="Single";
                "18"="String";
                "10"="UInt32";
                "12"="UInt64";
                }

 $dataTypes.GetEnumerator() | ForEach-Object {
        if ($id -eq $_.Key)
        {
             return $_.Value
        }
    }




}

function Get-SSISValue{
[CmdletBinding()]    
    Param(
        [string]$type,
       [string]$value
    )

$dataTypes = @{ "Boolean"=$value;
                "Byte"=$value;
                "Datetime"=$value;
                "Decimal"=$value;
                "Double"=$value;
                "Int16"=$value;
                "Int32"=$value;
                "Int64"=$value;
                "SByte"=$value;
                "Single"=$value;
                "String"="N'$value'";
                "UInt32"=$value;
                "UInt64"=$value;
                }

 $dataTypes.GetEnumerator() | ForEach-Object {
        if ($type -eq $_.Key)
        {
             return $_.Value.ToString()
        }
    }




}

function Deploy-SSISEnvironment{
    [CmdletBinding()]    
    Param(

       [string]$IspacPath,
       [string]$TargetServer,
       [string]$FolderName,
       [string]$EnvironmentName


    )





     # Test out our connection to SQL (if we fail, we won't loop this stuff trying and failing for 30 min)
    $TimeStamp = (Invoke-Sqlcmd -Query "SELECT GETDATE() AS connected_as_of" -ServerInstance $TargetServer -Database "MSDB")
    If(!$TimeStamp)
    {
        Write-Host "Could not connect to $TargeServer"
        return
    }

    # create environment if it doesn't already exist
    Write-Host "Creating environment $EnvironmentName in $FolderName"
    $environmentid = Set-SSISEnvironment -Ensure "Present" -TargetServer $TargetServer -FolderName $FolderName -EnvironmentName $EnvironmentName
    Write-Host "Created environment $EnvironmentName in $FolderName with return code $environmentid"




    # unzip our ispac & get the parameters file
    Import-Module Cartwheel.IO
    Add-Type -AssemblyName System.IO.Compression.FileSystem
    $parent = Split-Path -Path $IspacPath
    $DirectoryPath = "$parent\ispac"
    Set-Directory $DirectoryPath "Absent" > $null
    [io.compression.zipfile]::ExtractToDirectory($IspacPath, $DirectoryPath)
    $configfiles = Get-ChildItem -Path $DirectoryPath -Filter "*.params" -ErrorAction SilentlyContinue -Force  -Recurse      
    $item = $configfiles[0].FullName # there will only ever be one of these
    [xml]$xmldata = get-content $item 

    $params = $xmldata.Parameters.Parameter
    $params | foreach-object {
            $variable = $_.Name
            $id = $_.Properties.Property | where{$_.Name -eq "ID"}
            $value = $_.Properties.Property | where{$_.Name -eq "Value"}
            $datatype = $_.Properties.Property | where{$_.Name -eq "DataType"}
  
    
            $info = @{
              "variable" = $variable; 
              "value" = $value.InnerXML;
              "datatype"=$datatype.InnerXML;
            }

   
            $dt = Get-SSISDataType $info.datatype
            $var = $info.variable
            $val = Get-SSISValue -type $dt -value $info.value 

            $sqlcmd = "
            DECLARE @environment_id bigint = $environmentid, @var sysname = N'$var', @env sysname = N'$EnvironmentName', @folder sysname = N'$FolderName',@dt sysname = N'$dt' ;
                IF EXISTS (SELECT 1 FROM [SSISDB].[catalog].[environment_variables] WHERE environment_id = @environment_id AND name = @var)
                BEGIN
                    EXEC [SSISDB].[catalog].[delete_environment_variable] @environment_name=@env, @folder_name=@folder, @variable_name=@var
                END
                ELSE
                BEGIN
                    EXEC [SSISDB].[catalog].[create_environment_variable] @variable_name=@var, @sensitive=False, @description=@var, @environment_name=@env, @folder_name=@folder, @value=$val, @data_type=@dt
                END
 
            "

            
    
            Invoke-Sqlcmd -Query $sqlcmd -ServerInstance $TargetServer -Database "MSDB" -Variable $sqlparams

    
    }
 

    



    #loop our parms file and deploy each to the environment
}

function Set-SSISFolder{

[CmdletBinding()]    
    Param(
        [Parameter(Mandatory)]
        [ValidateSet("Present", "Absent")]
        [string]$Ensure,
        [Parameter(Mandatory)]
        [string]$TargetServer,
        [Parameter(Mandatory)]
        [string]$FolderName
    )

 
 
 if ($Ensure -eq "Present") {
 
 $sqlcmdPresent = "
DECLARE @folder_id bigint
DECLARE @folder sysname = '$FolderName'

IF NOT EXISTS (SELECT 1 FROM [SSISDB].[catalog].[folders] WHERE name = @folder)
    BEGIN
        EXEC [SSISDB].[catalog].[create_folder] @folder_name=@folder, @folder_id=@folder_id OUTPUT
    END
    ELSE
    BEGIN
        SET @folder_id = (SELECT folder_id FROM [SSISDB].[catalog].[folders] WHERE name = @folder)
    END
SELECT @folder_id as folderid
"


 $folderid = (Invoke-Sqlcmd -Query $sqlcmdPresent -ServerInstance $TargetServer -Database "MSDB" ).folderid

 } 
 else {
  $envid = Set-SSISEnvironment -Ensure "Absent" -TargetServer $TargetServer -FolderName $FolderName   -RemoveAll

  $sqlcmdAbsent = "
DECLARE @folder_id bigint
DECLARE @folder sysname = '$FolderName'

IF EXISTS (SELECT 1 FROM [SSISDB].[catalog].[folders] WHERE name = @folder)
    BEGIN
        EXEC [SSISDB].[catalog].[delete_folder] @folder_name=@folder
        SET @folder_id = -1
    END
    ELSE
    BEGIN
        SET @folder_id = 0
    END
SELECT @folder_id as folderid
"


  $folderid = (Invoke-Sqlcmd -Query $sqlcmdAbsent -ServerInstance $TargetServer -Database "MSDB" ).folderid
 }
 
 
 
 

 return  $folderid

}

function Get-SSISFolder{

[CmdletBinding()]    
    Param(
        [Parameter(Mandatory)]
        [string]$TargetServer,
        [Parameter(Mandatory)]
        [string]$FolderName
    )

 

 
$sqlcmd = "
DECLARE @folder_id bigint
DECLARE @folder sysname = '$FolderName'
 
SET @folder_id = (SELECT folder_id FROM [SSISDB].[catalog].[folders] WHERE name = @folder)
 
SELECT isnull(@folder_id,0) as folderid
"


$folderid = (Invoke-Sqlcmd -Query $sqlcmd -ServerInstance $TargetServer -Database "MSDB" ).folderid


 
 
 
 

 return  $folderid

}

function Set-SSISEnvironment{

[CmdletBinding()]    
    Param(
        [Parameter(Mandatory)]
        [ValidateSet("Present", "Absent")]
        [string]$Ensure,
        [Parameter(Mandatory)]
        [string]$TargetServer,
        [Parameter(Mandatory)]
        [string]$FolderName,
        [string]$EnvironmentName,
        [switch] $RemoveAll
    )



# CRAZY AMOUNTS OF DUPLICATE CODE IN THIS ONE... NEED TO REFACTOR


 $folderid =(Get-SSISFolder -TargetServer $TargetServer -FolderName $FolderName)

if ($Ensure -eq "Present") {
 $folderid =(Set-SSISFolder -Ensure "Present" -TargetServer $TargetServer -FolderName $FolderName)

 $sqlcmdPresent = "
 
DECLARE @folder_id bigint = $folderid, @foldername sysname = '$FolderName', @env sysname = '$EnvironmentName';

IF NOT EXISTS (SELECT 1 FROM [SSISDB].[catalog].[environments] WHERE folder_id = @folder_id AND name = @env)
    BEGIN
        EXEC [SSISDB].[catalog].[create_environment] @folder_name=@foldername, @environment_name=@env
    END
    Select environment_id as environmentid from [SSISDB].[catalog].[environments] where name = @env AND folder_id = @folder_id
"


 $environmentid = (Invoke-Sqlcmd -Query $sqlcmdPresent -ServerInstance $TargetServer -Database "MSDB").environmentid
 } 
 else {

  

    if ($RemoveAll -and $folderid -ne 0)
    {
        #loop all environments
        $loopcode = "SELECT e.name as environmentnames FROM [SSISDB].[catalog].[environments] e where folder_id = $folderid"
        $environmentnames= (Invoke-Sqlcmd -Query $loopcode -ServerInstance $TargetServer -Database "MSDB" ).environmentnames
        foreach ($EnvironmentName in $environmentnames)
        {
            #recursive call
             $envid = Set-SSISEnvironment -Ensure "Absent" -TargetServer $TargetServer -FolderName $FolderName -EnvironmentName $EnvironmentName
        }

    }
    else
    {
        $sqlcmdAbsent = "
    
                DECLARE @folder_id bigint = $folderid, @foldername sysname = '$FolderName', @env sysname = '$EnvironmentName', @environment_id bigint;

                IF EXISTS (SELECT 1 FROM [SSISDB].[catalog].[environments] WHERE folder_id = @folder_id AND name = @env)
                    BEGIN
                        EXEC [SSISDB].[catalog].[delete_environment] @folder_name=@foldername, @environment_name=@env
                        SET @environment_id = -1
                    END
                    ELSE
                    BEGIN
                        SET @environment_id = 0
                    END
 
                    Select @environment_id as environmentid
    
                   "

#write-host $sqlcmdAbsent
        $environmentid = (Invoke-Sqlcmd -Query $sqlcmdAbsent -ServerInstance $TargetServer -Database "MSDB" ).environmentid
    }

  
 }


 return  $environmentid


}

function Remove-SSISProject{

# THIS IS NOT A SET SINCE WE DEPLOY THE PROJECTS, CAN'T CREATE THEM IN SQL
[CmdletBinding()]    
    Param(
        [Parameter(Mandatory)]
        [string]$TargetServer,
        [Parameter(Mandatory)]
        [string]$FolderName,
        [string]$ProjectName,
        [switch]$RemoveAll
    )





 $folderid =(Get-SSISFolder -TargetServer $TargetServer -FolderName $FolderName)

  

    if ($RemoveAll -and $folderid -ne 0)
    {
        #loop all environments
        $loopcode = "SELECT e.name as projectnames FROM [SSISDB].[catalog].[projects] e where folder_id = $folderid"
        $environmentnames= (Invoke-Sqlcmd -Query $loopcode -ServerInstance $TargetServer -Database "MSDB" ).projectnames
        foreach ($EnvironmentName in $environmentnames)
        {
            #recursive call
             $envid = Remove-SSISEnvironment -Ensure "Absent" -TargetServer $TargetServer -FolderName $FolderName -ProjectName $ProjectName
        }

    }
    else
    {
        $sqlcmdAbsent = "
    
                DECLARE @folder_id bigint = $folderid, @foldername sysname = '$FolderName', @proj sysname = '$ProjectName', @project_id bigint;

                IF EXISTS (SELECT 1 FROM [SSISDB].[catalog].[projects] WHERE folder_id = @folder_id AND name = @proj)
                    BEGIN
                        EXEC [SSISDB].[catalog].[delete_project] @folder_name=@foldername, @project_name=@proj
                        SET @project_id = -1
                    END
                    ELSE
                    BEGIN
                        SET @project_id = 0
                    END
 
                    Select @project_id as projecttid
    
                   "


        $projectid = (Invoke-Sqlcmd -Query $sqlcmdAbsent -ServerInstance $TargetServer -Database "MSDB" ).projectid
    }

  



 return  $projectid


}


<# ::: EXPORTED FUNCTIONS ::: #>
function Build-SSIS{

 param(
        [Parameter(Mandatory = $true)]
        [string]$ProjectDirectory,
         [Parameter(Mandatory = $true)]
        [string]$ConfigurationValue
        )


$dict = @{}

Write-Host "Discovering projects ..."
$projects = Get-ProjectFolders $ProjectDirectory #"C:\Users\derek.mckee\Documents\ETLFramework"
foreach($project in $projects)
{
    Write-Host "Found project: $project"
    Write-Host "Writing manifest ..."
    $manifest = Add-Manifest  $project $ConfigurationValue
    Write-Host "Writing packages ..."
    Add-Packages  $project $manifest.OutDir
    Write-Host "Writing connection managers ..."
    Add-ConnectionManager  $project $manifest.OutDir
    Write-Host "Writing parameters ..."
    Add-Parameters  $project $manifest.OutDir $ConfigurationValue
    Write-Host "Writing content types ..."
    Add-ContentTypes $project $manifest.OutDir
    Write-Host "Packing ispac ..."
    $ispacLocation = Add-Ispac  $project $manifest.OutDir



    $info = @{  'ispacLocation'=$ispacLocation;
                'ProjectLocation'=$project;
                'Configuration'=$ConfigurationValue;
                'BuildVersion'=[System.Version]::Parse($manifest.VersionMajor+"."+$manifest.VersionMinor+"."+$manifest.VersionBuild);

             }

    $dict.Add($manifest.ProjectName,$info)



    }
    return $dict
}

function Deploy-SSIS{

[CmdletBinding(DefaultParameterSetName='ByIspac')]
Param(
   [Parameter(Mandatory = $true)]
   [string]$TargetServerName,

   [Parameter(Mandatory = $true)]
   [string]$CatalogFolder,

   [Parameter(Mandatory = $true)]
   [string]$EnvironmentName,

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

   [Parameter(Mandatory = $true, ParameterSetName = 'ByBuild')]
   [System.Collections.Hashtable]$BuildOutput
   

)

if ($IspacPath)
{

# TODO: Remove ProjectName. This needs to be derived from the deployment file since they have to match for deployment to succeed.
Write-Host "Checking connectivity to server ..."

#getting project name
$ProjectName = (Split-Path -Path $IspacPath -leaf ).Replace(".ispac","")


Write-Host "Deploying folder, environment, and variables to server ..."
Deploy-SSISEnvironment -IspacPath $IspacPath -TargetServer $TargetServerName -FolderName $CatalogFolder  -EnvironmentName $EnvironmentName



# Local Variables
$SSISNamespace = "Microsoft.SqlServer.Management.IntegrationServices"
$ProjectFilePath = $IspacPath

# Load the IntegrationServices assembly
$loadStatus = [System.Reflection.Assembly]::Load("Microsoft.SQLServer.Management.IntegrationServices, "+
    "Version=14.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL")

# Create a connection to the server
$sqlConnectionString = `
    "Data Source=" + $TargetServerName + ";Initial Catalog=master;Integrated Security=SSPI;"
$sqlConnection = New-Object System.Data.SqlClient.SqlConnection $sqlConnectionString

# Create the Integration Services object
$integrationServices = New-Object $SSISNamespace".IntegrationServices" $sqlConnection

# Get the Integration Services catalog
$catalog = $integrationServices.Catalogs["SSISDB"]
$folder = $catalog.Folders[$CatalogFolder]

if($folder)
{
    Write-Host "Target folder exists ..."
}else
{
    Write-Host "Creating Catalog folder ..."
    # Create the target folder
    $folder = New-Object $SSISNamespace".CatalogFolder" ($catalog, $TargetFolderName,
        "Folder description")
    $folder.Create()
}


Write-Host "Deploying " $ProjectName " project ..."

# Read the project file and deploy it
[byte[]] $projectFile = [System.IO.File]::ReadAllBytes($ProjectFilePath)
$folder.DeployProject("$ProjectName".Trim(), $projectFile)

Write-Host "Done."

}

if($BuildOutput)
    {
        $builds.GetEnumerator() | foreach-object {  
            $ispaclocation = Get-HashProperty -HashTable  $builds -KeyName $_.key -PropertyName "ispacLocation"
            Deploy-SSIS -TargetServerName $TargetServerName -IspacPath "$ispaclocation" -CatalogFolder $CatalogFolder -EnvironmentName $EnvironmentName
        }
    }




}

function Get-SSISInstance {
    [CmdletBinding()]
    param()
        $Win32Name= "msdts*"
        $Win32Path=  "MsDtsSrvr.exe"
        $Instances = Get-WmiObject win32_service -computerName localhost | Where-Object { $_.Name -match $Win32Name -and $_.PathName -match $Win32Path } 
        return $Instances | Select Name,State
    }


















<#
# EXAMPLE USAGE
 
[string]$SourceFolder = "C:\Users\derek.mckee\Documents\ETLFramework"
[string]$ConfigurationValue = "production"
    Build-SSIS -ProjectDirectory $SourceFolder -ConfigurationValue $ConfigurationValue
 
 
[string]$TargetServerName=".\SQL_2017"
[string]$IspacPath="C:\Users\derek.mckee\Documents\ETLFramework\InfoMgmt DevOps Framework\EDW.SSIS.ETLEngine\bin\$ConfigurationValue\EDW.SSIS.ETLEngine.ispac"
[string]$DeploymentFolder="ETLEngine"
    Deploy-SSIS -TargetServerName $TargetServerName -IspacPath $IspacPath -CatalogFolder $DeploymentFolder -EnvironmentName $ConfigurationValue
 
 
 
 
#>