VisiPsLib.psm1
function Truncate_Database { [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='High')] Param( $sqlInstance , $database ) Process{ $scriptPath = "$env:LOCALAPPDATA\Log\ScriptTruncateDB-$sqlInstance-$database" $scriptDrop = Join-Path $scriptPath "Drop-$(Get-Date -format "yyyyMMdd-HHmmss").sql" $scriptCreate = Join-Path $scriptPath "Create-$(Get-Date -format "yyyyMMdd-HHmmss").sql" New-Item $scriptPath -ItemType Directory -Force @($scriptDrop,$ScriptCreate) | ForEach-Object { New-Item $_ -ItemType File -Force } $opt = New-DbaScriptingOption $opt.IncludeIfNotExists = $true $SMOserver = New-Object ('Microsoft.SqlServer.Management.Smo.Server') -argumentlist $SQLInstance $db = $SMOserver.Databases[$database] if($PSCmdlet.ShouldProcess("$SQLInstance.Database","Truncate all tables")){ # generate fk scripts Write-Output "Generating FK scripts..." $tables = $db.Tables #| select -First 100 for($i=0;$i -lt $tables.count; $i++){ $perct = ($i / $tables.count) * 100 $table = $tables[$i] #Write-Progress -Activity "Generate FK scripts" -Status "Table: $($table.Name)" -PercentComplete $perct Write-Progress -Activity "Generate FK script" -Status "Table: $($table.Schema +'.' + $($table.Name))" -PercentComplete $perct $table.EnumForeignKeys() | % { $opt.ScriptDrops = $true $db.Tables[$_.table_name, $_.table_schema].ForeignKeys[$_.Name] | Export-DbaScript -ScriptingOptionsObject $opt -FilePath $scriptDrop -Append | out-null $opt.ScriptDrops = $false $db.Tables[$_.table_name, $_.table_schema].ForeignKeys[$_.Name] | Export-DbaScript -ScriptingOptionsObject $opt -FilePath $scriptCreate -Append | out-null } } "Drop scripts saved to $scriptDrop" "Create scripts saved to $scriptCreate" "ok" # drop fk Write-Output "Dropping FK constraints..." Invoke-Sqlcmd -ServerInstance $sqlInstance -Database $database -InputFile $scriptDrop "ok" # truncate tables Write-Output "Truncating tables..." #$db.Tables | % { $_.Name; $_.TruncateData() } $tables = $db.Tables | select -First 100 for($i=0;$i -lt $tables.count; $i++){ $perct = ($i / $tables.count) * 100 $table = $tables[$i] Write-Progress -Activity "Truncate table" -Status "Table: $($table.Schema +'.' + $($table.Name))" -PercentComplete $perct $table.TruncateData() } "ok" # recreate fk Write-Output "Recreating FK constraints..." Invoke-Sqlcmd -ServerInstance $sqlInstance -Database $database -InputFile $scriptCreate "ok" # check table rowcount Write-Output "Checking table rowcount..." #Get-DbaDbTable -SqlInstance $sqlInstance -Database $database | ? Rowcount -gt 0 | % { throw "Table $($_.Name) not empty" } $tables = Get-DbaDbTable -SqlInstance $sqlInstance -Database $database for($i=0;$i -lt $tables.count; $i++){ $perct = ($i / $tables.count) * 100 $table = $tables[$i] Write-Progress -Activity "Check rowcount " -Status "Table: $($table.Schema +'.' + $($table.Name))" -PercentComplete $perct If ($table.Rowcount -gt 0 ) { Throw "Table not empty" } } "check tables ok" } } } Set-Alias -Name Truncate-database -Value Truncate_database function Disable-Telemetry{ [CmdletBinding(SupportsShouldProcess)] Param ($ComputerName) Process { $sb = { get-service | ? Name -match 'SQLWriter|telemetry' | % { Stop-Service -Name $_.Name -Force Set-Service -Name $_.Name -StartupType Disabled } ################################################## # Deactivate CEIP registry keys # ################################################## # Set all CustomerFeedback & EnableErrorReporting in the key directory HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server to 0 # Set HKEY_LOCAL_MACHINE\Software\Microsoft\Microsoft SQL Server\***\CustomerFeedback=0 # Set HKEY_LOCAL_MACHINE\Software\Microsoft\Microsoft SQL Server\***\EnableErrorReporting=0 # *** --> Version of SQL Server (100,110,120,130,140,...) # For the Engine # Set HKEY_LOCAL_MACHINE\Software\Microsoft\Microsoft SQL Server\MSSQL**.<instance>\CPE\CustomerFeedback=0 # Set HKEY_LOCAL_MACHINE\Software\Microsoft\Microsoft SQL Server\MSSQL**.<instance>\CPE\EnableErrorReporting=0 # For SQL Server Analysis Server (SSAS) # Set HKEY_LOCAL_MACHINE\Software\Microsoft\Microsoft SQL Server\MSAS**.<instance>\CPE\CustomerFeedback=0 # Set HKEY_LOCAL_MACHINE\Software\Microsoft\Microsoft SQL Server\MSAS**.<instance>\CPE\EnableErrorReporting=0 # For Server Reporting Server (SSRS) # Set HKEY_LOCAL_MACHINE\Software\Microsoft\Microsoft SQL Server\MSRS**.<instance>\CPE\CustomerFeedback=0 # Set HKEY_LOCAL_MACHINE\Software\Microsoft\Microsoft SQL Server\MSRS**.<instance>\CPE\EnableErrorReporting=0 # ** --> Version of SQL Server (10,11,12,13,14,...) ################################################## $Key = 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server' $FoundKeys = Get-ChildItem $Key -Recurse | Where-Object -Property Property -eq 'EnableErrorReporting' foreach ($Sqlfoundkey in $FoundKeys) { $SqlFoundkey | Set-ItemProperty -Name EnableErrorReporting -Value 0 $SqlFoundkey | Set-ItemProperty -Name CustomerFeedback -Value 0 } ################################################## # Set HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Microsoft SQL Server\***\CustomerFeedback=0 # Set HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Microsoft SQL Server\***\EnableErrorReporting=0 # *** --> Version of SQL Server(100,110,120,130,140,...) ################################################## $WowKey = "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Microsoft SQL Server" $FoundWowKeys = Get-ChildItem $WowKey | Where-Object -Property Property -eq 'EnableErrorReporting' foreach ($SqlFoundWowKey in $FoundWowKeys){ $SqlFoundWowKey | Set-ItemProperty -Name EnableErrorReporting -Value 0 $SqlFoundWowKey | Set-ItemProperty -Name CustomerFeedback -Value 0 } } # apply script block if ($PSCmdlet.ShouldProcess("[$ComputerName]", "Disable telemetry")) { Invoke-Command -ComputerName $computerName -ScriptBlock $sb -ea continue } } } function Disable-AuditTriggers { [CmdletBinding(SupportsShouldProcess)] <# .SYNOPSIS Disable or drop audit triggers .Description Disables or drops all triggers matching the name patter 'Audit' Default = Disable , DROP managed by switch parameter History 0.9.40 - created .PARAMETER SQLInstance Target server Pipeline OK .PARAMETER Database Target Database .PARAMETER DropTriggers Will performa DROP instead of DISABLE (default) .EXAMPLE Disable-AuditTriggers -SQLInstance SRV-MAG1 .EXAMPLE Get-VisiServers REC | Disable-AuditTriggers -Database ArizonaCash -DropTriggers #> Param( [parameter(Mandatory=$true,position=0,valueFromPipeline=$true )] [ValidateNotNullOrEmpty()] [alias('srv')] [string] $SQLInstance , [parameter(Mandatory=$false,position=1)] [alias('dbn')] [string] $Database = 'Arizona' , [parameter(Mandatory=$false,position=2)] [switch] $DropTriggers ) Begin { If ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { $DebugPreference = "Continue" } else { $DebugPreference = "SilentlyContinue" } } Process { Write-Verbose $SQLInstance Write-Verbose $Database $SMOserver = New-Object ('Microsoft.SqlServer.Management.Smo.Server') -argumentlist $SQLInstance $SMOserver.databases[$Database].Tables | ForEach-Object { $triggers = $_.Triggers | Where-Object Name -match 'Audit' $triggers | ForEach-Object { Write-Verbose $_.Name if ($DropTriggers.IsPresent) { if ($PSCmdlet.ShouldProcess("[$SQLInstance].[$Database].$_", "Drop trigger")) { $_.Drop() } } else { if ($PSCmdlet.ShouldProcess("[$SQLInstance].[$Database].$_", "Disable trigger")) { $_.IsEnabled = $false $_.Alter() } } } } } } Function Restore-CaisseFromS1 { [CmdletBinding(SupportsShouldProcess)] <# .SYNOPSIS Restore ArizonaCash db from S1 to Caisse .Description .PARAMETER SQLInstance SQLInstance - caisse .EXAMPLE #> Param ( [parameter(Mandatory=$false,position=0,ValueFromPipeline=$true)] [ValidateNotNullOrEmpty()] [string]$Caisse = $env:COMPUTERNAME , [parameter(Mandatory=$false,position=1)] [ValidateNotNullOrEmpty()] [string]$S1 , [parameter(Mandatory=$false,position=4)] [switch]$SkipDbRestore , [parameter(Mandatory=$false,position=5)] [string]$DbTransferNetworkShare = '\\srv-nas\backup\temp' , [parameter(Mandatory=$false,position=3)] [switch]$SkipPostRestoreDataOps , [parameter(Mandatory=$false,position=2)] [switch]$SkipConfigMacAddress ) Begin { if ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { $DebugPreference = "Continue" } else { $DebugPreference = "SilentlyContinue" } } Process { ## connect to Server $Server = Connect-DbaInstance -SqlInstance $Caisse $Database = 'ArizonaCash' ## get S1 name if ([string]::IsNullOrEmpty($s1)) { write-verbose 'get s1 name' $s1 = (invoke-sqlcmd -ServerInstance $Caisse -Query "EXEC('SELECT @@SERVERNAME as s1') AT [ArizonaCASH]").s1 write-verbose "S1 = $s1" write-verbose 'ok' } ## copy login ArizonaCASH from S1 $Login = 'ArizonaCash' Write-Verbose "Copy login ArizonaCASH from $s1" Copy-DbaLogin -Source $s1 -Destination $Caisse -Login $Login $server | Invoke-DbaQuery -Query "ALTER LOGIN $Login WITH DEFAULT_DATABASE=$Database" Write-Verbose 'ok' ## backup /restore DB if (-not($SkipDbRestore.IsPresent)) { Write-Verbose $("Restore ArizonaCASH from $s1" ) Copy-DbaDatabase -Source $s1 -Destination $Caisse -Database $Database -SharedPath $DbTransferNetworkShare -Force -BackupRestore -debug:$false Repair-DbaDbOrphanUser -SqlInstance $Caisse -Force -debug:$false Write-Verbose 'ok' } ## config MacAddress if (-not($SkipConfigMacAddress.IsPresent)) { write-verbose "--check if MAC values are not null @ $S1 " $qry = " IF EXISTS ( SELECT * FROM dbo.cr_point_of_sale WHERE CRPOS_logical_address IS NULL AND crpos_name <> 'OPTIC' ) BEGIN RAISERROR('CR_point_of_sale.CRPOS_logical_addres is NULL @ S1',16, -1) ; RETURN END IF EXISTS ( SELECT * FROM cr_pos_local_data WHERE crpld_key = 'MacAddress' AND crpld_value IS NULL ) BEGIN RAISERROR('CR_POS_local_data.CRPLD_value is NULL @ S1',16, -1) ; RETURN END " #Invoke-Sqlcmd -ServerInstance $s1 -Query $qry -Database ArizonaCASH -ea Stop $qryGetMac = " SELECT crpos_logical_address as mac FROM dbo.cr_point_of_sale WHERE CRPOS_logical_address IS NOT NULL AND crpos_name <> 'OPTIC' " $mac = (invoke-sqlcmd -ServerInstance $s1 -Database ArizonaCASH -Query $qryGetMac ).mac Write-Debug $qryGetMac Write-Debug "Mac = $mac" # write Mac Address to db $qry = " -- update CR_POS_local_data with local MAC UPDATE dbo.CR_POS_local_data SET CRPLD_value = '$mac' WHERE crpld_key = 'MacAddress' " Write-Debug $qry $server | Invoke-DbaQuery -Query $qry -Database ArizonaCash Write-Verbose 'ok' } ## remove Audit Triggers Disable-AuditTriggers -SQLInstance $Caisse -Database $Database -DropTriggers ## data ops post restore if (-not($SkipDataOps.IsPresent)) { write-verbose "DataOps" $qry = " EXEC dbo.aps_cr_pos_local_data_create; UPDATE cr_pos_local_data SET CRPLD_Value = 3 WHERE crpld_key = 'Databaselevel' -- truncate tables TRUNCATE TABLE dbo.CR_TT_Open_Ticket_List TRUNCATE TABLE dbo.cr_eft_transaction DELETE dbo.cr_sales_operation DELETE dbo.cr_sales_item DELETE dbo.cr_sales_header DELETE dbo.cr_cash_report_line DELETE dbo.cr_cash_report_version DELETE dbo.cr_cash_report_header DELETE dbo.cr_master_cash_report " Write-Verbose $qry #Invoke-Sqlcmd -Database ArizonaCASH -Query $qry -Verbose -ErrorAction Stop -QueryTimeout 15000 $server | Invoke-DbaQuery -Database $Login -Query $qry -QueryTimeout 15000 write-verbose 'ok' } } # end process } # end function Function Deploy_VisiDB_v4 { <# .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 Version 0.9.42 - buildInfo now returns the details of the log file .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 $_ })] [alias('RelPath')] [string] $ReleasePath , [parameter(Mandatory=$true,position=1,valueFromPipeline=$true )] [ValidateNotNullOrEmpty()] [alias('Srv')] [string] $SQLInstance , [parameter(Mandatory=$false,position=2)] [alias('dbn')] [string] $Database = '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)] [Alias('disableVisiSysLog')] [switch] $NoLog = $false , [parameter(Mandatory=$false,position=7)] [hashtable]$BuildInfo = @{} , [parameter(Mandatory=$false,position=8)] [switch] $IncludeIndex = $false , [parameter(Mandatory=$false,position=9)] [PSCredential]$SQLCredential , [parameter(Mandatory=$false,position=10)] [Switch]$NoCLR ) # end param Begin { If ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { $DebugPreference = "Continue" } else { $DebugPreference = "SilentlyContinue" } $ErrorActionPreference = 'Stop' } Process { ## attempt to stop transcription if (-not($noTranscript.IsPresent)) { try{stop-transcript|out-null} catch [System.InvalidOperationException]{} } ## init vars and clear errors $srv = $SQLInstance $dbn = $Database #$disableVisiSysLog = $noLog $log_id = $null $Global:Error.Clear() $buildInfo = @{} ## prepare connection $sqlParams = @{ ServerInstance = $SQLInstance } if ($SQLInstance -match 'BVT'){ $sqlParams += @{ Credential = $SQLCredential } } ## start transcription if (-not($noTranscript.IsPresent)) { $logFile = Join-Path -Path $env:LOCALAPPDATA -ChildPath "Log\Build_$($dbn)_$(Split-Path $ReleasePath -Leaf)_$($buildAction)_$($srv).$($(Get-Date -Format s ) -ireplace ':', '-' ).log" Write-Debug $("[100] Log file = {0}" -f $logFile ) Start-Transcript $logFile $BuildInfo.LogFile = $logFile } try { ### get latest from TFS if ($GetLatest.IsPresent) { if ($VerbosePreference -eq "Continue" ) { tf get $ReleasePath /recursive Write-Debug '[200]get' } else { tf get $ReleasePath /recursive | Out-Null Write-Debug '[200] get quiet' } Write-Debug "[200]TF Get Ok " } ##get last changeSet try { Write-Debug '[300] start change set ' $changeSet = @(tf history $ReleasePath /stopafter:1 /noprompt /recursive)[2].Split(' ')[0] } catch { $changeSet = -1 } Write-Debug "[300]Get Changeset ok, changeset = $changeSet" $BuildInfo.ChangeSet = $changeSet Write-Debug "$buildAction build starting" if ($IncludeIndex.IsPresent) { $exclude = [char](0) # use something that won't show up in a file name } else { $exclude = 'NORUN|INDEX' } if ($NoCLR.IsPresent) { $exclude += '|CLR' } Write-Debug "Exclude = $exclude" switch ($buildAction.ToUpper()) { 'NEW' { $files = Get-ChildItem -Path $ReleasePath -Recurse -File -Filter *.sql | Where-Object {$_.FullName -imatch '100\.New' -and $_.FullName -inotmatch $exclude } } 'PARTIALBUILD'{ $files = Get-ChildItem -Path $ReleasePath -Recurse -File -Filter *.sql | Where-Object {$_.FullName -inotmatch $exclude } } 'UPGRADEBD' { $files = Get-ChildItem -Path $ReleasePath -Recurse -File -Filter *.sql | Where-Object {$_.FullName -imatch '800\.UpgradeBD' -and $_.FullName -inotmatch $exclude } } 'UPGRADESOFT' { $files = Get-ChildItem -Path $ReleasePath -Recurse -File -Filter *.sql | Where-Object {$_.FullName -imatch '801\.Upgrade' -and $_.FullName -inotmatch $exclude } } 'UPGRADEBOTH' { $files = Get-ChildItem -Path $ReleasePath -Recurse -File -Filter *.sql | Where-Object {($_.FullName -imatch '801\.Upgrade' -or $_.FullName -imatch '800\.UpgradeBD' ) -and $_.FullName -inotmatch $exclude } } } $fileCount = ($files |Measure-Object).Count $BuildInfo.FileCount = $($fileCount) Write-Debug $("[400]Release path = {0} " -f $ReleasePath ) Write-Debug $("[410]Files OK Count = {0} " -f $fileCount) ## check if there is something to build if ($fileCount -eq 0) { Write-Warning "No files to build were found" } ### log build start on target server Write-Debug '[420]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 @sqlParams -Query $qry).log_id Write-Debug "[421]Log build start ok" } catch { # do not fail deploy if log fails ; this is done on purpose Write-Debug "[422]VisiSys.Log failed "; $_.Exception.Message } ## start deploy try { foreach ($file in $files | Sort-Object { $_.FullName -replace "\W", 'z' }) { Write-Output $($SQLInstance + '.' + $Database + " " + [char]0x21e8 + " " + $(split-path $(Split-Path $file.FullName ) -leaf) + '/' + $file.BaseName) #Write-Verbose $($file.DirectoryName -replace '^d\:\\sources\\\w+\\', '' ) Write-Debug "[510] Object $file" Invoke-Sqlcmd @sqlParams -database $Database -InputFile $($file.FullName) -QueryTimeout 10000 Write-Debug "[511] Object OK " } ### log build OK $qry = "EXEC dbo.sp_Save_VisiSys_Log @Id = '$log_id', @note = '$buildAction OK', @status='0'" Write-Debug $qry try { #$server | Invoke-DbaQuery -Query $qry Invoke-Sqlcmd @sqlParams -Query $qry } catch { Write-Debug "VisiSys log failed" ; $_.Exception.Message } } #end try catch { Write-Debug "[530] Object $file NOK - start build failed ops " ## 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 "[531]] Log build failed" try { $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 "[532] $qry " Invoke-Sqlcmd @sqlParams -Query $qry Write-Debug "[533] Log build failed ok" } catch { # again do not fail this if log failed Write-Debug "[535] Visisys log failed"; $_.Exception.Message } ##throw error Write-Debug "[555] $($BuildInfo.File) " Write-Debug "[556] $($BuildInfo.Message)" Write-Debug "[557] $($BuildInfo.Dir) " throw "Build failed " } #end catch } # end outer try finally { if (-not($noTranscript.IsPresent)) { if ($VerbosePreference -eq "Continue" ) { Stop-Transcript } else { Stop-Transcript | Out-Null } } } #end outer finally } #end process } #end function Set-Alias -Name Build-VisiDb -Value Deploy_VisiDB_v4 Set-Alias -Name Deploy-VisiDB -Value Deploy_VisiDB_v4 function Find-SysadminMembers { <# .SYNOPSIS Looks for sysadmin members in ALL S1 and Caisses Saves results in ONECM.VisiSystem.Control.SysadminMembers Sends an email with results (if any). Caisses down saved in Control.CaisseDown .Description Looks for sysadmin members in ALL S1 and Caisses Saves results in ONECM.VisiSystem.Control.SysadminMembers Sends an email with results (if any). .PARAMETER MailRecipients Recipients for report email Default "listeDba@visilab.ch" .PARAMETER ExcludeList Accepted sysadmin members Default "sa|ssi-dba|ssi-sqladm|visiSQLAdmin .EXAMPLE # Find-SysadminMembers .EXAMPLE # Find-SysadminMembers -MailRecipients 'mircea.nicolescu@visilab.ch' .EXAMPLE # Find-SysadminMembers -ExcludeList 'sa|ssi-dba' #> [CmdletBinding(SupportsShouldProcess)] Param ( [parameter(Mandatory=$false,position=0)] [string] $mailRecipients = 'listeDBA@visilab.ch' , [parameter(Mandatory=$false,position=1)] [string] $excludeList = 'sa|ssi-dba|ssi-sqladm|visiSQLAdmin' ) Begin { } Process{ $srv = 'SRV-ONECM' $dbn = 'VisiSystem' $table = 'Control.SysadminMembers' $tableCaisseDown = 'Control.CaisseDown' $title = 'Non-dba Sysadmin SQL Accounts' # process servers Get-DbaServerRoleMember -SqlInstance $(gvsp) -ServerRole sysadmin | Where-Object Name -notmatch $excludeList | Write-DbaDataTable -SqlInstance $srv -Database $dbn -Table $table -AutoCreateTable -Truncate # process caisses Invoke-Sqlcmd -ServerInstance $srv -Database $dbn -Query "IF OBJECT_Id('$tableCaisseDown','U') IS NOT NULL TRUNCATE TABLE $tableCaisseDown" Get-VisiCaisses -scope Prod | ForEach-Object { Write-Verbose $_.crpos_name if (Test-Connection -ComputerName $($_.crpos_name) -Quiet -Count 1 ) { Get-DbaServerRoleMember -SqlInstance $($_.crpos_name) -ServerRole sysadmin | Where-Object Name -notmatch $excludeList | Write-DbaDataTable -SqlInstance $srv -Database $dbn -Table $table -AutoCreateTable } else { $_ | Write-DbaDataTable -SqlInstance $srv -Database $dbn -Table $tableCaisseDown -AutoCreateTable } } # add time_stamp to Caisses_down $qryAlterTable = "alter table $tableCaisseDown ADD time_stamp datetime2(0) not null default getdate()" invoke-sqlcmd -serverinstance $srv -database $dbn -query $qryAlterTable # send email $qry = " IF EXISTS ( SELECT 1 FROM $dbn.$table ) BEGIN DECLARE @tableHTML NVARCHAR(MAX) ; SET @tableHTML = N'<H1>$title</H1>' + N'<table border=`"1`">' + N'<tr><th>Computer Name</th>' + N'<th>InstanceName</th>' + N'<th>SQL Instance</th>' + N'<th>Role</th>' + N'<th>Name</th>'+ N'</tr>' + CAST ( ( SELECT td = ComputerName, '', td = InstanceName, '', td = SQlinstance, '', td = Role, '', td = Name FROM $dbn.$table ORDER BY ComputerName ASC, [name] ASC FOR XML PATH('tr'), TYPE ) AS NVARCHAR(MAX) ) + N'</table>' ; IF EXISTS ( SELECT 1 from VisiSystem.Control.CaisseDown ) BEGIN DECLARE @tableHTML2 NVARCHAR(MAX) ; SET @tableHTML2 = N'<H1>Caisses down</H1>' + N'<table border=`"1`">' + N'<tr><th>CRPOS Name</th>' + N'<th>Sub short name</th>'+ N'</tr>' + CAST ( ( SELECT td = CRPOS_name, '', td = Sub_short_name FROM VisiSystem.Control.CaisseDown ORDER BY CRPOS_Name ASC FOR XML PATH('tr'), TYPE ) AS NVARCHAR(MAX) ) + N'</table>' ; SELECT @tableHTML = @tableHTML + @tableHTML2 END EXEC msdb.dbo.sp_send_dbmail @recipients='$MailRecipients', @subject = '$title', @body = @tableHTML, @body_format = 'HTML' END " Write-Verbose $qry Invoke-Sqlcmd -ServerInstance $srv -Query $qry } } function Compare-Procedures { <# .SYNOPSIS Compare procedures code and VisiVersion between 2 servers .Description Compare results are saved on Server1.VisiSystem.Control.Objects .PARAMETER SQLInstance1 Server1 Will persist the comparison results in VisiSystem.Control.Objects .PARAMETER SQLInstance2 Server2 .PARAMETER Database1 Database1 .PARAMETER Database2 Database12 .PARAMETER MailRecipients Recipients for report email Default "listeDbaDevSql@visilab.ch;eric.colombara@visilab.ch" .PARAMETER ProcedurePattern TSQL LIKE pattern for procedure name filter .EXAMPLE # Compare-Procedures -SQLInstance1 SRV-ONECM SQLInstance2 SRV-ONEWEB -Database1 Arizona -Database2 Arizona -ProcedurePattern '%sel%' -MailRecipients mircea.nicolescu@visilab.ch .EXAMPLE # $params = @{ SQLInstance1 = 'ONECM' SQLInstance2 = 'BVT1' Database1 = 'Arizona' Database2 = 'Arizona_ref' MailRecipients = 'mircea.nicolescu@visilab.ch' ProcedurePattern = '%' Verbose = $true } Compare-Procedures @params #> [CmdletBinding(SupportsShouldProcess)] Param ( [parameter(Mandatory=$true,position=0)] [ValidateNotNullOrEmpty()] [string] $SQLInstance1 , [parameter(Mandatory=$true,position=1)] [ValidateNotNullOrEmpty()] [string] $SQLInstance2 , [parameter(Mandatory=$true,position=2)] [ValidateNotNullOrEmpty()] [string] $Database1 , [parameter(Mandatory=$true,position=3)] [ValidateNotNullOrEmpty()] [string] $Database2 , [parameter(Mandatory=$false,position=4)] [string] $MailRecipients = 'listeDbaDevSql@visilab.ch;eric.colombara@visilab.ch' , [parameter(Mandatory=$false,position=5)] [string] $ProcedurePattern = '%' ) Begin { If ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { $DebugPreference = "Continue" } else { $DebugPreference = "SilentlyContinue" } try { Invoke-Sqlcmd -ServerInstance $SQLInstance1 -Query "select 1" -ErrorAction Stop -ConnectionTimeout 2 | Out-Null } catch { Throw "Connection to $SQLInstance1 failed" } try { Invoke-Sqlcmd -ServerInstance $SQLInstance2 -Query "select 1" -ErrorAction Stop -ConnectionTimeout 2 | Out-Null } catch { Throw "Connection to $SQLInstance2 failed" } } Process { $ErrorActionPreference = "stop" $server1 = $SQLInstance1 $server2 = $SQLInstance2 # create results table if not exists $resultsTableQry = " IF OBJECT_ID('Control.Objects','U') IS NULL CREATE TABLE Control.[Objects] ( Id INT IDENTITY PRIMARY KEY , Server_1 SYSNAME , Server_2 SYSNAME , [Database_1] SYSNAME , [Database_2] SYSNAME , [Name] SYSNAME , [Type] CHAR(2) , Diff_type VARCHAR(50) , Modify_date_1 DATETIME2(0) , Modify_date_2 DATETIME2(0) , Visi_version_1 CHAR(10) , Visi_version_2 CHAR(10) , Hb_1 VARBINARY(8000) , Hb_2 VARBINARY(8000) , Control_time DATETIME2(0) DEFAULT CURRENT_TIMESTAMP , Control_user SYSNAME DEFAULT CURRENT_USER ) EXEC sp_save_visiVersion 'Control.Objects', '101.2'; " Invoke-Sqlcmd -ServerInstance $Server1 -Database Visisystem -QueryTimeout 5 -Query $resultsTableQry # build collect procs query $qryProcs = " DROP TABLE IF EXISTS #procs ; CREATE TABLE #procs (proc_name SYSNAME PRIMARY KEY, create_Date DATETIME2, modify_date DATETIME2, visi_version CHAR(10), [code] VARCHAR(MAX), hb VARBINARY(8000)) ; INSERT #procs SELECT CONCAT(s.name, '.', p.name) AS [proc_name] , p.create_date , p.modify_date , CONVERT(CHAR(10), v.value) AS visi_version , sm.definition AS [code] , NULL AS hb FROM sys.procedures AS p JOIN sys.schemas AS s ON s.[schema_id] = p.[schema_id] JOIN sys.sql_modules AS sm ON sm.[object_id] = p.[object_id] OUTER APPLY ( SELECT * FROM sys.fn_listextendedproperty('VisiVersion' , 'schema', s.name, 'procedure', p.name, NULL, NULL ) ) v WHERE p.name NOT LIKE 'msmerge%' AND p.is_ms_shipped = 0 --and s.name <>'Control' AND p.name LIKE '$ProcedurePattern' ; UPDATE #procs SET code = REPLACE([code],';','') ; -- eliminate false positives caused by ending semicolon UPDATE #procs SET hb = hashbytes('SHA2_256', [code]) ; ALTER TABLE #procs DROP COLUMN [code] ; SELECT * FROM #procs ; " # collect procs info # create tempdb tables - this must be done manaually as AutoCreate messes up the datatypes $qry = " DROP TABLE IF EXISTS dbo.local_procs CREATE TABLE local_procs (proc_name SYSNAME PRIMARY KEY, create_Date DATETIME2, modify_date DATETIME2, visi_version CHAR(10), hb VARBINARY(8000)) ; DROP TABLE IF EXISTS dbo.remote_procs CREATE TABLE remote_procs (proc_name SYSNAME PRIMARY KEY, create_Date DATETIME2, modify_date DATETIME2, visi_version CHAR(10), hb VARBINARY(8000)) ; " Invoke-Sqlcmd -ServerInstance $server1 -Database Tempdb -Query $qry # populate local_proce and remote_procs Write-Verbose "Collect procs info $server1" Invoke-Sqlcmd -ServerInstance $server1 -Database $database1 -Query $qryProcs -QueryTimeout 10000 | Write-DbaDbTableData -SqlInstance $server1 -Database tempdb -Table dbo.local_procs -Truncate Write-Verbose 'ok' Write-Verbose "Collect procs info $server2" Invoke-Sqlcmd -ServerInstance $server2 -Database $database2 -Query $qryProcs -QueryTimeout 10000 | Write-DbaDbTableData -SqlInstance $server1 -Database tempdb -Table dbo.remote_procs -Truncate Write-Verbose 'ok' # process results Write-Verbose "Process results" $objType = 'P' $qryDiff = " --------------------------- --delete from results table --------------------------- DELETE Visisystem.control.Objects WHERE [Type] = '$objType' AND server_1 = '$server1' AND server_2 = '$server2' AND database_1 = '$database1' AND database_2 = '$database2' ; ----------------------- --miss local (server 1) ----------------------- ;WITH x AS ( SELECT proc_name FROM tempdb.dbo.remote_procs AS rp EXCEPT SELECT proc_name FROM tempdb.dbo.local_procs AS lp ) INSERT [Visisystem].[Control].[Objects]( Server_1 , Server_2 , [Database_1] , [Database_2] , [Name] , [Type] , Diff_type , Modify_date_1 , Modify_date_2 , Visi_version_1 , Visi_version_2 , Hb_1 , Hb_2 ) SELECT '$server1' , '$server2' , '$database1' , '$database2' , rp.proc_name , '$objType' , 'MISS_$Server1' , NULL , rp.modify_date , NULL , rp.visi_version , NULL , NULL FROM tempdb.dbo.remote_procs AS rp JOIN x AS x ON x.proc_name = rp.proc_name ------------------------ --miss remote (server 2) ------------------------ ;WITH y as ( SELECT proc_name FROM tempdb.dbo.local_procs AS lp EXCEPT SELECT proc_name FROM tempdb.dbo.remote_procs AS rp ) INSERT [Visisystem].[Control].[Objects]( Server_1 , Server_2 , [Database_1] , [Database_2] , [Name] , [Type] , Diff_type , Modify_date_1 , Modify_date_2 , Visi_version_1 , Visi_version_2 , Hb_1 , Hb_2 ) SELECT '$server1' , '$server2' , '$database1' , '$database2' , lp.proc_name , '$objType' , 'MISS_$Server2' , lp.modify_date , NULL , lp.visi_version , NULL , NULL , NULL FROM tempdb.dbo.local_procs AS lp JOIN y AS y ON y.proc_name = lp.proc_name ; ------------------------ -- different visiVersion ------------------------ INSERT [Visisystem].[Control].[Objects]( Server_1 , Server_2 , [Database_1] , [Database_2] , [Name] , [Type] , Diff_type , Modify_date_1 , Modify_date_2 , Visi_version_1 , Visi_version_2 , Hb_1 , Hb_2 ) SELECT '$server1' , '$server2' , '$database1' , '$database2' , rp.proc_name , '$objType' , 'DIFF_VISIVERSION' , lp.modify_date , rp.modify_date , lp.visi_version , rp.visi_version , NULL--lp.hb , NULL--rp.hb FROM tempdb.dbo.local_procs AS lp JOIN tempdb.dbo.remote_procs AS rp ON rp.proc_name = lp.proc_name WHERE rp.visi_version <> lp.visi_version --------------------------------- --same VisiVersion different code --------------------------------- INSERT [Visisystem].[Control].[Objects]( Server_1 , Server_2 , [Database_1] , [Database_2] , [Name] , [Type] , Diff_type , Modify_date_1 , Modify_date_2 , Visi_version_1 , Visi_version_2 , Hb_1 , Hb_2 ) SELECT '$server1' , '$server2' , '$database1' , '$database2' , rp.proc_name , '$objType' , 'DIFF_CODE' , lp.modify_date , rp.modify_date , lp.visi_version , rp.visi_version , lp.hb , rp.hb FROM tempdb.dbo.local_procs AS lp JOIN tempdb.dbo.remote_procs AS rp ON rp.proc_name = lp.proc_name WHERE ISNULL(rp.hb,-1) <> ISNULL(lp.hb,-1) AND rp.visi_version = lp.visi_version " # copy to clipboard #[Windows.forms.Clipboard]::SetText($qryDiff) Invoke-Sqlcmd -ServerInstance $server1 -Database Tempdb -Query $qryDiff Write-Verbose 'ok' #send email report $qryMail = " DECLARE @tableHTML NVARCHAR(MAX) ; SET @tableHTML = N'<H1>Procedures Control Report</H1>' + N'<table border=`"1`">' + N'<tr><th>Server 1</th>' + N'<th>Server 2</th>' + N'<th>Database 2</th>' + N'<th>Database 2</th>' + N'<th>Object name</th>' + N'<th>Object type</th>' + N'<th>Diff type</th>' + N'<th>Modify date 1 </th>'+ N'<th>Modify date 2 </th>'+ N'<th>VisiVersion 1 </th>' + N'<th>VisiVersion 2 </th>' + N'<th>Control time </th>' + N'<th>Control user</th></tr>' + CAST ( ( SELECT td = Server_1, '', td = Server_2, '', td = Database_1, '', td = Database_2, '', td = [Name], '', td = [Type], '', td = Diff_type, '', td = ISNULL(CONVERT(CHAR(20),Modify_date_1),'NULL'), '', td = ISNULL(CONVERT(CHAR(20),Modify_date_2),'NULL'), '', td = ISNULL(Visi_version_1,'NULL'), '', td = ISNULL(Visi_version_2,'NULL'), '', td = Control_time , '', td = Control_user FROM VisiSystem.Control.Objects WHERE server_1 = '$server1' AND server_2 = '$server2' AND database_1 = '$database1' AND database_2 = '$database2' AND [Type] = '$objType' ORDER BY Id ASC FOR XML PATH('tr'), TYPE ) AS NVARCHAR(MAX) ) + N'</table>' ; --SELECT @tableHTML EXEC msdb.dbo.sp_send_dbmail @recipients='$mailRecipients', @subject = 'Procedures Version control report $server1 - $server2 ', @body = @tableHTML, @body_format = 'HTML' " Write-Verbose "Send email report" Invoke-Sqlcmd -ServerInstance $Server1 -Query $qryMail Write-Verbose 'ok' } } function Compare-ProcedureCode { <# .SYNOPSIS Compare Stored Procedeure code between 2 servers Requires BeyondCompare installed in "C:\Program Files\Beyond Compare 4" .Description .PARAMETER SQlInstance1 Server #1 .PARAMETER SQLInstance2 Server #2 .PARAMETER Database1 Database on server 1 - default Arizona .PARAMETER Database2 Database on server 2 - default Arizona .PARAMETER ProcedureName Procedure to compare .EXAMPLE # Compare-ProcedureCode -SQLInstance1 srv-onecm -SQLInstance2 srv-oneweb -ProcedureName p_GetNextID .EXAMPLE # $params = @{ SQLInstance1 = 'SRV-ONECM' SQLInstance2 = 'SRV-ONEWEB' Database1 = 'VisiSystem' Database2 = 'VisiSystem' ProcedureName = 'p_visi_purge_agent_history' } Compare-ProcedureCode @params #> [CmdletBinding(SupportsShouldProcess)] Param ( [string]$SQLInstance1 , [string]$SQLInstance2 , [string]$Database1 = 'Arizona' , [string]$Database2 = 'Arizona' , [string]$ProcedureName ) Begin{ If ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { $DebugPreference = "Continue" } else { $DebugPreference = "SilentlyContinue" } } Process { # split proce name - extract schema if ($ProcedureName -match '\.' ) { $schema = ($ProcedureName -split '\.')[0] $object = ($ProcedureName -split '\.')[1] } else { $schema = 'dbo' $object = $ProcedureName } Write-Debug "Schema = $schema Object = $object" #$guid1 = [guid]::NewGuid().ToString() #($file1 = Join-Path -Path $env:TEMP -ChildPath $($guid1 + '.sql')) $file1 = Join-Path -Path $env:TEMP -ChildPath $($ProcedureName + '-'+$SQLInstance1 + '.sql') Write-Debug $file1 #$guid2 = [guid]::NewGuid().ToString() #($file2 = Join-Path -Path $env:TEMP -ChildPath $($guid2 + '.sql')) $file2 = Join-Path -Path $env:TEMP -ChildPath $($ProcedureName + '-'+$SQLInstance2 + '.sql') Write-Debug $file2 #New-Item $file2 -ItemType File $srv1 = New-Object ('Microsoft.SqlServer.Management.Smo.Server') -argumentlist $SQLInstance1 -ea Stop $srv1.Databases[$database1].StoredProcedures[$Object,$schema] | Export-DbaScript -FilePath $file1 -NoPrefix | Out-Null Write-Debug 'srv1 ok' $srv2 = New-Object ('Microsoft.SqlServer.Management.Smo.Server') -argumentlist $SQLInstance2 -ea Stop $srv2.Databases[$database2].StoredProcedures[$object,$schema] | Export-DbaScript -FilePath $file2 -NoPrefix |Out-Null Write-Debug 'srv2 ok ' if ($PSCmdlet.ShouldProcess($ProcedureName,"Comparing on $sqlinstance1, $sqlInstance2")) { set-location "C:\Program Files\Beyond Compare 4" start-process bcompare -ArgumentList "$file1 $file2" } } } function Get-Arc8 { $archived = @('SRV-ACHATS','VI015-S1','VI016-S1','VI017-S1','VI019-S1','VI020-S1','VI021-S1','VI022-S1','VI024-S1','VI025-S1','VI026-S1','VI027-S1','VI028-S1','VI031-S1','VI032-S1','VI035-S1','VI038-S1','VI039-S1','VI040-S1','VI040-S1','VI042-S1','VI042-S1','VI046-S1','VI047-S1','VI047-S1','VI049-S1','VI049-S1','VI050-S1','VI050-S1','VI060-S1','VI512-S1','VI519-S1','VI581-S1','VI583-S1') (Get-VisiServers prod | Where-Object server_name -notin $archived | Where-Object server_name -notmatch 'SRV|PV').server_name } function Export-UDDT { [CmdletBinding(SupportsShouldProcess)] Param ( [parameter(Mandatory=$true,position=0,ValueFromPipeline=$true)] [ValidateNotNullOrEmpty()] [string]$Destination , [parameter(Mandatory=$false,position=1)] [ValidateNotNullOrEmpty()] [string]$Source = 'SRV-ONECM' , [parameter(Mandatory=$false,position=2)] [switch]$ExcludeCash ) Begin { If ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { $DebugPreference = "Continue" } else { $DebugPreference = "SilentlyContinue" } $srvx = New-Object ('Microsoft.SqlServer.Management.Smo.Server') -argumentlist $Source $so = New-DbaScriptingOption $so.ScriptSchema = $true $so.IncludeIfNotExists = $true } Process{ Write-Verbose "Destination: $destination" # process Arizona $srvx.Databases['Arizona'].UserDefinedDataTypes | Export-DbaScript -ScriptingOptionsObject $so -Passthru | ForEach-Object { Write-Debug $_ foreach ($tgt_dbn in @('model','tempdb')) { Invoke-Sqlcmd -ServerInstance $Destination -Database $tgt_dbn -Query $_ } } # process Cash if(-not($ExcludeCash.isPresent)){ $srvx.Databases['ArizonaCASH'].UserDefinedDataTypes | Export-DbaScript -ScriptingOptionsObject $so -Passthru | ForEach-Object { Write-Debug $_ foreach ($tgt_dbn in @('model','tempdb')) { Invoke-Sqlcmd -ServerInstance $Destination -Database $tgt_dbn -Query $_ } } } } } function New-CloneIndex{ <# .SYNOPSIS Clone indexes to another server .Description .PARAMETER .EXAMPLE #> [CmdletBinding(SupportsShouldProcess)] Param ( [parameter(Mandatory=$true,position=0)] [ValidateNotNullOrEmpty()] [string]$Source , [parameter(Mandatory=$true,position=1,ValueFromPipeline=$true)] [ValidateNotNullOrEmpty()] [string]$Destination , [parameter(Mandatory=$true,position=2)] [string]$SourceDatabase , [parameter(Mandatory=$true,position=3)] [string]$DestinationDatabase , [parameter(Mandatory=$true,position=4)] [string]$Table , [parameter(Mandatory=$false,position=5)] [switch]$SaveOldIndex ) Begin { if ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { $DebugPreference = "Continue" } else { $DebugPreference = "SilentlyContinue" } # split table name - extract schema if ($table -match '\.' ) { $schema = ($table -split '\.')[0] $object = ($table -split '\.')[1] } else { $schema = 'dbo' $object = $table } Write-Debug "Schema = $schema Object = $object" # script indexes to apply # NB having this code here willa void the indexes being scripted again for every destination in the pipe $src_srvx = New-Object ('Microsoft.SqlServer.Management.Smo.Server') -argumentlist $Source $guid = [guid]::NewGuid().ToString() $gPath = Join-Path -Path $env:TEMP -ChildPath $guid New-Item $gPath -ItemType Directory -Force | Out-Null $optScript = New-DbaScriptingOption $optScript.IncludeIfNotExists = $true $src_srvx.databases[$Sourcedatabase].tables[$object,$schema].Indexes | Where-Object IndexKeyType -notin (1,2) | Export-DbaScript -ScriptingOptionsObject $optScript -FilePath $(Join-DbaPath $gPath $('new index - '+$table +'.sql')) | Out-Null if ($debugPreference -eq "Continue" ) { invoke-item $gPath } } Process { $tgt_srvx = New-Object ('Microsoft.SqlServer.Management.Smo.Server') -argumentlist $Destination # save target indexes before ovwerwrite if ($SaveOldIndex.IsPresent) { $save_file = Join-DbaPath -Path $env:LOCALAPPDATA 'log' $($($Destination -replace '\\', '-' )+'-'+$DestinationDatabase+'-'+$schema+'.'+$object +'-indexesBeforeOverwrite.log' ) Write-Verbose "Old indexes save file = $save_file" $orig_indexes = $tgt_srvx.Databases[$DestinationDatabase].Tables[$object,$schema].Indexes | Where-Object IndexKeyType -notin (1,2) $orig_indexes | Export-DbaScript -FilePath $save_file -debug:$false | Out-Null if ($debugPreference -eq "Continue") { Invoke-Item $save_file } } # drop target indexes async #$orig_indexes | ForEach-Object { $_.Drop() } $optDrop = New-DbaScriptingOption $optDrop.IncludeIfNotExists = $true $optDrop.ScriptDrops = $true $gPathDrop = Join-Path -Path $env:TEMP -ChildPath $([guid]::NewGuid().ToString()) New-Item $gPathDrop -ItemType Directory -Force | Out-Null Write-Verbose "Idx drop path = $gpathdrop" $tgt_srvx.databases[$DestinationDatabase].tables[$object,$schema].Indexes | Where-Object IndexKeyType -notin (1,2) | Export-DbaScript -ScriptingOptionsObject $optDrop -FilePath $(Join-DbaPath $gPathDrop $('drop old index - ' + $table +'.sql')) | out-null if ($debugPreference -eq "Continue" ) { invoke-item $gPathDrop } New-AsyncIndexDeploy -SQLInstance $Destination -Database $DestinationDatabase -path $gPathDrop # apply indexes to destination asynchroneously Write-Verbose "---`n`nDestination = $destination" New-AsyncIndexDeploy -SQLInstance $Destination -Database $DestinationDatabase -path $gPath } } function New-RefactoryIndex { <# .SYNOPSIS Renames indexes on table according to Visi DB index naming .Description .PARAMETER .EXAMPLE #> [CmdletBinding(SupportsShouldProcess)] Param ( [parameter(Mandatory=$true,position=0)] [ValidateNotNullOrEmpty()] [string]$SQLInstance , [parameter(Mandatory=$true,position=1)] [ValidateNotNullOrEmpty()] [string]$Database , [parameter(Mandatory=$false,position=3,ValueFromPipeline=$true)] [string]$table ) Begin { if ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { $DebugPreference = "Continue" } else { $DebugPreference = "SilentlyContinue" } } Process { Write-Box $table # extract schema from table name if ($table -match '\.' ) { $schema = ($table -split '\.')[0] $tableName = ($table -split '\.')[1] } else { $schema = 'dbo' $tableName = $table } write-debug "Table = $table" write-debug "Schema = $schema" write-debug "TableName = $tableName" # loop thru indexes and build string $str = '' $SMOsrv = New-Object ('Microsoft.SqlServer.Management.Smo.Server') -argumentlist $SQLInstance $SMOsrv.Databases[$Database].Tables[$tableName,$schema].Indexes | Where-Object { $_.IndexKeyType -notin (1,2) } | ForEach-Object { $idx_cols = $($_.IndexedColumns | Where-Object { -not $_.IsIncluded } ) -join ',' $include_cols = $($_.IndexedColumns | Where-Object { $_.IsIncluded } ) -join ',' $str += $("EXEC dbo.sp_visi_index `n`t@table = '$table', `n`t@index_cols = '$idx_cols', `n`t@unique = $([int]$_.IsUnique) " ) if ($include_cols.Length -gt 0 ) { $str += $(", `n`t@include_cols = '" + $include_cols + "'") } $str += "`n" } # proceed to drop/create indexes if ($PSCmdlet.ShouldProcess($table)) { Measure-Command { "`n" $str | Out-Default invoke-sqlcmd -ServerInstance $SQLInstance -Database $Database -Query $str -QueryTimeout 1000 | Out-Default } | Select-Object @{n="Total time elapsed";e={$_.Hours,"h" , $_.Minutes,"m",$_.Seconds,"s"-join " "}} } else { #whatIf true , print script and exit Write-Output $str } } } Function Update-StatsParallel { [CmdLetbinding()] Param ( [parameter(Mandatory=$true,position=0)] [ValidateNotNullOrEmpty()] [string] $SQLInstance , [parameter(Mandatory=$true,position=1)] [string] $Database , [parameter(Mandatory=$true,position=2,ValueFromPipeline=$true)] [string] $Table , [parameter(Mandatory=$true,position=3)] [switch]$WaitForCompletion ) # end param Process { $ErrorActionPreference = 'Stop' # 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 $SQLInstance -Query $qryCheckTraceFlag # log start $qryLog = " DECLARE @logId UNIQUEIDENTIFIER; EXEC dbo.sp_Save_VisiSys_Log @Id = @logId OUTPUT ,@Domain = 'UPDATE STATISTICS',@Module = '$table', @note = '$Database', @message = 'parallel XXL'; SELECT @logId AS [logid]; " $logId = (Invoke-Sqlcmd -ServerInstance $SQLInstance -Query $qryLog ).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 $SQLInstance -Database $Database -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'$Database', --@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 $SQLInstance -Query $qry -DisableVariables ## start job $start_job = "exec msdb.dbo.sp_start_job @job_name = '$job_name'" ; Invoke-Sqlcmd -ServerInstance $SQLInstance -Query $start_job } # wait for completion if ( $WaitForCompletion.IsPresent) { while ($(Get-UpdateStatsRunning -SQLInstance $SQLInstance -table $table -database $database ) -gt 0 ) { Start-Sleep -Seconds 5 } } } #end process } #end function Function Get-UpdateStatsRunning { [CmdLetbinding()] Param ( [string]$SQLInstance , [string]$database , [string]$table ) Process{ $qry = " SELECT COUNT(*) as stats_running FROM sys.dm_exec_requests r OUTER APPLY sys.dm_exec_sql_text(sql_handle) t WHERE session_id != @@SPID -- don't show this query AND session_id > 50 -- don't show system queries AND r.command LIKE 'UPDATE STATISTICS' AND t.[text] LIKE '%$table%' " (Invoke-Sqlcmd -ServerInstance $SQLInstance -Database $database -Query $qry ).stats_running } } 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 #> [CmdLetbinding()] Param ( [parameter(Mandatory=$false,position=0,ValueFromPipeline=$true)] [ValidateNotNullOrEmpty()] [string]$SQLInstance , [parameter(Mandatory=$false,position=1,ValueFromPipeline=$true)] [ValidateNotNullOrEmpty()] [string]$Database , [parameter(Mandatory=$true,position=2)] [ValidateScript({test-path $_ })] [string]$path , [parameter(Mandatory=$false,position=1)] [switch]$KeepJob ) Begin{ if ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { $DebugPreference = "Continue" } else { $DebugPreference = "SilentlyContinue" } } Process{ # get files and create job $operator = 'DBA' Get-ChildItem $path -Recurse -file -filter *.sql | ForEach-Object { Write-debug "Table Name = $($_.BaseName) " $jobName = "## - $SQLInstance - Async Index - ## - $($_.BaseName)" Write-Verbose "Job Name = $jobName" $command = $(Get-Content $_.FullName) -replace "'" , "''" $outputFile = '$(ESCAPE_SQUOTE(SQLLOGDIR))\$(ESCAPE_SQUOTE(JOBNAME))_$(ESCAPE_SQUOTE(STEPID))_$(ESCAPE_SQUOTE(DATE))_$(ESCAPE_SQUOTE(TIME)).log' if ($KeepJob.IsPresent){ $deleteLevel = 0 } else { $deleteLevel = 1 } $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 = 2, @notify_level_netsend = 0, @notify_level_page = 0, @notify_email_operator_name = '$($operator)', @delete_level = $deleteLevel; 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', @retry_attempts = 3, @retry_interval = 3, @database_name = '$($database)' , @command = N'$command' , @output_file_name=N'$outputFile' ; --start job EXEC msdb.dbo.sp_start_job @job_name = '$jobName'" Write-Debug $qry 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-Object 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-VisiServersProd {(Get-VisiServers -scope PROD -IncludeCentrale).server_name } Set-Alias -Name gvsp -Value Get-VisiServersProd function Get-VisiMagsProd {(Get-VisiServers -scope PROD -ExcludeAchats).server_name} Set-Alias -Name gvmp -Value Get-VisiMagsProd function Get-VisiServersRec {(Get-VisiServers -scope REC -IncludeCentrale).server_name} Set-Alias gvsr Get-VisiServersRec function Get-VisiMagsRec {(Get-VisiServers -scope REC -ExcludeAchats).server_name} Set-Alias -Name gvmr -Value Get-VisiMagsRec function Get-VisiServersDev1 {(Get-VisiServers -scope DEV1 -IncludeCentrale).server_name} Set-Alias gvsd1 Get-VisiServersDev1 function Get-VisiMagsDev1 {(Get-VisiServers -scope Dev1 -ExcludeAchats).server_name} Set-Alias -Name gvmd1 -Value Get-VisiMagsDev1 function Get-VisiServersDev2 {(Get-VisiServers -scope DEV2 -IncludeCentrale).server_name} Set-Alias gvsd2 Get-VisiServersDev2 function Get-VisiMagsDev2 {(Get-VisiServers -scope Dev2 -ExcludeAchats).server_name} Set-Alias -Name gvmd2 -Value Get-VisiMagsDev2 function Get-VisiCaissesProd {(Get-VisiCaisses -scope PROD).crpos_name} Set-Alias -Name gvcp -Value Get-VisiCaissesProd function Get-VisiCaissesRec {(Get-VisiCaisses -scope REC).crpos_name} Set-Alias -Name gvcr -Value Get-VisiCaissesRec function Get-VisiCaissesD1 {(Get-VisiCaisses -scope DEV1).crpos_name} Set-Alias -Name gvcd1 -Value Get-VisiCaissesD1 function Get-VisiCaissesD2 {(Get-VisiCaisses -scope DEV2).crpos_name} Set-Alias -Name gvcd2 -Value Get-VisiCaissesD2 Function Get-VisiServers { <# .SYNOPSIS Returns Visilab Servers Dev, Rec or Prod .Description Returns Visilab Servers .PARAMETER Scope .PARAMETER IncludeCentrale .PARAMETER ExcludeAchats .EXAMPLE Get-VisiServers -Scope REC #> [CmdLetbinding()] Param ( [parameter(Mandatory=$false,position=0)] [ValidateSet('Dev1','Dev2', 'Rec', 'Prod', 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=3)] # [switch] $Simple = $false , #[parameter(Mandatory=$false,position=4)] # [switch] $ExcludePreviousRelease = $false ) #end param Begin { if ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { $DebugPreference = "Continue" } else { $DebugPreference = "SilentlyContinue" } } Process{ switch ($scope) { 'DEV1' { $srv = 'DEV1OCM'} 'DEV2' { $srv = 'DEV2OCM'} 'REC' { $srv = 'ONECMR'} 'PROD' { $srv = 'ONECM'} } $qry = "select * from Arizona.dbo.v_servers where 1=1 " if (-not($IncludeCentrale.IsPresent)) { $qry += " AND [server_name] NOT LIKE '%ONECM%' AND [server_name] NOT LIKE '%DEV[1-3]OCM%'" } if ($ExcludeAchats.IsPresent){ if ($scope -match 'DEV'){ $xaPattern = '%DEV[1-9]OA%' } else { $xaPattern = '%ACHATS%' } $qry += " AND [server_name] NOT LIKE '$xaPattern'" } #run query Write-Debug $qry Invoke-Sqlcmd -ServerInstance $srv -database Arizona -Query $qry | Sort-Object server_name } # end process } 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 | Where-Object {$_.Name -match '^LSRestore.*Arizona$'} } 'Arc' { $jobs = $SMOserver.JobServer.Jobs | Where-Object {$_.Name -match '^LSRestore.*Archive$'} } 'Both' { $jobs = $SMOserver.JobServer.Jobs | Where-Object {$_.Name -match '^LSRestore'} } } #Write-Debug $jobs | select Name $jobs | ForEach-Object { 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" if ($IncludeIndex.IsPresent) { $exclude = [char](0) # use something that won't show up in a file name } else { $exclude = 'NORUN|INDEX' } switch ($buildAction.ToUpper()) { 'NEW' { $files = Get-ChildItem -Path $ReleasePath -Recurse -File -Filter *.sql | Where-Object {$_.FullName -imatch '100\.New' -and $_.FullName -inotmatch $exclude } } 'PARTIALBUILD'{ $files = Get-ChildItem -Path $ReleasePath -Recurse -File -Filter *.sql | Where-Object {$_.FullName -inotmatch $exclude } } 'UPGRADEBD' { $files = Get-ChildItem -Path $ReleasePath -Recurse -File -Filter *.sql | Where-Object {$_.FullName -imatch '800\.UpgradeBD' -and $_.FullName -inotmatch $exclude } } 'UPGRADESOFT' { $files = Get-ChildItem -Path $ReleasePath -Recurse -File -Filter *.sql | Where-Object {$_.FullName -imatch '801\.Upgrade' -and $_.FullName -inotmatch $exclude } } 'UPGRADEBOTH' { $files = Get-ChildItem -Path $ReleasePath -Recurse -File -Filter *.sql | Where-Object {($_.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 Function Deploy_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)] [string] $srv = $env:COMPUTERNAME , [parameter(Mandatory=$false,position=1)] [ValidateScript({test-path $_})] [string] $relPath = "D:\Projets BDD\70 - Common Tools and Helpers" ) Process { If ( $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent ) { $DebugPreference = "Continue" } else { $DebugPreference = "SilentlyContinue" } write-debug $relPath Build-VisiDb -srv $srv -dbn Master -ReleasePath $relPath -IncludeIndex } # end process } # end function #Set-Alias -Name Build-SQLCommonTools -value Build_VisiSQLCommonTools Set-Alias -Name Deploy-SQLCommonTools -value Deploy_VisiSQLCommonTools Function New-RefreshEnv { [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" } } Process{ # log and transcript ops New-Item "$env:LOCALAPPDATA\Log" -ItemType Directory -Force $log = Join-Path -Path $env:LOCALAPPDATA -ChildPath "Log\Refresh.$($destination).$(get-date -f yyyy-MM-dd).log" try{ stop-transcript|out-null } catch [System.InvalidOperationException]{} Start-Transcript -Path $log -Append #load hash table $h = @{} $listDBMag = @('VisiTemp','Arizona','ArizonaCASH','Archive','ArizonaLD','VisiAudit') $listDbCentrale = @('Arizona','ArizonaCASH','Archive','Elvira','ElviraPV','VisiTemp','OneImport','OneShare','OneShareArchive','OneCustomer') { $h.Add('DEV1OA' , @('SRV-ACHATS' , $listDBMag)) $h.Add('DEV1OCM' , @('SRV-ONECM' , $listDbCentrale)) $h.Add('DEV1OM' , @('VI022-S1' , $listDBMag)) $h.Add('DEV1OM2' , @('PV421-S1' , $listDBMag)) $h.Add('DEV1OM3' , @('VI015-S1' , $listDBMag)) $h.Add('DEV1OW' , @('SRV-ONEWEB' , $listDBMag)) } $h.Add('DEV2OA' , @('SRV-ACHATS' , $listDBMag)) $h.Add('DEV2OCM' , @('SRV-ONECM' , $listDbCentrale)) $h.Add('DEV2OM' , @('VI024-S1' , $listDBMag)) $h.Add('DEV2OM2' , @('PV421-S1' , $listDBMag)) $h.Add('DEV2OM3' , @('SRV-ATWORK' , $listDBMag)) $h.Add('DEV2OW' , @('SRV-ONEWEB' , $listDBMag)) $h.Add('SRV-ACHATSR' ,@('SRV-ACHATS' , $listDBMag)) $h.Add('SRV-ATHOMER' ,@('SRV-ATHOME' , $listDBMag)) $h.Add('SRV-ATWORKR' ,@('SRV-ATWORK' , $listDBMag)) $h.Add('SRV-MAG1' ,@('VI022-S1' , $listDBMag)) $h.Add('SRV-MAG2' ,@('VI031-S1' , $listDBMag)) $h.Add('SRV-MAG3' ,@('VI015-S1' , $listDBMag)) $h.Add('SRV-ONECMR' ,@('SRV-ONECM' , $listDbCentrale)) $h.Add('SRV-ONEWEBR' ,@('SRV-ONEWEB' , $listDBMag)) $h.Add('SRV-PV1' ,@('PV420-S1' , $listDBMag)) $h.Add('SRV-PV2' ,@('PV421-S1' , $listDBMag)) $h.Add('STRATEGIC' ,@('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\RefreshEnv\$destination" New-Item $sharedPath -ItemType Directory -Force "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-Object @{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-File $( Join-Path -Path $env:TEMP -ChildPath "RepairOrphans.$($destination).$(get-date -f yyyy-MM-dd).log") 'ok' ## post restore ops Measure-Command{ $h.$destination[1] | ForEach-Object { "Set recovery mode and Remove replication {0}" -f $_ | Out-Default ## NB Try catch this MF next time Invoke-Sqlcmd -ServerInstance $destination -Query "exec sp_killall '$_'; alter database [$_] set recovery simple ; exec sp_removeDbReplication '$_' ; " -QueryTimeout 10000 | Out-Default ## end try catch } }| Select-Object @{n="Total time elapsed";e={$_.Hours,"h" , $_.Minutes,"m",$_.Seconds,"s"-join " "}} "ok" } # end process End { 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 | ForEach-Object { 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" } } Process{ switch -regex ($scope) { 'DEV1' { $srv = 'DEV1OCM';break } 'DEV2' { $srv = 'DEV2OCM';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 } # end process } 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-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 | ForEach-Object { $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 |