VisiPsLib.psm1

function Get-AgentJobHistoryTimeline { 

<#
 
.SYNOPSIS
Get Agent job history using dbaTools
 
.Description
 
 
.PARAMETER
SQLInstance
 
.PARAMETER
StartDate
 
.PARAMETER
EndDate
 
.EXAMPLE
 
#>
 
[CmdLetbinding()]
    Param (
        [string]$SQLInstance 
        ,
        [string]$StartDate = (Get-Date).Adddays(-1).toString('yyyy-MM-dd') + ' 20:00' 
        ,
        [string]$EndDate = (Get-Date).toString('yyyy-MM-dd') + ' 09:00'
    ) 
    Process{ 
        ($file = 'd:\temp\sqlAgentHistory.html' )
        get-DbaAgentJobHistory -SqlInstance $SQLInstance -StartDate $startDate -EndDate $endDate -ExcludeJobSteps | ConvertTo-DbaTimeline | Out-File $file -Encoding ASCII
        Invoke-Item $file
    } 
} 

function New-AsyncIndexDeploy  { 
<#
 
.SYNOPSIS
Builds all indexes in UpgradeBD asycnhroneously
 
.Description
 
Builds Async index from folder
Creates one self delete Agent job for each file in parameter folder
 
Path MUST contain a deploy.json file with dbn and job notification info
 
.PARAMETER
Path
Where to find files
 
.PARAMETER
SQLInstance
 
.EXAMPLE
New-AsyncIndex -Path 'D:\sources\mni\Projet One\One\Release 10.1\SQL\OneCash\800.UpgradeBD\300.Indexes' -srv ONECMR
 
gvsr
#>
 
[CmdLetbinding()]
    Param (

        [parameter(Mandatory=$false,position=0,ValueFromPipeline=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$SQLInstance 
        ,
        [parameter(Mandatory=$true,position=1)]
        [ValidateScript({test-path $_ })]
        [string]$path 
    ) 
    Process{ 

    # check for deploy.json
    ($deployFile = Join-Path -Path $path -ChildPath deploy.json )
    if ( -not ( test-path $deployFile )) { 
        throw "$deployFile not found " 
        return 
    } 

    # get info from deploy file
    ($deployInfo = get-content -path $deployFile | ConvertFrom-Json)

    # get files and create jobs
    Get-ChildItem $path -Recurse -file -filter *.sql | ForEach-Object { 
        Write-Box $_.BaseName  
        ($jobName = "## - $($_.BaseName)" )
        $command = $(Get-Content $_.FullName) -replace "'" , "''" 
        $outputFile = '$(ESCAPE_SQUOTE(SQLLOGDIR))\$(ESCAPE_SQUOTE(JOBNAME))_$(ESCAPE_SQUOTE(STEPID))_$(ESCAPE_SQUOTE(DATE))_$(ESCAPE_SQUOTE(TIME)).log'
        ($qry = "
        DECLARE @job_name SYSNAME = '$jobName'
        IF EXISTS ( SELECT 1 FROM sysjobs WHERE [name] = '$jobName')
            EXEC dbo.sp_delete_job @job_name = '$jobName'
        EXEC dbo.sp_add_job
            @job_name = @job_name,
            @enabled = 1,
            @description = null,
            @start_step_id = 1,
            @category_name = null,
            @category_id = null,
            @owner_login_name = 'sa',
            @notify_level_eventlog = 0,
            @notify_level_email = 1,
            @notify_level_netsend = 0,
            @notify_level_page = 0,
            @notify_email_operator_name = '$($deployInfo.Notification)',
            @delete_level = 1;
        EXEC dbo.sp_add_jobserver
            @job_name = @job_name;
        EXEC sp_add_jobstep
            @job_name = @job_name,
            @step_name = N'step_1',
            @subsystem = N'TSQL',
            @database_name = '$($deployInfo.database)' ,
            @command = N'$command' ,
            @output_file_name=N'$outputFile'
     ;
        --start job
        EXEC msdb.dbo.sp_start_job @job_name = '$jobName'
        "
)
        Invoke-Sqlcmd -ServerInstance $SQLInstance -Database msdb -Query $qry  -DisableVariables 
     } 
    }
} 

function Set-NewGUID_ApsVersionManager{

<#
.Synopsis
 
  Generate a guid and update the file "APSVersionManagerServer.xml" for applications
  OneOptic or OneCash
 
.Description
  Generate a guid and update the file "APSVersionManagerServer.xml" for applications
  OneOptic or OneCash.
 
.Parameter server
  targeted server
 
.Parameter Appli
  Application name (OneOptic or OneCash only)
  Select the GUID to modify
 
.Example
  Set-NewGUID_ApsVersionManager -server Vi099-S1 -Appli OneOptic
   
  .output file's name
  \\$server\c$\inetpub\APSVersionManager\APSVersionManagerServer.xml
 
#>

[CmdLetbinding()]

    param ([String]$server, [Validateset("OneOptic", "ArizonaCash")]$Appli)
    $XML_path = "\\$server\c$\inetpub\APSVersionManager\APSVersionManagerServer.xml"
    [XML]$XML = Get-Content -Path $XML_path 
     $1= ($xml.APSVersionManagerServerSettings.RegisteredApplication | Where-Object {$_.ApplicationName -eq $Appli} | select version)
    $guid = [guid]::NewGuid()
    $Newguid = "{"+$guid+"}"
    ### modification du APSVersionManagerServer.xml avec le nouveau GUID ###
    $XML_File = get-content -Path $XML_path 
     $XML_File = $XML_File -replace $1.Version , $Newguid 
     $XML_File |Out-File -FilePath $XML_path -Encoding utf8
    } 
    

function Get-VisiServersDev3 { 
<#
.SYNOPSIS
Returns Visilab Servers Dev3
.Description
Returns Visilab Servers Dev3 - including ACHA & CM
Alias gvsd3
.EXAMPLE
Get-VisiServersDev3
.EXAMPLE
gvsd3
#>
 
[CmdLetbinding()]
Param () 
    Process{ 
        Get-VisiServers -scope Dev3 -IncludeCentrale 
    } 
} 
Set-Alias -Name gvsd3 -Value Get-VisiServersDev3

function Get-VisiServersRec { 
<#
.SYNOPSIS
Returns Visilab Servers Rec
.Description
Returns Visilab Servers Rec - including ACHA & CM
Alias gvsr
.EXAMPLE
Get-VisiServersRec
.EXAMPLE
gvsr
#>
 
[CmdLetbinding()]
Param () 
    Process{ 
        Get-VisiServers -scope Rec -IncludeCentrale 
    } 
} 
Set-Alias -Name gvsr -Value Get-VisiServersRec 

function Get-VisiServersProd { 
<#
.SYNOPSIS
Returns Visilab Servers Prod
.Description
Returns Visilab Servers Prod - including ACHA & CM
Alias gvsr
.EXAMPLE
Get-VisiServersProd
.EXAMPLE
gvsr
#>
 
[CmdLetbinding()]
Param () 
    Process{ 
        Get-VisiServers -scope Prod -IncludeCentrale 
    } 
} 
Set-Alias -Name gvsp -Value Get-VisiServersProd 


function Get-VisiMagsRec { 
<#
.SYNOPSIS
Returns Visilab Mags Rec
.Description
Returns Visilab Mags Rec - without ACH or CM
Alias gvsr
.EXAMPLE
Get-VisiMagsRec
#>
 
[CmdLetbinding()]
Param () 
    Process{ 
        Get-VisiServers -scope Rec -ExcludeAchats
    } 
} 
Set-Alias -Name gvmr -Value Get-VisiMagsRec 

function Get-VisiMagsD3 { 
<#
.SYNOPSIS
Returns Visilab Mags Rec
.Description
Returns Visilab Mags Rec - without ACH or CM
Alias gvsr
.EXAMPLE
Get-VisiMagsRec
#>
 
[CmdLetbinding()]
Param () 
    Process{ 
        Get-VisiServers -scope Dev3 -ExcludeAchats
    } 
} 
Set-Alias -Name gvmd3 -Value Get-VisiMagsD3 



function Get-VisiMagsProd { 
<#
.SYNOPSIS
Returns Visilab Mags Prod
.Description
Returns Visilab Mags Prod - without ACH or CM
Alias gvmp
.EXAMPLE
Get-VisiMagsProd
.EXAMPLE
gvmp
#>
 
[CmdLetbinding()]
Param () 
    Process{ 
        Get-VisiServers -scope Prod -ExcludeAchats
    } 
} 
Set-Alias -Name gvmp -Value Get-VisiMagsProd



function Export-SimplexCMToStaging {
<#
.SYNOPSIS
Copies a distinct company from CM into Staging @ Mag
 
.Description
 
.PARAMETER Publication
Publication @ CM
 
.PARAMETER Destination
Destination Mag
 
.PARAMETER CompanyCode
CompanyCode @ CM
 
.EXAMPLE
Get-VisiServers -Scope REC
#>
 

[CmdLetbinding()]

    Param( 
        [parameter(Mandatory=$false,position=0,ValueFromPipeline=$true)]
        [string]$Publication
        ,
        [parameter(Mandatory=$true,position=10)]
        [ValidateNotNullOrEmpty()]
        [string]$Destination 
        ,
        [parameter(Mandatory=$true,position=10)]
        [ValidateNotNullOrEmpty()]
        [string]$CompanyCode 
    ) 

    Process {

        ## start transcription
            ($logFile  = Join-Path -Path "$env:LOCALAPPDATA\Log" -ChildPath "Export simplex CM 2 Staging - $publication to $destination - $(get-date -UFormat %Y-%m-%dT%H-%M-%S).log" ) 
            try{stop-transcript|out-null}
            catch [System.InvalidOperationException]{}
            if ($VerbosePreference -eq "Continue" ) { 
                Start-Transcript $logFile } 
            else { 
                Start-Transcript $logFile | Out-Null } 

        # get src_srv
        ($src_srv = Get-Publisher -srv $Destination)
        
        
        "Publication = {0} " -f $publication 

        # get src & tgt dbn
        #($src_dbn = (Get-DBARepPublication -sqlInstance $src_srv | ? PublicationName -eq $Publication).Database)
        ($src_dbn = (Get-DbaRepPublication -SqlInstance $src_srv -PublicationType Merge | ? publicationName -eq $Publication).Database ) 

        # create target staging db if not exists
        ($tgt_dbn = "SimplexStaging$Publication")
        Invoke-Sqlcmd -ServerInstance $Destination -Query "IF DB_ID('$tgt_dbn') IS NULL EXEC sys.sp_executeSQL N'CREATE DATABASE [$tgt_dbn]'" 
                
        # get company_Id
        if ($src_dbn -match 'cash') { 
            $sub_qry = "SELECT CR_Company_GUID as sub FROM ArizonaCASH.dbo.cr_company WHERE crcomp_code = '$CompanyCode'" } 
        else { 
            $sub_qry = "SELECT Company_Id as sub FROM Arizona.dbo.Company WHERE comp_code = '$CompanyCode' " } 

        ($sub = (Invoke-Sqlcmd -ServerInstance $src_srv -Query $sub_qry ).sub)
        if ([string]::IsNullOrEmpty($sub)) { 
            throw 'Company Id not found' } 

        # set script options
        $options = New-DbaScriptingOption
            $options.ScriptSchema = $true
            $options.IncludeIfNotExists  = $true
            $options.IncludeHeaders = $false
            $Options.ScriptBatchTerminator = $true
            $Options.ConvertUserDefinedDataTypesToBaseType  = $true
            $options.ClusteredIndexes = $true 
            $options.DRIAll = $false 

        # get tables to export
        ($tables_qry = "EXEC sp_get_repli_metadata @in_subsidiary_id = '$sub', @in_Publication = '$Publication', @in_table = '%', @repli_meta_data_version = 1, @in_debug = 0" )
        $tables = invoke-sqlcmd -ServerInstance $src_srv -Database $src_dbn -Query $tables_qry  

        # export schemas to tempdb and target db
        $srvx = New-Object ('Microsoft.SqlServer.Management.Smo.Server') -argumentlist $src_srv 
        $srvx.Databases[$src_dbn].Schemas | Export-DbaScript -ScriptingOptionsObject $options -Passthru | % { 
            Invoke-Sqlcmd -ServerInstance $Destination -Database $tgt_dbn -Query $_ 
            Invoke-Sqlcmd -ServerInstance $src_srv -Database tempdb -Query $_ 
            } 

        # truncate all tables in tgt staging
        $srvy = New-Object ('Microsoft.SqlServer.Management.Smo.Server') -argumentlist $Destination 
        $srvy.Databases[$tgt_dbn].Tables | %  { $_.TruncateData() } 


        # process tables
        foreach ($tbl in $tables | ? article -match '.*' | ? az_type -gt 1 ) {
            
            write-box $tbl.article_long_name

            # varii replace in from clause

            $tbl.from_clause = $tbl.from_clause -replace 'Or INS_company = 1' , ''  -replace 'HOST_NAME\(\)' , "'$sub'" 

            # copy data to tempdb @ src
            # NB replace 'OR INS_company = 1 " to avoid lines that would create a duplicate PK error when inserted in Az
            ($tqry = "DROP TABLE IF EXISTS tempdb.$($tbl.article_long_name) ; `nSELECT $($tbl.article_long_name).* INTO tempdb.$($tbl.article_long_name) `n$($tbl.from_clause )"  )
            Invoke-Sqlcmd -ServerInstance $src_srv -Database $src_dbn -Query $tqry -QueryTimeout 1000 
        
            # create table @ target
            # autoCreate in copy-dbabdTableData option fails :(
            Invoke-Sqlcmd -ServerInstance $Destination -Database $tgt_dbn -Query "DROP TABLE IF EXISTS $($tbl.article_long_name)" 
            Get-DbaDbTable -SqlInstance $src_srv -Database $src_dbn -Table $tbl.article_long_name | Export-DbaScript -ScriptingOptionsObject $options -Passthru | % { Invoke-Sqlcmd -ServerInstance $Destination -Database $tgt_dbn -Query $_ } 

            # copy tempdb table to tgt
            $params = @{
                SQLInstance = $src_srv
                Destination = $Destination 
                Database = 'tempdb' 
                DestinationDataBase = $tgt_dbn 
                Table = $($tbl.article_long_name)
                Truncate = $true 
                AutoCreateTable = $true 
                #query = $xQry
                BulkCopyTimeout = 1000
                KeepNulls = $true 
            } 
            Copy-DbaDbTableData @params 
        }
    } 

    End { 
        ## stop transcript
        try{stop-transcript|out-null}
        catch [System.InvalidOperationException]{}
    } 

} 


Function Get-VisiServers { 
<#
.SYNOPSIS
Returns Visilab Servers Dev, Rec or Prod
 
.Description
Returns Visilab Servers
 
.PARAMETER Scope
 
.PARAMETER IncludeCentrale
 
.PARAMETER ExcludeAchats
 
.PARAMETER IncludeCaisses
 
.PARAMETER ExcludePreviousRelease
 
.EXAMPLE
Get-VisiServers -Scope REC
#>
 

[CmdLetbinding()]
    Param (
        [parameter(Mandatory=$false,position=0)]
        [ValidateSet('Dev1','Dev2', 'Dev3', 'Rec', 'Prod', 'Arc4', 'Arc5' , 'Arc6' , ignorecase=$True)]
        [string] $scope = 'DEV1', 

        [parameter(Mandatory=$false,position=1)]
            [switch] $IncludeCentrale , 

        [parameter(Mandatory=$false,position=2)]
            [switch] $ExcludeAchats  ,

        [parameter(Mandatory=$false,position=3)]
            [switch] $IncludeCaisses , 

        [parameter(Mandatory=$false,position=4)]
            [switch] $Extended = $false  , 

        [parameter(Mandatory=$false,position=5)]
            [switch] $ExcludePreviousRelease = $false 


    ) #end param
    Begin {
            if ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { 
                $DebugPreference = "Continue" 
            } 
            else { 
                $DebugPreference = "SilentlyContinue" 
            } 
            $sl = @() 
    } 
    Process{ 

        ### DEV3
        if ( $scope -eq 'DEV3' ) {
            $sl = @('DEV3OM2', 'DEV3OM') 
            if ($IncludeCentrale.IsPresent){ 
                $sl  +=  'DEV3OCM' 
            } 
            # add SRV-SQLDEV3
            for ($i=0; $i -lt $sl.length; $i++){$sl[$i]=$('SRV-SQLDEV3\'+$sl[$i])}
        } 

        ## ARC4
        if ($scope -eq 'ARC4')  { 
            $sl = @('VI028-S1','VI031-S1','VI032-S1','VI035-S1','VI039-S1','VI040-S1','VI042-S1','VI047-S1','VI049-S1','VI050-S1')  
        }

        ## ARC5
        if ($scope -eq 'ARC5')  { 
            $qry = "
                SELECT s.server_name
                FROM msdb.dbo.sysmanagement_shared_registered_servers AS s
                JOIN msdb.dbo.sysmanagement_shared_server_groups AS g ON g.server_group_id = s.server_group_id
                WHERE g.name = 'Group #5' "
 
            Invoke-Sqlcmd -ServerInstance:SRV-DISTRIB -Query $qry | % { $sl += $_.server_name } 
        }

        ## ARC6
        if ($scope -eq 'ARC6')  { 
            $qry = "
                SELECT s.server_name
                FROM msdb.dbo.sysmanagement_shared_registered_servers AS s
                JOIN msdb.dbo.sysmanagement_shared_server_groups AS g ON g.server_group_id = s.server_group_id
                WHERE g.name = 'Group #6' "
 
            Invoke-Sqlcmd -ServerInstance:SRV-DISTRIB -Query $qry | % { $sl += $_.server_name } 
        }



        ### PROD
        if ($scope -eq 'PROD') { 
            $qry = ""
            if ($Extended.IsPresent) { 
                $qry = '
                    select *
                    from dbo.v_servers
                    where 1=1'

            } 
            else { 
                $qry = '
                    select server_name
                    from dbo.v_servers
                    where 1=1'

            } 

            if (-not($IncludeCentrale.IsPresent)) { 
                $qry += "
                    AND [server_name] <> 'SRV-ONECM'"

            } 

            if ($ExcludeAchats.IsPresent){ 
                $qry += "
                    AND [server_name] <> 'SRV-ACHATS' "

            } 

            if ($IncludeCaisses.IsPresent -and $Extended.IsPresent) { 
                $qry += "
                UNION
                SELECT
                    Company_ID
                    ,CompanyCode
                    ,COMP_short_name
                    ,Subsidiary_ID
                    ,SUB_short_name
                    ,SUB_code
                    ,sub_company
                    ,Organizational_unit_ID
                    ,OU_code
                    ,OU_short_name
                    ,System_site_ID
                    --,Server_name
                    ,CRPOS_Name AS server_name
                FROM dbo.v_caisses "

            } 

            if ($IncludeCaisses.IsPresent -and -not($Extended.IsPresent)) { 
                $qry += "
                UNION
                SELECT CRPOS_NAME
                FROM dbo.v_caisses "

            } 

            #run query
            Write-Debug $qry 
            if ($Extended.IsPresent) { 
                Invoke-Sqlcmd -ServerInstance:SRV-ONECM -database Arizona -Query $qry | % { $sl += $_ } 
            } 

            else { 
                Invoke-Sqlcmd -ServerInstance:SRV-ONECM -database Arizona -Query $qry | % { $sl += $_.server_name } 
            } 

        } 

        ### DEV1
        if ( $scope -eq 'DEV1' ) {
            $sl = @('DEV1OM', 'DEV1OM2') 
            $sl +=  'DEV1OM3'
            $sl +=  'DEV1OW' 
            if (-not($ExcludeAchats.IsPresent)) { 
                $sl  +=  'DEV1OA'
            } 
            if ($IncludeCentrale.IsPresent){ 
                $sl  +=  'DEV1OCM' 
            } 

            if ( $IncludeCaisses.IsPresent) { 
                $sl += @('DEV1OC1','DEV1OC2','DEV1OC3')
            } 

            # add SRV-ONEDEV2
            for ($i=0; $i -lt $sl.length; $i++){$sl[$i]=$('SRV-SQLDEV1\'+$sl[$i])}
        } # end if dev1

        ### REC
        if ( $scope -eq 'REC' ) {
            
            
            $sl = @('SRV-MAG1', 'SRV-MAG2', 'SRV-ONEWEBR','SRV-ATHOMER','SRV-ATWORKR','SRV-PV1','SRV-PV2') 

            if (-not($ExcludePreviousRelease.IsPresent)) { 
                $sl += 'SRV-MAG3' 
            } 

            if (-not($ExcludeAchats.IsPresent)) { 
                $sl  +=  'SRV-ACHATSR'
            } 
            if ($IncludeCentrale.IsPresent){ 
                $sl  +=  'SRV-ONECMR' 
            } 

            if ( $IncludeCaisses.IsPresent) { 
                $sl += @('MAG2-C1','MAG1-C1','PV1-C1','MAG3-C1','PV2-C1')
            } 


        } # end if REC

        ### DEV2
        if ( $scope -eq 'DEV2' ) {
            $sl = @('DEV2OM', 'DEV2OW','DEV2OM2','DEV2OM3') 
            if (-not($ExcludeAchats.IsPresent)) { 
                $sl  +=  'DEV2OA'
            } 
            if ($IncludeCentrale.IsPresent){ 
                $sl  +=  'DEV2OCM' 
            } 
            if ( $IncludeCaisses.IsPresent) { 
                $sl += @('DEV2OC1','DEV2OC2','DEV2OC3')
            }
            for ($i=0; $i -lt $sl.length; $i++){$sl[$i]=$('SRV-SQLDEV2\'+$sl[$i])}
        } # end if DEV2


    } # end process

    End {
        return $sl | Sort-Object 
    } 
} 






Function Update-StatsParallel { 
[CmdLetbinding()]
#############################################################
#
#
# Function Visi_UpdateStatsParallel
#
# 2018-09-18 MNI Created
#
#############################################################
Param (
        [parameter(Mandatory=$false,position=0)]
        [string] $srv = $env:COMPUTERNAME
        ,
        [parameter(Mandatory=$true,position=1)]
        [string] $dbn 
        ,
        [parameter(Mandatory=$true,position=2)]
        [string] $table 

    ) # end param
    
    Process { 
        # check trace Flag 7471 stop if not set
        $qryCheckTraceFlag = "
        IF OBJECT_ID('tempdb.dbo.#t7471') IS NOT NULL
            DROP TABLE #t7471;
        CREATE TABLE #t7471([traceFlag] SYSNAME, [status] INT, [global] INT, [session] INT ) ;
 
        INSERT #t7471
        EXEC sys.sp_executeSQL N'DBCC TRACESTATUS (7471) WITH NO_INFOMSGS '
 
        IF NOT EXISTS (
            SELECT *
            FROM #t7471
            WHERE traceFlag = 7471 AND STATUS = 1
        )
        BEGIN
            RAISERROR('TraceFlag 7471 not set. Execution stopped', 16, -1) ;
            RETURN ;
     
        END
        "
 
        Write-Verbose $qryCheckTraceFlag 
        Invoke-Sqlcmd -ServerInstance $srv -Database $dbn -Query $qryCheckTraceFlag -Verbose -ErrorAction Stop 


        # log start
        $qryLog = "
        DECLARE @logId UNIQUEIDENTIFIER;
        EXEC dbo.sp_Save_VisiSys_Log @Id = @logId OUTPUT ,@Domain = 'UPDATE STATISTICS',@Module = '$table', @note = '$dbn', @message = 'parallel XXL';
        SELECT @logId AS [logid]; "

        $logId = (Invoke-Sqlcmd -ServerInstance $srv -Database $dbn -Query $qryLog -Verbose -ErrorAction Stop ).logId


        # get stats and create jobs
        $qryStats  = "
        DECLARE @id BIGINT = OBJECT_ID('$table','U')
        SELECT s.name AS statName
        FROM sys.[stats] AS s
        WHERE s.[object_id] = @id "

        $stats = (Invoke-Sqlcmd -ServerInstance $srv -Database $dbn -Query $qryStats -Verbose -ErrorAction Stop ).statName 

        foreach ($stat in $stats) { 
            $command  = "
            UPDATE STATISTICS $table [$stat] WITH FULLSCAN,MAXDOP=0;
            EXEC dbo.sp_Save_VisiSys_Log @Id = ''$logId'';
            "

            $desc = "Update statistics for table $table ; Generated by PS Script ; Contact: MNI" 
            $job_name = "## Update STATS $table $stat " 
            $outputFile = '$(ESCAPE_SQUOTE(SQLLOGDIR))\$(ESCAPE_SQUOTE(JOBNAME))_$(ESCAPE_SQUOTE(STEPID))_$(ESCAPE_SQUOTE(DATE))_$(ESCAPE_SQUOTE(TIME)).log'

            $qry  = "
            DECLARE @job_name SYSNAME = '$job_name'
 
            IF EXISTS ( SELECT 1 FROM msdb.dbo.sysjobs AS j WHERE j.name = @job_name)
                EXEC msdb.dbo.sp_delete_job @job_name=@job_name, @delete_unused_schedule=1;
            EXEC msdb.dbo.sp_add_job
                @job_name=@job_name,
                @enabled=1,
                @notify_level_eventlog=0,
                @notify_level_email=2, --2=on fail 3=always
                @notify_level_netsend=0,
                @notify_level_page=0,
                @delete_level=1, -- 0=never, 1=after run
                @description='$desc',
                @category_name=N'[Uncategorized (Local)]',
                @owner_login_name=N'sa',
                @notify_email_operator_name=N'DBA';
 
            EXEC msdb.dbo.sp_add_jobstep
                @job_name = @job_name,
                @step_name=N'step_1',
                @step_id=1,
                @cmdexec_success_code=0,
                @on_success_action=1,
                @on_success_step_id=0,
                @on_fail_action=2,
                @on_fail_step_id=0,
                @retry_attempts=0,
                @retry_interval=0,
                @os_run_priority=0, @subsystem=N'TSQL',
                @command=N'$command',
                @database_name=N'$dbn',
                --@output_file_name=N'$outputFile' ,
                @flags=0;
                  
 
            EXEC msdb.dbo.sp_update_job @job_name = @job_name, @start_step_id = 1;
            EXEC msdb.dbo.sp_add_jobserver @job_name = @job_name, @server_name = N'(local)';
            "
 
            ## create job
            $job_name 
            Invoke-Sqlcmd -ServerInstance $srv -Database $dbn -Query $qry -DisableVariables 
    
            ## start job
            $start_job = "exec msdb.dbo.sp_start_job @job_name = '$job_name'" ; 
            Invoke-Sqlcmd -ServerInstance $srv -Query $start_job 
        } 
    } #end process
} #end function


Function Add-CMAGroup { 
#############################################################
#
# Function Add_to_CMA_Group
# --------------------------------------------------------------------
#
# ---------------------------------------------------------------------
# History:
# 2018-02-19 MNI Creation
#
#############################################################
[cmdletbinding()] 
Param( 
    [parameter(Mandatory=$true,position=0)]
    [ValidateScript({invoke-sqlcmd -serverInstance $_ -query "select 1" -ConnectionTimeout 3 })] 
    [string] $CMAsrv 
    ,
    [parameter(Mandatory=$true,position=1)]
    #[ValidateNotNull]
    [string] $group 
    ,
    [parameter(Mandatory=$true,position=2)]
    #[ValidateNotNull]
    [string] $parentGroup 
    ,
    [parameter(Mandatory=$true,position=3)]
    #[ValidateNotNull]
    $hostList  
) # end param
    Process {
        If ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { 
            $DebugPreference = "Continue" 
        } 
        else { 
            $DebugPreference = "SilentlyContinue" 
        } 
        Write-Debug $("Group = {0} | ParentGroup = {1} " -f $group, $parentGroup) 
        $dbn = 'MSDB' 

        ## resolve groupId
        $qry = "
        DECLARE @group SYSNAME = '$group' ;
        DECLARE @parentGroup SYSNAME = '$parentGroup';
        DECLARE @groupId INT = -1;
 
        SELECT @groupId = g.server_group_id
        FROM dbo.sysmanagement_shared_server_groups AS g
        JOIN dbo.sysmanagement_shared_server_groups AS gp ON g.parent_id = gp.server_group_id
        WHERE g.name = @group
        AND gp.name = @parentGroup;
       
        IF @groupId = -1
        BEGIN
            RAISERROR('Group [%s] not found ' , 16, -1, @group) ;
            RETURN ;
        END
        SELECT @groupId AS groupId;
        "
 
        $groupId = (invoke-sqlcmd -ServerInstance $CMAsrv -Database $dbn -Query $qry -ea Stop ).groupId 
        Write-Debug $("GroupId = {0} " -f $groupId ) 

        ##proceed to inserting rows
        foreach ($host in $($hostList | sort-object) ) { 
            $qry = "INSERT INTO dbo.sysmanagement_shared_registered_servers_internal
            (server_group_id,name,server_name,[description],server_type)
            VALUES($groupId,'$host','$host','$host',0)"
 
            Write-Debug $qry 
            invoke-sqlcmd -ServerInstance:$CMAsrv -Database:$dbn -Query:$qry -Verbose -ea Stop 
        } 

        #>




    } #end Process
} #end function

function Disable-LogShipping {

#############################################################
#
# Function Disable-LogShipping
# --------------------------------------------------------------------
#
# ---------------------------------------------------------------------
# History:
# 2017-12-22 MNI Creation
# 2019-04-18 MNI Nouvelle version avec bds Arizona et Archive
#
#############################################################
[CmdletBinding()] 
    Param( 
        [parameter(Mandatory=$false,position=0)]
        [ValidateSet('Az','Arc', 'Both', ignorecase=$True)]
        [string] $scope = 'Both'
    ) 
    Begin {
        #If ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) {
        # $DebugPreference = "Continue" }
        #else {
        # $DebugPreference = "SilentlyContinue" }
    } 
    Process { 
        $srv = 'SRV-ONEMIRROR' 
        $SMOserver = New-Object ('Microsoft.SqlServer.Management.Smo.Server') -argumentlist $srv -ErrorAction Stop 

        switch ($scope) { 
            'Az'  { $jobs = $SMOserver.JobServer.Jobs | ? {$_.Name -match '^LSRestore.*Arizona$'} } 
            'Arc'  { $jobs = $SMOserver.JobServer.Jobs | ? {$_.Name -match '^LSRestore.*Archive$'} }
            'Both'  { $jobs = $SMOserver.JobServer.Jobs | ? {$_.Name -match '^LSRestore'} }
        } 
        #Write-Debug $jobs | select Name

        $jobs | % { 
            Box $_.Name 
            "JobName = [{0}] | Status before = [{1}] " -f $_.Name , $_.IsEnabled 
            "Altering job status, please wait..." 
            $_.IsEnabled = $false 
            $_.Alter() 
            "JobName = [{0}] | Status after = [{1}] " -f $_.Name , $_.IsEnabled 
        }
    } # end process
} # end function

Function dbBuild_basic_v2 { 
<#
.SYNOPSIS
Visilab SQL Db Build
 
.Description
Builds a given releasePath ( folder or object) against a SQL database
Version 0.9.23
    - parameter SkipGetLatest deprecated
    - default behaviour will NOT get latest from TFS, -GetLAtest parameter added to force this operation
 
.PARAMETER ReleasePath
The path or object to build
 
.PARAMETER srv
Target SQL Server
 
.PARAMETER dbn
Target Database
 
.PARAMETER BuildAction
Choose among New, UpgradeDB, UpgradeBoth or PartialBuild
Default Partial Build
 
.PARAMETER SkipGetLatest
Will NOT perform a tf get if specified
Deprecated - replaced by -GetLatest
 
.PARAMETER NoTranscript
Will NOT save the build details in D:\MSSQL\SQLJobsLog if present
 
.PARAMETER DisableVisiSysLog
Will NOT write to Visisys.Log if present
 
.PARAMETER BuildInfo
Will return a hash containing the build result ( used for nightly build logging )
 
.PARAMETER GetLatest
Will perform a TFS GET -recursive on the provided releasePath
 
.PARAMETER IncludeIndex
Will include any file having INDEX in the name
Index files are excluded by default
 
.EXAMPLE
Build-VisiDB -srv SRV-ONECMR bla bla bla
#>


    [cmdletbinding()] 
    Param( 
        [parameter(Mandatory=$true,position=0)]
        [ValidateScript({test-path $_ })]
        [string] $ReleasePath  
        ,
        [parameter(Mandatory=$true,position=1,valueFromPipeline=$true )]
        [ValidateNotNullOrEmpty()]
        [string] $srv 
        ,
        [parameter(Mandatory=$false,position=2)]
        [string] $dbn = 'Arizona' 
        , 
        [parameter(Mandatory=$false,position=3)]
        [ValidateSet('New','UpgradeBD', 'UpgradeSOFT', 'UpgradeBOTH', 'PartialBuild', ignorecase=$True)]
        [string] $buildAction = 'PartialBuild' 
        , 
        [parameter(Mandatory=$false,position=4)]
        [switch] $GetLatest = $false 
        ,
        [parameter(Mandatory=$false,position=5)]
        [switch] $noTranscript = $false   
        ,
        [parameter(Mandatory=$false,position=6)]
        [switch] $disableVisiSysLog = $false   
        ,
        [parameter(Mandatory=$false,position=7)]
        [hashtable]$buildInfo = @{} 
        ,
        [parameter(Mandatory=$false,position=6)]
        [switch] $IncludeIndex = $false   

    ) # end param

    Begin   {
        If ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { $DebugPreference = "Continue" } 
        else { $DebugPreference = "SilentlyContinue" } 
    } 
    Process { 
        ## attempt to stop transcription
        if (-not($noTranscript.IsPresent)) { 
            try{stop-transcript|out-null}
            catch [System.InvalidOperationException]{}
        } 

        ## clear errors
        $Global:Error.Clear() 
        
        ## start transcription
        if (-not($noTranscript.IsPresent)) { 
            $logFile  = Join-Path -Path D:\MSSQL\SQLJobsLog -ChildPath "Build_$($dbn)_$(Split-Path $ReleasePath -Leaf)_$($buildAction)_$($srv).$($(Get-Date -Format s ) -ireplace ':', '-' ).log" 
            Write-Debug $("Log file = {0}" -f $logFile ) 
            if ($VerbosePreference -eq "Continue" ) { 
                Start-Transcript $logFile } 
            else { 
                Start-Transcript $logFile | Out-Null } 
        } 
        try { 
            ### get latest from TFS
            if ($GetLatest.IsPresent) { 
                if ($VerbosePreference -eq "Continue" ) { tf get $ReleasePath /recursive } 
                else { tf get $ReleasePath /recursive  | Out-Null } 
                Write-Debug "TF Get Ok " 
            } # end if NoGet

            ##get last changeSet
            try { $changeSet = @(tf history $ReleasePath /stopafter:1 /noprompt /recursive)[2].Split(' ')[0] } 
            catch { $changeSet = -1 } 
            Write-Debug "Get Changeset ok, changeset = $changeSet" 

            ### get relPath files to build

            Write-Debug "$buildAction build starting" 
            $exclude = 'NORUN|INDEX'
            switch ($buildAction.ToUpper()) { 
                'NEW'         { $files = gci -Path $ReleasePath -Recurse -File -Filter *.sql | ? {$_.FullName -imatch '100\.New' -and $_.FullName -inotmatch $exclude } } 
                'PARTIALBUILD'{ $files = gci -Path $ReleasePath -Recurse -File -Filter *.sql | ? {$_.FullName -inotmatch $exclude } } 
                'UPGRADEBD'   { $files = gci -Path $ReleasePath -Recurse -File -Filter *.sql | ? {$_.FullName -imatch '800\.UpgradeBD' -and $_.FullName -inotmatch $exclude } }
                'UPGRADESOFT' { $files = gci -Path $ReleasePath -Recurse -File -Filter *.sql | ? {$_.FullName -imatch '801\.Upgrade' -and $_.FullName -inotmatch $exclude } }
                'UPGRADEBOTH' { $files = gci -Path $ReleasePath -Recurse -File -Filter *.sql | ? {($_.FullName -imatch '801\.Upgrade' -or $_.FullName -imatch '800\.UpgradeBD' )  -and $_.FullName -inotmatch $exclude } } 
            } 
            Write-Debug $("Release path = {0} " -f $ReleasePath )
            Write-Debug $("Files OK Count = {0} " -f $($files.Count)) 

            ## check if there is something to build
            if ($files.Count -eq 0) { 
                Write-Warning "No files to build were found"
            }
    
            ### log build start on target server
            Write-Debug 'Log build start ' 
            try { $qry = "DECLARE @log_id UNIQUEIDENTIFIER; EXEC dbo.sp_Save_VisiSys_Log @Id=@log_id OUTPUT,@Domain='DB_Build',@Module='$dbn',@Message='$ReleasePath',@note='$buildAction',@RowCount='$changeSet';SELECT @log_id as log_id;" 
                  write-debug $qry 
                  $log_id = (Invoke-Sqlcmd -ServerInstance:$srv -Query:$qry ).log_id  } # end try
            catch { Write-Debug "VisiSys.Log failed "; $_.Exception.Message } 
    
            ## start building
            try { 
                foreach ($file in $files | Sort-Object { $_.FullName -replace "\W", 'z' }) { 
                    $($srv + '.' + $dbn + " " +  [char]0x21e8 + " " + $(split-path  $(Split-Path $file.FullName ) -leaf) + '/' + $file.BaseName)
                    Write-Debug $($file.DirectoryName -replace '^d\:\\sources\\\w+\\', '' ) 
                    Invoke-Sqlcmd -ServerInstance:$srv -Database:$dbn -InputFile:$($file.FullName) -QueryTimeout:10000 
                    Write-Debug "--- Build object OK `n" 
                } 
                
                ## gather build info
                $buildInfo.FileCount = $($files.Count) 
                
                ### log build OK
                $qry = "EXEC dbo.sp_Save_VisiSys_Log @Id = '$log_id', @note = '$buildAction OK', @status='0'" 
                write-debug $qry 
                try { Invoke-Sqlcmd -ServerInstance:$srv -Query $qry } 
                catch { write-debug "VisiSys log failed" ; $_.Exception.Message } 
            } #end try
            catch { 
               ## gather custom error info
                   $buildInfo.Message=$_.Exception.Message 
                   $buildinfo.File = $file.Name
                   $buildInfo.Dir = $file.DirectoryName
                   $buildInfo.ts = get-date 
               
               #### log db build error
               write-debug " --- Log build NOK" 
               $qry ="EXEC dbo.sp_Save_VisiSys_Log @Id='$log_id',@note='Build $buildAction FAILED',@status= '1',@remark='$($buildInfo.Message -replace "'", "''")',@fileName='$($file.Name)',@parent='$($file.DirectoryName)'" 
               Write-Debug $qry 
               try {Invoke-Sqlcmd -ServerInstance:$srv -Query $qry } 
               catch { write-debug "Visisys log failed"; $_.Exception.Message } 
               
               ##throw error
               throw "Build failed | $($buildInfo.file) | $($buildinfo.Message) | $($buildInfo.Dir)" 

            } #end catch
        } # end outer try
     
        finally { 
            if (-not($noTranscript.IsPresent)) { 
                if ($VerbosePreference -eq "Continue" ) { Stop-Transcript } 
                else { Stop-Transcript | Out-Null } 
            } #end if
        } #end outer finally
    } #end process
} #end function
Set-Alias -Name Build-VisiDb -Value dbBuild_basic_v2



Function Build_VisiSQLCommonTools { 
<#
.SYNOPSIS
Builds Visilab SQL common tools
$/Projets BDD/70 - Common Tools and Helpers
 
.Description
Builds Visilab SQL common tools
$/Projets BDD/70 - Common Tools and Helpers
 
.PARAMETER Scope
 
.PARAMETER IncludeCentrale
 
.PARAMETER ExcludeAchats
 
.PARAMETER IncludeCaisses
 
.PARAMETER ExcludePreviousRelease
 
.EXAMPLE
Get-VisiServers -Scope REC
#>
 
[cmdletbinding()] 
    Param (
        [parameter(Mandatory=$false,position=0,ValueFromPipeline=$true)]
        #[ValidateScript({invoke-sqlcmd -serverInstance $_ -query "select 1" -ConnectionTimeout 1 })]
        [string] $srv = $env:COMPUTERNAME
        ,
        [parameter(Mandatory=$false,position=1)]
        [ValidateScript({test-path $_})] 
        [string] $relPath = "D:\Sources\MNI\Projets BDD\70 - Common Tools and Helpers"
        ) 
    Process {
    
        #THROW ' Replaced by Build-SQLCommonTools in VisiPsLib
        If ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { $DebugPreference = "Continue" } 
        else { $DebugPreference = "SilentlyContinue" }        

        #start by building sp_save_visiVersion
        $file = gci -Path $relPath -Filter *sp_save_visiVersion* -File 
        invoke-sqlcmd -ServerInstance $srv -InputFile $file.FullName -ea Stop 
        
        #proceed to build all others
        Build-VisiDb -srv $srv -buildAction PartialBuild -dbn Master -ReleasePath $relPath -ea Stop 

    } # end process
} # end function
Set-Alias -Name Build-SQLCommonTools -value Build_VisiSQLCommonTools





Function New-RefreshDev { 
[CmdLetbinding()]
    Param (
        [parameter(Mandatory=$false,position=0,ValueFromPipeline=$true)]
        [ValidateNotNullOrEmpty() ]
        [string] $destination  
    ) #end param

    Begin {
        if ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { $DebugPreference = "Continue" 
        } 
        else { $DebugPreference = "SilentlyContinue" 
        } 
        
        #log file
        $log = "d:\MSSQL\SQLJobsLog\RefreshRecette.$($destination).$(get-date -f yyyy-MM-dd).log"
        
        #stop-transcript
        try{
          stop-transcript|out-null
        }
        catch [System.InvalidOperationException]{}
        Start-Transcript -Path $log -Append 
    } 
    Process{ 
    
        #load hash table
        $h = @{} 

        $h.Add('DEV1OA'     , @('SRV-ACHATSR'  , @('VisiTemp','Arizona','ArizonaCASH','Archive'))) 
        # demander a ADE pour VisiPeriph
        $h.Add('DEV1OCM' , @('SRV-ONECMR'    , @('VisiTemp','Arizona','ArizonaCASH','Archive','Elvira','ElviraPV','VisiTemp','OneImport','OneShare','OneShareArchive')))
                                                
        $h.Add('DEV1OM'     , @('SRV-MAG1'        , @('VisiTemp','Arizona','ArizonaCASH','Archive')))
        $h.Add('DEV1OM2' , @('SRV-PV1'        , @('VisiTemp','Arizona','ArizonaCASH','Archive')))
        $h.Add('DEV1OM3' , @('SRV-ATWORKR'  , @('VisiTemp','Arizona','ArizonaCASH','Archive')))
        $h.Add('DEV1OW'     , @('SRV-ONEWEBR'  , @('VisiTemp','Arizona','ArizonaCASH','Archive')))
                                                 
                                                 
        $h.Add('DEV2OA'     , @('SRV-ACHATSR'  , @('VisiTemp','Arizona','ArizonaCASH','Archive'))) 
        # demander a ADE pour VisiPeriph
        $h.Add('DEV2OCM' , @('SRV-ONECMR'    , @('VisiTemp','Arizona','ArizonaCASH','Archive','Elvira','ElviraPV','VisiTemp','OneImport','OneShare','OneShareArchive')))
                                                 
        $h.Add('DEV2OM'     , @('SRV-MAG1'        , @('VisiTemp','Arizona','ArizonaCASH','Archive')))
        $h.Add('DEV2OM2' , @('SRV-PV1'        , @('VisiTemp','Arizona','ArizonaCASH','Archive')))
        $h.Add('DEV2OM3' , @('SRV-MAG3'     , @('VisiTemp','Arizona','ArizonaCASH','Archive')))
        $h.Add('DEV2OW'     , @('SRV-ONEWEBR'  , @('VisiTemp','Arizona','ArizonaCASH','Archive')))




        write-debug "destination = $destination" 
        if ( $destination -inotin $h.keys) { 
            throw "Destination $destination is not valid for a refresh recette procedure" 
            return 
        } 

        "Destination = {0} " -f $destination 
        "Source = {0}" -f $h.$destination[0]
        
        <#
 
        ## drop replication
        'Drop replication ...'
        if ($destination -notmatch 'STRATEGIC') {
            $Publisher = Get_Publisher -srv $destination
            Write-Debug $("Publisher = {0}" -f $Publisher)
             
        }
        'ok'
        #>
 

        #if ($destination -match 'OCM' ) {
            #throw "Must remove db replication on Az and AzCash before copy db !!! Otherwise drop will fail"
            #return
        #}



        ## copy database
        'Copy database(s)...'
        $sharedPath = "\\SRV-NAS\BACKUP\RefreshDev2\$destination"
        if ( -not (test-path $sharedPath )) { 
            New-Item $sharedPath -ItemType Directory 
        } 
        "dbList = {0} "  -f $($h.$destination[1] -join ',' ) 

        
        $params = @{
            Source = $h.$destination[0]
            Destination = $destination
            SharedPath = $sharedPath
            BackupRestore = $true
            Force = $true
            Database = $h.$destination[1]
            WithReplace = $true
            NoBackupCleanUp = $true 
            NumberFiles = 1 
        }
        Measure-Command { 
            Copy-DbaDatabase @Params | Out-Default 
        }  | select @{n="Total time elapsed";e={$_.Hours,"h" , $_.Minutes,"m",$_.Seconds,"s"-join " "}}
        
        
        'ok'  

        <#
        ## repair orphan users
        'Repair orphan users...'
        Repair-DbaDbOrphanUser -SqlInstance $destination -Database $h.$destination[1] | Out-Default
        'ok'
 
         
 
        ## post restore ops
        box 'Post restore ops...'
        $h.$destination[1] | % {
            "Remove replication {0} " -f $_
            $qry = "exec sp_removeDbReplication '$_' "
            Measure-Command {
                Invoke-Sqlcmd -ServerInstance $destination -Database master -Query $qry -vb | Out-Default
            } | select TotalSeconds
            "ok"
 
            "Set recovery mode {0}" -f $_
            $qry = "exec sp_killall '$_';
            alter database [$_] set recovery simple ;"
            Measure-Command {
                Invoke-Sqlcmd -ServerInstance $destination -Database master -Query $qry -vb | Out-Default
            } | select TotalSeconds
            "ok"
        }
        #>
 
    } # end process


    End {         
        ## stop transcript to release file for tee-object
        Stop-Transcript 

    } 
} 

Function New-AggregateMissSub { 
[CmdLetbinding()]
    Param ( 
        [parameter(Mandatory=$true,position=0,ValueFromPipeline=$true)]
        [string] $table ,
        [parameter(Mandatory=$true,position=1)]
        [string] $srv ,
        [parameter(Mandatory=$false,position=1)]
        [string] $dbn = 'Arizona' 
        ) 
    Begin { 
        if ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { 
            $DebugPreference = "Continue" 
        } 
        else { 
            $DebugPreference = "SilentlyContinue" 
        } 
    } 
    
    Process { 
        box "$table @ $srv" 

        ## init vars
        Write-Debug "Init vars" 
        [string]$centrale = Get-Publisher -srv $srv 
        Write-Debug "Centrale = $centrale"         

        $pk = (Invoke-Sqlcmd -ServerInstance $srv -Database $dbn -Query "SELECT dbo.fn_Get_Table_PK('$table') AS [pk]" ).pk 
        if([string]::IsNullOrEmpty($pk)) { 
            throw "Pk not found for table [$table]" 
            return 1
        } 
        Write-Debug "Pk = $pk" 

        $file =  "d:\temp\bcp_missing_x.dat" 
        Write-Debug "File = $file" 

        $Publication = 'Document' 

        $sub = (Invoke-Sqlcmd -ServerInstance $srv  -Query "select Arizona.dbo.fn_get_current_sub() as [sub]"  ).sub
        Write-Debug "Subsidiary = $sub " 
        Write-Debug "ok" 

        ##creer la table a la centrale
        Write-Debug "Process aggregate table @ $centrale" 
        $table_centrale = "tempdb.dbo.missing_$($table)_mags"
        $qry = "IF OBJECT_ID('$table_centrale') IS NULL
            CREATE TABLE $table_centrale ($pk INT, subsidiary_id INT ) "
 
        Write-Debug "Qry create table centrale :
            $qry "
 
        Invoke-Sqlcmd -ServerInstance $centrale -Query $qry -vb -ea Stop 
        Write-Debug "ok" 

        # check table
        write-verbose "Check table $table" 
        Verify-Table -srv $srv -Publication $Publication -table $table -check_missing_at_sub
        Write-Verbose "ok" 

        # get missing lines and copy to temp table
        Write-Verbose "Get missing lines and write to temp table" 
        $qry = "
        IF OBJECT_ID('tempdb.dbo.missing') IS NOT NULL
            DROP TABLE tempdb.dbo.missing;
        CREATE TABLE tempdb.dbo.missing ($pk INT, subsidiary_id INT ) ;
        WITH missing AS (
            SELECT CAST($pk AS INT) AS $pk
            FROM tempdb.dbo.$table
            EXCEPT
            SELECT $pk
            FROM Arizona.dbo.$table
        )
        INSERT tempdb.dbo.missing
        SELECT * , '$sub'
        FROM missing;
        "

        Write-Debug "Missing lines qry:
            $qry "
 
        Invoke-Sqlcmd -ServerInstance $srv -Query $qry -vb -ea Stop 
        Write-Verbose "ok" 

        # bcp out temp table (@ mag)
        write-debug 'BCP OUT' 
        Write-Verbose "BCP out temp table (@ mag) " 
        $arglist = @(
            'dbo.missing',
            "out $file",
            "-S $srv",
            "-d TempDB",
            "-T " , 
            "-N " , 
            "-e d:\temp\bcp_out_error.txt"
        )
        Start-Process -FilePath bcp.exe -ArgumentList $arglist -RedirectStandardOutput d:\temp\bcp_out.log -wait -NoNewWindow 
        Write-Verbose "ok" 

        # bcp in @ Centrale
        Write-Verbose "BCP In @ centrale" 
        $qry = "DELETE $table_centrale WHERE subsidiary_id = $sub ; " 
        Write-Debug $qry 
        Invoke-Sqlcmd -ServerInstance $centrale -Query $qry -vb -ea Stop 
        
        $arglist = @(
            "$table_centrale",
            "in $file",
            "-S $centrale",
            #"-d TempDB",
            "-T " , 
            "-N " , 
            "-e d:\temp\bcp_error.txt"
        )
        Start-Process -FilePath bcp.exe -ArgumentList $arglist -RedirectStandardOutput d:\temp\bcp_in.log -wait -NoNewWindow 
        Write-Verbose "ok" 
    
        ##print info note
        $rc = (Invoke-Sqlcmd -ServerInstance $centrale -Query "select count(*) as rc from $table_centrale where subsidiary_id = '$sub' ").rc 
        "{4} Missing {0} rows for {1} copied into {2} (sub {3}) " -f $srv  , $table , $table_centrale, $sub , $rc 
    }
} 
#Set-Alias -Name Aggregate-MissSub -Value Aggregate_MissSub

Function Test-EmptyString{ 
<#
.SYNOPSIS
Throws error (param #2) if string (param #1) is empty
 
.Description
Throws error (param #2) if string (param #1) is empty
 
.PARAMETER $string
String to test
 
.PARAMETER $errorMessage
Message to throw if string is empty
 
 
.EXAMPLE
Test-EmptyString 'abc' , 'error Msg'
#>
 

[CmdLetbinding()]
    Param (
        [string]$string , 
        [string]$errorMessage = 'String is empty' 
    )
    Process{ 
        #$string.gettype().FullName
        #$errorMessage.GetType().FullName
        if ([string]::IsNullOrEmpty($string)) { 
            Throw $errorMessage   
            return 
        }     
    }
} 
Function Enable-SSISQLAdmin  { 
<#
.SYNOPSIS
Enables account GPPH\SSI_SQLAdm on Rec or Prod
 
.Description
Enables account GPPH\SSI_SQLAdm on Rec or Prod
 
.PARAMETER Scope
 
.EXAMPLE
Enable-SSISQLAdmin -Scope REC
#>
 

[CmdLetbinding()]
    Param (
        [parameter(Mandatory=$false,position=0)]
        [ValidateSet('Rec', 'Prod', ignorecase=$True)]
        [string] $Scope = 'Rec' 
    ) #end param
    Begin {
            if ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { 
                $DebugPreference = "Continue" 
            } 
            else { 
                $DebugPreference = "SilentlyContinue" 
            } 
            $sl = @() 
    } 
    Process{ 
        # prepare qry
        $qry  = 'IF EXISTS ( SELECT * FROM sys.server_principals AS sp WHERE sp.name = ''GPPH\SSI-SQLAdm'' AND sp.is_disabled = 1 )
            EXEC sys.sp_ExecuteSQL N''ALTER LOGIN [GPPH\SSI-SQLAdm] ENABLE'' '
 
        Write-Debug $qry 
        
        #get servers
        $servers = Get-VisiServers -Scope $scope -IncludeCentrale 
        if ($scope -eq 'Rec' ) { 
            $servers += 'SRV-DISTRIBR' 
        } 
        else { 
            $servers += 'SRV-DISTRIB' 
        }                 

        # proceed to enable account
        $servers | % { 
             Write-Verbose $_ 
             Invoke-Sqlcmd -ServerInstance $_ -Query $qry 
             Write-Verbose 'ok' 
        } 

    } 
} 


Function Get-VisiCaisses { 
<#
.SYNOPSIS
Returns caisses from Visilab environments
 
.Description
Based on view Arizona.dbo.v_caisses.
*** Note:
System_site and CR_point_of_sale must be correctly populated for this function to return proper results
 
.PARAMETER Scope
 
.EXAMPLE
Get-VisiCaisses DEV1
 
.EXAMPLE
GET-VisiCaisses REC
 
.EXAMPLE
GET-VisiCaisses PROD
  
#>
 

[CmdLetbinding()]
    Param (
        [parameter(Mandatory=$false,position=0)]
        [ValidateSet('Dev1','Dev2', 'Rec', 'Prod' , ignorecase=$True)]
        [string] $scope = 'DEV1' 

    ) #end param
    Begin {
            if ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { 
                $DebugPreference = "Continue" 
            } 
            else { 
                $DebugPreference = "SilentlyContinue" 
            } 
            $sl = @() 
    } 
    Process{ 
        switch -regex ($scope) { 
            'DEV1' { $srv = 'DEV1OCM';break }
            'DEV2' { $srv = 'DEV2OCM';break }
            'DEV3' { $srv = 'DEV3OCM';break }
            'REC'  { $srv = 'SRV-ONECMR';break }
            'PROD' { $srv = 'SRV-ONECM';break }
        } 
        Write-debug "Srv: $srv" 
        $qry = "select * from v_caisses order by CRPOS_NAME ASC "
        Write-Debug $qry 
        Invoke-Sqlcmd -ServerInstance:$srv -database Arizona -Query $qry | % { $sl += $_ } 
    } # end process

    End {
        return $sl | Sort-Object CRPOS_NAME 
    } 
} 


function Write-Box {  
<#
.SYNOPSIS
Visi Write-Box function
.Description
Displays a text in a box
 
.PARAMETER str
 
.EXAMPLE
Write-Box 'myText'
 
#>
 
[CmdLetbinding()]
    Param(
        [parameter(Mandatory=$true, position=0)]
        [ValidateNotNullOrEmpty()]
        [string]  $str  
    ) # end param
    Process { 
        $ul = '┌'
        $lr ='┘'
        $vt = '│'
        $ho = '─'
        $ll='└'
        $ur='┐'
        $cr = [char]10+[char]13
        $result  = $($ul + $ho * $($str.Length+2)+ $ur  + $cr + $vt + ' ' + $str + ' ' + $vt +$cr +$ll + $ho * $($str.Length+2) + $lr ) 
        #return $result
        Write-Output $result
    } # end process

} #end function


function Get-Ou { 
<#
.SYNOPSIS
Resolve OU name or number
 
.Description
Matches input string with OU_short_name or OU_code and returns full OU info
 
.PARAMETER str
 
.EXAMPLE
#
Get-OU 512
 
.EXAMPLE
#
Get-OU Rive
 
#>
 
[CmdLetbinding()]
    Param(
            [parameter(Mandatory=$false, position=0)]
            [string]  $str  ## string to match
    )
    Begin { 
        If ( $PSCmdlet.MyInvocation.BoundParameters["Debug"] ) { $DebugPreference = "Continue" } 
        else { $DebugPreference = "SilentlyContinue" } 
    } 
    Process { 
        $qry = "SELECT ou.Organizational_unit_id, ou.OU_code, ou.ou_short_name, s.SUB_code, s.SUB_short_name , s.subsidiary_id
        FROM Arizona.dbo.Organizational_unit AS ou
        JOIN Arizona.dbo.Subsidiary AS s ON s.Subsidiary_ID = ou.OU_subsidiary
        where ou_code like '%$str%'
        OR ou_short_name like '%$str%'
        ORDER BY ou_code ASC "

        Write-Debug $qry 
        Invoke-Sqlcmd -ServerInstance SRV-ONECM -Query $qry 
    } #end process
} #end function



Function New-RefreshRecette { 
[CmdLetbinding()]
    Param (
        [parameter(Mandatory=$false,position=0,ValueFromPipeline=$true)]
        [ValidateNotNullOrEmpty() ]
        [string] $destination  
    ) #end param

    Begin {
        if ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { $DebugPreference = "Continue" 
        } 
        else { $DebugPreference = "SilentlyContinue" 
        } 
        
        #log file
        $log = "d:\MSSQL\SQLJobsLog\RefreshRecette.$($destination).$(get-date -f yyyy-MM-dd).log"
        
        #stop-transcript
        try{
          stop-transcript|out-null
        }
        catch [System.InvalidOperationException]{}
        Start-Transcript -Path $log -Append 

    } 
    Process{ 
    
        #load hash table
        $h = @{} 

        $h.Add('SRV-ACHATSR'                        ,@('SRV-ACHATS'                    , @('Arizona','ArizonaCASH','Archive'))) 
        $h.Add('SRV-ATHOMER'                        ,@('SRV-ATHOME'                    , @('Arizona','ArizonaCASH','Archive'))) 
        $h.Add('SRV-ATWORKR'                        ,@('SRV-ATWORK'                    , @('Arizona','ArizonaCASH','Archive')))
        $h.Add('SRV-MAG1'                            ,@('VI022-S1'                    , @('Arizona','ArizonaCASH','Archive')))
        $h.Add('SRV-MAG2'                            ,@('VI031-S1'                    , @('Arizona','ArizonaCASH','Archive')))
        $h.Add('SRV-MAG3'                            ,@('VI015-S1'                     , @('Arizona','ArizonaCASH','Archive')))
        $h.Add('SRV-ONECMR'                            ,@('SRV-ONECM'                    , @('Arizona','ArizonaCASH','Archive','Elvira','ElviraPV','VisiTemp','OneImport','OneShare','OneShareArchive','OneCustomer')))
        $h.Add('SRV-ONEWEBR'                        ,@('SRV-ONEWEB'                    , @('Arizona','ArizonaCASH','Archive')))
        $h.Add('SRV-PV1'                            ,@('PV420-S1'                    , @('Arizona','ArizonaCASH','Archive')))
        $h.Add('SRV-PV2'                            ,@('PV421-S1'                    , @('Arizona','ArizonaCASH','Archive')))
        $h.Add('SRV-STRATEGICR\STRATEGICSQL'        ,@('SRV-STRATEGIC\STRATEGICSQL'    , @('Arizona','ArizonaLD')))

        write-debug "destination = $destination" 
        if ( $destination -inotin $h.keys) { 
            throw "Destination $destination is not valid for a refresh recette procedure" 
            return 
        } 

        "Destination = {0} " -f $destination 
        "Source = {0}" -f $h.$destination[0]
        
        ## copy database
        'Copy database(s)...'
        $sharedPath = "\\SRV-NAS\BACKUP\RefreshRecette\$destination"
        if ( -not (test-path $sharedPath )) { 
            New-Item $sharedPath -ItemType Directory 
        } 
        $params = @{
            Source = $h.$destination[0]
            Destination = $destination
            SharedPath = $sharedPath
            BackupRestore = $true
            Force = $true
            Database = $h.$destination[1]
            WithReplace = $true
            NoBackupCleanUp = $true 
            NumberFiles = 1 
        }
        Measure-Command { 
            Copy-DbaDatabase @Params
        } 
        'ok'  

        <#
        ## post restore ops
        box 'Post restore ops...'
        $h.$destination[1] | % {
            "Remove replication {0} " -f $_
            $qry = "exec sp_removeDbReplication '$_' "
            Measure-Command {
                Invoke-Sqlcmd -ServerInstance $destination -Database master -Query $qry -vb | Out-Default
            } | select TotalSeconds
            "ok"
 
            "Set recovery mode {0}" -f $_
            $qry = "exec sp_killall '$_';
            alter database [$_] set recovery simple ;"
            Measure-Command {
                Invoke-Sqlcmd -ServerInstance $destination -Database master -Query $qry -vb | Out-Default
            } | select TotalSeconds
            "ok"
        }
        #>
 
    } # end process


    End {         
        ## stop transcript to release file for tee-object
        Stop-Transcript 

    } 
} 

Function New-VisiSQLAudit { 
<#
.SYNOPSIS
Deploy audit objets on a table
 
.Description
Deploy audit objets on a table
 
.PARAMETER Table
Table to be audited.
Pipeline parameter.
 
.PARAMETER SQLInstance
SQL Instance where the table to be audited lives
Default $env:COMPUTERNAME
 
.PARAMETER Database
Database where the table to be audited can be found
Default Arizona
 
.PARAMETER AuditDatabase
Target database for Audit table.
This is where the Audit_[table] will be created.
Default VisiAudit
 
.PARAMETER NoClobber
When false, script will drop and recreate an existing audit table
Default TRUE
 
.EXAMPLE
#
New-VisiSQLAudit -SQLInstance SRV-MAG2 -table dbo.Telecom
 
.EXAMPLE
#
@('Country') | New-VisiSQLAudit -SQLInstance SRV-MAG3
 
.EXAMPLE
# default Freq = 13
(Get-Publications -Publisher SRV-ONECMR).name | Update-RepliJobSchedule -Publisher SRV-ONECMR
 
#>
 
[CmdLetbinding()]

    Param (
        [parameter(Mandatory=$false,position=0,ValueFromPipeline=$true)]
        [ValidateNotNullOrEmpty() ]
        [string] $Table   
        , 
        [parameter(Mandatory=$false,position=1)]
        [ValidateNotNullOrEmpty() ]
        [string] $SQLInstance = $env:COMPUTERNAME 
        ,
        [parameter(Mandatory=$false,position=2)]
        [ValidateNotNullOrEmpty() ]
        [string] $Database = 'Arizona' 
        ,
        [parameter(Mandatory=$false,position=3)]
        [ValidateNotNullOrEmpty() ]
        [string] $AuditDatabase = 'VisiAudit' 
        ,
        [parameter(Mandatory=$false,position=4)]
        [boolean] $NoClobber = $TRUE 

        ) # end param
    
    Begin  { 
            If ( $PSCmdlet.MyInvocation.BoundParameters["Debug"] ) { 
                $DebugPreference = "Continue" 
            } 
            else { 
                $DebugPreference = "SilentlyContinue" 
            } 
            Write-Verbose "Visi Audit Objects 2.0" 
            $stopwatch =  [system.diagnostics.stopwatch]::StartNew()
    } 
        
    Process { 

        $srv = $sqlInstance 
        $tgt_dbn = $AuditDatabase
        $dbn = $database 

        if ($table -match '\.' ) { 
            $schema = ($table -split '\.')[0]
            $tableShortName = ($tbl -split '\.')[1]
        }
        else { 
            $schema = 'dbo' 
            $tableShortName = $table
        } 
        $tableLongName = $( $schema +'.' + $tableShortName ) 
        $auditTableShortName = $('Audit_' + $tableShortName) 
        $auditTableLongName = $($schema + '.' + $auditTableShortName) 
        $triggerShortName = $('t_IUD_Audit_' + $tableShortName) 
        $triggerLongName = $($schema +'.' + $triggerShortName) 
        
        Write-Debug $("Schema = {0} " -f $schema ) 
        Write-Debug $("Dbn = {0}" -f $dbn ) 
        Write-Debug $("TableShortName = {0} | TableLongName = {1} " -f $tableShortName , $tableLongName )
        Write-Debug $("auditTableShortName = {0} | auditTableLongName = {1} " -f $auditTableShortName , $auditTableLongName )
        Write-Debug $("triggerShortName = {0} | triggerLongName = {1} " -f $triggerShortName , $triggerLongName )

        $SMOserver = New-Object ('Microsoft.SqlServer.Management.Smo.Server') -argumentlist $srv -ErrorAction Stop 
        $scriptr =  New-Object ('Microsoft.SqlServer.Management.Smo.Scripter') ($SMOserver)
        $enc = New-Object("System.Text.UTF8Encoding")

        $optDrop = New-Object ('Microsoft.SqlServer.Management.Smo.ScriptingOptions') -Property @{ 
                ScriptDrops = $true 
                IncludeIfNotExists = $true 
                SchemaQualify = $true 
                ScriptSchema = $true 
            } 
        $optCreate = New-Object ('Microsoft.SqlServer.Management.Smo.ScriptingOptions') -Property @{ 
                ScriptDrops = $false 
                IncludeHeaders = $false 
                IncludeIfNotExists = $true 
                SchemaQualify = $true 
                ScriptSchema = $true 
                Encoding=$enc 
                NoCollation =$true 
                DRIAll = $false
                ConvertUserDefinedDataTypesToBaseType = $true 
                NoIdentities = $true ## do not script identity properties
            } 
        
        [string]$qry = "--audit SCript generated by new-visisqlaudit " 

        #####################
        ## xFer schemas
        #####################
        Write-Debug "Transfer schemas" 

        $SMOserver.Databases[$dbn].Schemas | % { 
            $qry = $_.Script($optCreate) 
            #Write-Debug $qry
            Invoke-Sqlcmd -ServerInstance $srv -Database $tgt_dbn -Query $qry 
        } 
        Write-Debug "OK " 


        #####################
        ## audit Table
        #####################
        Write-Debug "Create audit table"

        $tblx = $SMOserver.Databases[$dbn].Tables[$tableShortName, $schema]  
        #Write-Debug $tblx.Name
        
        ## drop audit table
        If ( $NoClobber -eq $false) { 
            $qry += $tblx.Script($optDrop) -replace $tableShortName , $('Audit_'+$tableShortName) 
            $qry += "`n--`n" 
        } 

        ## create audit table
        $qry += $tblx.Script($optCreate) -ireplace [regex]::Escape("[$tableShortName]") , "[$auditTableShortName]" 

        #audit table system columns
        $qry += "`nIf COL_LENGTH('$auditTableLongName','Audit_Id') IS NULL ALTER TABLE $auditTableLongName ADD Audit_Id INT IDENTITY PRIMARY KEY ;"
        $qry += "`nIf COL_LENGTH('$auditTableLongName','Server_name') IS NULL ALTER TABLE $auditTableLongName ADD Server_name SYSNAME NOT NULL DEFAULT @@servername ;"
        $qry += "`nIf COL_LENGTH('$auditTableLongName','Host') IS NULL ALTER TABLE $auditTableLongName ADD Host SYSNAME NOT NULL DEFAULT HOST_NAME();"
        $qry += "`nIf COL_LENGTH('$auditTableLongName','Login_name') IS NULL ALTER TABLE $auditTableLongName ADD Login_name SYSNAME NOT NULL DEFAULT SUSER_SNAME();"
        $qry += "`nIf COL_LENGTH('$auditTableLongName','Proc_name') IS NULL ALTER TABLE $auditTableLongName ADD Proc_name NVARCHAR(4000) NULL ;"
        $qry += "`nIf COL_LENGTH('$auditTableLongName','Time_stamp') IS NULL ALTER TABLE $auditTableLongName ADD Time_stamp DATETIME2(7) NOT NULL DEFAULT CURRENT_TIMESTAMP ;"
        $qry += "`nIf COL_LENGTH('$auditTableLongName','SPID') IS NULL ALTER TABLE $auditTableLongName ADD SPID INT NOT NULL DEFAULT @@SPID;"
        $qry += "`nIf COL_LENGTH('$auditTableLongName','Event_type') IS NULL ALTER TABLE $auditTableLongName ADD Event_type CHAR(2) NOT NULL; "
        $qry += "`nIf COL_LENGTH('$auditTableLongName','Program_name') IS NULL ALTER TABLE $auditTableLongName ADD [Program_name] VARCHAR(MAX) NULL;"
        $qry += "`nIf COL_LENGTH('$auditTableLongName','BMC_user_profile_id') IS NULL ALTER TABLE $auditTableLongName ADD [BMC_user_profile_id] VARCHAR(100) NULL;"
        Write-Debug $qry 
        Invoke-Sqlcmd -ServerInstance $srv -Database $tgt_dbn -Query $qry -vb -ea Stop 

        ## audit synonym
        Write-Verbose $("Synonym = {0}" -f $auditTableLongName ) 
        Write-Debug $("`n"+'#'*50 + "`nAudit Synonym `n" +'#'*50) 


        $qry = "
        IF OBJECT_ID('$auditTableLongName', 'SN' ) IS NULL
            EXEC sys.sp_executeSQL N'CREATE SYNONYM $auditTableLongName FOR VisiAudit.$auditTableLongName'"
 
        write-debug $qry 
        Invoke-Sqlcmd -ServerInstance $srv -Database $dbn -Query $qry -vb -ea Stop 

        ## audit trigger
        Write-Verbose $("Trigger = {0}" -f $triggerLongName ) 

        ## column list
        Write-Debug $("`n"+'#'*50 + "`nCreate audit trigger`n" +'#'*50) 
        $table_col_list_qry = "
        SELECT STUFF(
            (SELECT ',' + c.name
            FROM sys.[columns] AS c
            WHERE c.[object_id] = OBJECT_ID('$tableShortName','U')
            AND c.system_type_id not in (34,35,99,189)
            FOR XML PATH(''),TYPE ).value('.','NVARCHAR(MAX)') ,1, 1 ,'') AS col_list "
 
        Write-Debug $table_col_list_qry 
        $table_col_list = (Invoke-Sqlcmd -ServerInstance $srv -Database $dbn -Query $table_col_list_qry -ErrorAction Stop -Verbose).col_list 
        Write-Debug "Table col list = $table_col_list " 
        

        ## audit trigger
        $trig_qry = "
        IF OBJECT_ID('$triggerLongName', 'TR') IS NULL
            EXEC sys.sp_executeSQL N'CREATE TRIGGER $triggerLongName ON $tableLongName FOR INSERT,DELETE, UPDATE AS RETURN ' ;
        GO
        ALTER TRIGGER $triggerLongName ON $tableLongName FOR INSERT, DELETE, UPDATE AS
        SET NOCOUNT ON
        DECLARE @event_type CHAR;
        IF EXISTS(SELECT * FROM inserted)
            IF EXISTS(SELECT * FROM deleted)
                SELECT @event_type = 'U'
            ELSE
                SELECT @event_type = 'I'
        ELSE
            IF EXISTS(SELECT * FROM deleted)
                SELECT @event_type = 'D'
            ELSE
                --no rows affected - cannot determine event
                SELECT @event_type = '?'
        --
        DECLARE @table_name SYSNAME ;
        SELECT @table_name = OBJECT_NAME(parent_id)
        FROM sys.triggers AS t
        WHERE t.[object_id] = @@procid;
 
        DECLARE @host_name SYSNAME;
        SELECT @host_name = des1.[host_name]
        FROM sys.dm_exec_sessions AS des1
        WHERE des1.session_id = @@spid;
           DECLARE @proc NVARCHAR(4000);
        DECLARE @Buffer table ( EventType nvarchar(30), Parms int, EventInfo nvarchar(4000) ) ;
        INSERT INTO @Buffer ( EventType, Parms, EventInfo )
        EXEC ('DBCC INPUTBUFFER(@@SPID) WITH NO_INFOMSGS ');
        SELECT @proc = EventInfo FROM @Buffer;
        DECLARE @program_name SYSNAME ;
        SELECT @program_name = program_name from sys.dm_exec_sessions where session_id = @@spid ;
        DECLARE @bmc_user_profile_Id INt = NULL;
        "
 
        if ($dbn -eq 'Arizona') { 
            $trig_qry += "SELECT @bmc_user_profile_id = aci.APSCI_bmc_user_profile FROM Arizona.dbo.APS_connection_info AS aci WITH (NOLOCK) WHERE aci.APSCI_SQL_spid = @@SPID ; " 
        } 

        $trig_qry += "BEGIN TRY
            INSERT INTO $auditTableLongName (
            Event_type,
            [Host],
            [Proc_name] ,
            [Program_name] ,
            [BMC_User_profile_Id],
            $table_col_list
            )
            SELECT
                CASE @event_type WHEN 'U' THEN 'U1' ELSE @event_type END ,
                @host_name,
                @proc,
                @program_name,
                @bmc_user_profile_id,
                $table_col_list
            FROM DELETED ;
 
            INSERT INTO $auditTableLongName (
                Event_type,
                [Host],
                [proc_name] ,
                [Program_name] ,
                [BMC_User_profile_Id],
                $table_col_list
            )
            SELECT
                CASE @event_type WHEN 'U' THEN 'U2' ELSE @event_type END ,
                @host_name,
                @proc,
                @program_name,
                @bmc_user_profile_id,
                $table_col_list
            FROM INSERTED
            JOIN sys.dm_exec_sessions AS des1 ON @@spid = des1.session_id ;
        END TRY
        BEGIN CATCH
            --replace later when visisys.log is moved out of Arizona
            --EXEC dbo.sp_Save_VisiSys_Log @Domain = '$auditTableLongName', @Module = '$triggerLongName', @Message = 'audit failed', @CloseImmediately = 1 ;
        END CATCH
        GO
         
        EXEC sp_setTriggerOrder @triggerName = '$triggerLongName' , @order = 'First',@stmttype = 'UPDATE';
        EXEC sp_setTriggerOrder @triggerName = '$triggerLongName' , @order = 'First',@stmttype = 'INSERT';
        EXEC sp_setTriggerOrder @triggerName = '$triggerLongName' , @order = 'First',@stmttype = 'DELETE';
        "



        #"Create audit triggers for $table_name"
        Write-Debug $("Creating trigger: [{0}]" -f $triggerLongName ) 
        Write-Debug  $trig_qry  
        
        Invoke-Sqlcmd -ServerInstance $srv -Database $dbn -Query $trig_qry  -ErrorAction Stop 





    }  #end process

    End { 
        $stopwatch.Stop()
        write-verbose $("Elapsed seconds = {0} " -f ($stopwatch.Elapsed).TotalSeconds) 
     }

} #end function

















### ALIASES

Set-Alias -Name xou -Value Get-ou 
Set-Alias -Name box -value Write-Box
#### export members
#### WARNING only members with a DASH will be exported , the others are PRIVATE functions
## export moved to psd1