Auto.ps1

#Set-StrictMode -Version Latest
#####################################################
# Auto
#####################################################
<#PSScriptInfo
 
.VERSION 0.21
 
.GUID 602bc07e-a621-4738-8c27-0edf4a4cea8e
 
.AUTHOR David Walker, Sitecore Dave, Radical Dave
 
.COMPANYNAME David Walker, Sitecore Dave, Radical Dave
 
.COPYRIGHT David Walker, Sitecore Dave, Radical Dave
 
.TAGS sitecore powershell local install iis solr
 
.LICENSEURI https://github.com/SitecoreDave/SharedSitecore.SitecoreLocal/blob/main/LICENSE
 
.PROJECTURI https://github.com/SitecoreDave/SharedSitecore.SitecoreLocal
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
- see README.md
 
#>


<#
.SYNOPSIS
Auto All The Things!
 
.DESCRIPTION
PowerShell script that helps you Automate All The Things!
 
.EXAMPLE
PS> Auto 'name'
 
PS> Auto az armtemplate.json
 
.EXAMPLE
PS> Auto 'name' 'template'
 
.EXAMPLE
PS> Auto 'name' 'template' 'd:\repos'
 
.Link
https://github.com/Radical-Dave/Auto
 
.OUTPUTS
    System.String
#>

[CmdletBinding(SupportsShouldProcess=$true)]
Param(
    [Parameter(Mandatory = $false, Position=0)]
    [string] $action = 'help',
    [Parameter(Mandatory = $false, Position=1)]
    [string] $data = '',
    [Parameter(Mandatory = $false, Position=2)]
    [string] $path = '',
    [string] $adApp = 'DevOps',
    [switch] $Force = $false
)
begin {
    $Global:ErrorActionPreference = 'Stop'
    $PSScriptName = ($MyInvocation.MyCommand.Name.Replace(".ps1",""))
    $PSScriptVersion = (Test-ScriptFileInfo -Path $MyInvocation.MyCommand.Path | Select-Object -ExpandProperty Version)
    $PSCallingScript = if ($MyInvocation.PSCommandPath) { $MyInvocation.PSCommandPath | Split-Path -Parent } else { $null }
    Write-Verbose "#####################################################"
    Write-Host "# $PSScriptRoot/$PSScriptName $($PSScriptVersion):$action $data $path called by:$PSCallingScript" -ForegroundColor White
    
    $StopWatch = New-Object -TypeName System.Diagnostics.Stopwatch
    $StopWatch.Start()
    Write-Verbose "path:$path"

    if (@('az','tf') -contains $action -and $data -ne "") {
        if (Test-Path "$PSScriptRoot\data\$action\$data\tasks\$data.json") {
            $path = "$PSScriptRoot\data\$action\tasks.json";
        } elseif (Test-Path "$PSScriptPath\data\$action\tasks\$data\$data.json") {
            $path = "$PSScriptPath\data\$action\$data\tasks.json";
        }
        $tasks = $path
    } else {
        if (!$path -and $action -ne 'az') {
            if (Test-Path "$PSScriptRoot/$PSScriptName.json") {
                $path = "$PSScriptRoot/$PSScriptName.json"
            } else {
                $profileParent =Split-Path $profile -Parent
                if (Test-Path "$profileParent/$($PSScriptName).json") {
                    $path = "$profileParent/$($PSScriptName).json"
                }
            }
        }
    }
    Write-Verbose "path:$path"
    #if (!(Test-Path $path)) {
    # throw "ERROR invalid path:$($path)"
    #}
    if ($path) {
        try {
            #$tasks = Get-Content .\auto.json | Out-String | Invoke-Expression
            $configFile = (Get-Content $path -Raw) | ConvertFrom-Json
            #Write-Host "config:$($config)"
        } catch {
            throw $_
        }
        Write-Verbose "logs:$($configFile.logs)"
        try {
            #Write-Verbose "checking tasks"
            $tasksNode = $configFile.psobject.properties["tasks"].value
            #Write-Verbose "checking props"
            #Write-Host "tasksNode:$($tasksNode)"
            $tasks = $tasksNode.PSObject.Properties
            #Write-Host "tasks:$($tasks)"
        } catch {
            Write-Verbose "NON-Critical? Error parsing task(s): $_"
        }
    }
    
    if (!$path) {
        if ((Test-Path "$PSScriptPath\data\$action\$data\tasks.json")) {
            $path = "$PSScriptPath\data\$action\$data\tasks.json";
        }
    }

    Write-Verbose "path:$path"
}
process {
    if ($action -eq 'add' -and $data.IndexOf('=') -gt -1) {
        Write-Host "add task:$data"
        $ds = $data.split('=')
        #if ($config.tasks["$data"]) {
            #if (!Force) {
            # throw "ERROR Task:$action already exists. Use -Force to overwrite."
            #} else {
            # $config.tasks | Add-Member -MemberType NoteProperty -Name "$($ds[0])" -Value "$($ds[1])" -PassThru -Force
            #}
        #} else {
            $configFile.tasks | Add-Member -MemberType NoteProperty -Name "$($ds[0])" -Value "$($ds[1])" -PassThru -Force
        #}
        $configFile | ConvertTo-Json | Out-File $path
    } elseif ($action -eq 'del' -or $action -eq 'delete' -and $data) {
        if (!$configFile -or !$configFile.tasks) {
            throw 'ERROR no config or config.tasks?'
        }
        Write-Host "delete task:$data"
        $configFile.tasks.PSObject.Properties.Remove("$data")
        $configFile | ConvertTo-Json | Out-File $path
    } else {
        $task = @()
        Write-Verbose "action:$action"
        if ($tasks -and $action -ne 'help') {
            $taskProperty = $tasks[$action]
            Write-Verbose "taskProperty:$taskProperty"
            if ($taskProperty) {
                $task = $taskProperty.value
            }
        }
        if ($task) {
            Write-Verbose "task:$task"
            if ($task -like '*$(data)*') {
                Write-Verbose "data:$data"
                $task = $task.replace('$(data)', "$($data)")
                #$task = $task -replace '$(data)', "$($data)"
            }
            Write-Verbose "task:$task"
            $cmd = $task
            Write-Verbose "cmd:$cmd"
            if ($cmd -like '~\*') {
                $cmd = (Join-Path (Split-Path $profile -Parent) ($task.Remove(0,2)))
            } elseif ($cmd -like '.\*') {
                $cmd = (Join-Path $PSScriptRoot ($task.Remove(0,2)))
            } elseif ($cmd.Substring(0,2) -eq '*\') {
                $name = $cmd.Remove(0,2)
                Write-Host "name:$name"
                $checkPath = $data
                if (!$checkPath) {
                    #$cmd = (Join-Path $PSScriptRoot ($task.Remove(0,2)))
                    $checkPath = "$(Split-Path $path -Parent)\data\tests\nested"
                }                
                
                Write-Host "checkPath:$checkPath"
                $cmd = Get-ChildItem "$checkPath\$name*" -Recurse | Select-Object FullName
                if (!$cmd) {
                    throw "ERROR could not find item $name in $checkPath -Recurse"
                }
            }
            Write-Host "Invoke:$cmd" -ForegroundColor White
            if (!$data) {
                Invoke-Expression -Command $cmd -OutVariable $results
            } else {
                Invoke-Expression -Command "$cmd $data" -OutVariable $results
            }
            Write-Host "RESULTS:$results"
        } else {
            #if ($action -ne 'help' -and $action -ne 'az' -and $action -ne 'tf') {
            if (@('help','az','tf','tfd','sql') -notcontains $action) {
                Write-Host "Task not found in $PSScriptName.json: $action, to add use: -addTask 'AutoScript'" -ForegroundColor White
            }
            if ($action -eq 'sql') {
                if(!$data) {$data = 'SELECT @@version'} #* FROM SYS.DATABASES #SYS_TABLES

                if ($path -notlike ';') {
                    #use config
                    $path = "Data Source=(local);Initial Catalog=.;Integrated Security=SSPI;"
                }

                Write-Host "RUN:$data"
                Write-Host "AGAINST:$path"
                
                Write-Host "path:$path"
                try {
                    $connection = New-Object system.data.sqlclient.sqlconnection        
                    Write-Verbose "[BEGIN ] Creating the SQL Command object"
                    $cmd = New-Object system.Data.SqlClient.SqlCommand
                    $connection.connectionstring = $path
                    $connection.open()

                    #join the connection to the command object
                    $cmd.connection = $connection
                    $cmd.CommandText = $data
                    
                    Write-Verbose "[PROCESS] Invoking $data"
                    if ($PSCmdlet.ShouldProcess($data)) {
                        
                        #determine what method to invoke based on the query
                        Switch -regex ($data) {
                            "^Select (\w+|\*)|(@@\w+ AS)" {                            
                                $reader = $cmd.executereader()
                                $out=@()
                                #convert datarows to a custom object
                                while ($reader.read()) {                                    
                                    $h = [ordered]@{}
                                    for ($i=0;$i -lt $reader.FieldCount;$i++) {
                                        $col = $reader.getname($i)                                            
                                        $h.add($col,$reader.getvalue($i))
                                    } #for
                                    $out += new-object -TypeName psobject -Property $h 
                                } #while

                                $out
                                $reader.close()
                                Break
                            }
                            "@@" { 
                                $cmd.ExecuteScalar()
                                Break
                            }
                            Default {
                                $cmd.ExecuteNonQuery() | Out-Null
                            }
                        }
                    }
                } 
                catch {
                    throw "ERROR $PSScriptName sql $data - $_" #-InformationVariable results
                }
            } elseif (@('az','tf','tfd') -contains $action) {
                Write-Host "RUN:$path"

                $envPrefix = ''
                #if ($action -eq 'tf') { $envPrefix = 'TF_VAR_'}
                if (@('tf','tfd') -contains $action) { $envPrefix = 'TF_VAR_'}
                
                #todo: finish working with Nick to use set-env (otherwise use set-envs)
                @((Split-Path $profile -Parent),$PSScriptRoot,("$currLocation" -ne "$PSScriptRoot" ? $currLocation : ''),$data