# Filename: extract-solution.ps1
param(
  [Parameter(Mandatory=$True)]
  [string]$OrgServiceUri,
  [Parameter(Mandatory=$True)]
  [string]$Username,
  [Parameter(Mandatory=$True)]
  #[string]$Domain,
  #[Parameter(Mandatory=$True)]
  [string]$Password,
  [Parameter(Mandatory=$True)]
  [string]$SolutionName,
  [switch]$checkout, #Optional – pass if you want to Check Out the existing files in the extract location
  [switch]$checkin #Optional – pass if you want to Check In the updated files after extraction
) 

$script_path = $myinvocation.mycommand.path
$script_folder = Split-Path $script_path -Parent
$project_path = Split-Path $script_folder -Parent
$solutionFilesFolder = Join-Path $project_path "source"
$log_path = Join-Path $project_path "logs"

$transcriptfile = "$log_path/extract-solution-transcript-$(get-date -f yyyyMMdd-HHmmss).log"
$logfile = "$log_path/extract-solution-sp_log$(get-date -f yyyyMMdd-HHmmss).log"

$ErrorActionPreference="SilentlyContinue"
Stop-Transcript | out-null
$ErrorActionPreference = "Stop"
Start-Transcript -path "$transcriptfile" -append

# CI Toolkit
$xrmCIToolkit = "$project_path/tools/Cmdlets/Xrm.Framework.CI.PowerShell.dll"
Write-Host "Importing CIToolkit: $xrmCIToolkit"
Import-Module $xrmCIToolkit

# TF.exe location
$tfCommand = "C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\tf.exe"

# SolutionPackager location
$solutionPackager = Join-Path $project_path "tools/solutionpackager.exe"

$connectionString = "url=$OrgServiceUri; Username=$Username; Password=$Password;"


Write-Host "TF.exe: $tfCommand"
Write-Host "SolutionPackager: $solutionPackager"
Write-Host "Solution Files Folder: $solutionFilesFolder"
Write-Host "ConnectionString: $connectionString"
Write-Host "Check In: $checkin"
Write-Host "Check Out: $checkout"

#Check Pending Changes
$pendingChanges = & "$tfCommand" status /recursive /noprompt "$solutionFilesFolder"
if ($pendingChanges -like "*no pending changes*")
{
    Write-Output $pendingChanges
}
else
{
    Write-Output $pendingChanges
    Write-Error "Pending Changes Detected. Undo your changes and try again."
    Write-Log "Pending Changes Detected. Undo your changes and try again."
    return
}
#Before Files
[string[]]$beforeFiles = [System.IO.Directory]::GetFileSystemEntries($solutionFilesFolder, "*", [IO.SearchOption]::AllDirectories)
#Write-Host "Before Files: " $beforeFiles
#Check Out
if ($checkout -and ($beforeFiles.Length -gt 0))
{
    & "$tfCommand" checkout /recursive /noprompt "$solutionFilesFolder"
}
#Export Solutions
Write-Host "Exporting Solution" 
$unmanagedSolution = Export-XrmSolution -ConnectionString $connectionString -Managed $False -OutputFolder $project_path -UniqueSolutionName $solutionName
Write-Host "Exported Solution: $unmanagedSolution"

Write-Host "Removing existing source files proactively before solution unpack"
#$removeoutput = Get-ChildItem "$solutionFilesFolder" -Filter *.dll -Recurse | Remove-Item
$removeoutput = Get-ChildItem "$solutionFilesFolder" -Recurse | Where-Object{!($_.PSIsContainer)} | Remove-Item 
Write-Host $removeoutput

#Solution Packager
$extractOuput = & "$solutionPackager" /action:Extract /zipfile:"$project_path\$unmanagedSolution" /folder:"$solutionFilesFolder" /errorlevel:warning /allowWrite:Yes /allowDelete:Yes /log:$logfile
#Write-Output $extractOuput

if ($lastexitcode -ne 0)
{
    throw "Solution Extract operation failed with exit code: $lastexitcode"
}
else
{
    if (($extractOuput -ne $null) -and ($extractOuput -like "*warnings encountered*"))
    {
        Write-Warning "Solution Packager encountered warnings. Check the output."
        #Write-Log "Solution Packager encountered warnings. Check the output."
    }
}

#After Files
[string[]]$afterFiles = [System.IO.Directory]::GetFileSystemEntries($solutionFilesFolder, "*", [IO.SearchOption]::AllDirectories)
#Write-Host "After Files: " $afterFiles

#Get the deltas
$deletedFiles = $beforeFiles | where {$afterFiles -notcontains $_}
$addedFiles = $afterFiles | where {$beforeFiles -notcontains $_}
if ($deletedFiles.Length -gt 0)
{
    #Write-Host "Deleted Files:" $deletedFiles
    $_files = [System.String]::Join(""" """, $deletedFiles)

    #we specifically DO NOT want to undo changes. we want any conflicts to surface here
	#& "$tfCommand" undo /noprompt "$_files"
    
	#& "$tfCommand" delete /noprompt "$_files"
	foreach ($delfile in $deletedFiles)
	{
		& "$tfCommand" delete /noprompt "$delfile"
	}
}
if ($addedFiles.Length -gt 0)
{
    #Write-Host "Added Files:" $addedFiles
    $_files = [System.String]::Join(""" """, $addedFiles)
    #& "$tfCommand" add /noprompt "$_files"
	foreach ($addfile in $addedFiles)
	{
		& "$tfCommand" add /noprompt /noignore "$addfile"
	}
}
# Checkin
if ($checkin)
{
    & "$tfCommand" checkin /recursive "$project_path"
}
Stop-Transcript
# End of script