VisiPsLib.psm1
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; EXEC dbo.sp_Save_VisiSys_Log @Id = ''$logId''; " $desc = "some desc " $job_name = "## Update STATS $table $stat " $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'GPPH\MNicolescu', @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', @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 -Verbose -ErrorAction Stop ## start job $start_job = "exec msdb.dbo.sp_start_job @job_name = '$job_name'" ; Invoke-Sqlcmd -ServerInstance $srv -Query $start_job -Verbose -ErrorAction Stop } } #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 .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 .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 Build Info Will return a hash containing the build result ( used for nightly build logging ) .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] $SkipGetLatest = $false , [parameter(Mandatory=$false,position=5)] [switch] $noTranscript = $false , [parameter(Mandatory=$false,position=6)] [switch] $disableVisiSysLog = $false , [parameter(Mandatory=$false,position=7)] [hashtable]$buildInfo = @{} ) # 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 (-not ($SkipGetLatest.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" switch ($buildAction.ToUpper()) { 'NEW' { $files = gci -Path $ReleasePath -Recurse -File -Filter *.sql | ? {$_.FullName -imatch '100\.New' -and $_.FullName -inotmatch 'NORUN' } } 'PARTIALBUILD'{ $files = gci -Path $ReleasePath -Recurse -File -Filter *.sql | ? {$_.FullName -inotmatch 'NORUN' } } 'UPGRADEBD' { $files = gci -Path $ReleasePath -Recurse -File -Filter *.sql | ? {$_.FullName -imatch '800\.UpgradeBD' -and $_.FullName -inotmatch 'NORUN' } } 'UPGRADESOFT' { $files = gci -Path $ReleasePath -Recurse -File -Filter *.sql | ? {$_.FullName -imatch '801\.Upgrade' -and $_.FullName -inotmatch 'NORUN' } } 'UPGRADEBOTH' { $files = gci -Path $ReleasePath -Recurse -File -Filter *.sql | ? {($_.FullName -imatch '801\.Upgrade' -or $_.FullName -imatch '800\.UpgradeBD' ) -and $_.FullName -inotmatch 'NORUN' } } } 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 + " " + [char]0x21e8 + " " + $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 Invoke-BuildVisiSQLCommonTools 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 |