Twitter

Follow SQLQuill on Twitter

Subscribe

MN Pass

Powershell Script for SQLSaturdays and Twitter

SQL Saturdays and Twitter go together like peas and carrots. I’ve found the networking page of any SQL Saturday site is very valuable to not only get in contact with people about the event, but also to stay in contact and build long term relationships. Helping plan, organize and speak at SQLSaturday #99, I didn’t want to loose the conncections I had made, so I decided to check out all the twitter accounts of the people who had registered for for it.

What’s the easiest way to do this? POWERSHELL!!!

I stumbled a few times (one time I opened 83 tabs in Chrome and had to stop using twitter for an hour), but here is the script I came up with.

Notes on the script:

#--------------------------------------------------------------------------------------
#Open a tab in Chrome for each twitter account on a SQLSaturday Networking Page
#Created by Andy Lohn - http://www.sqlfeatherandquill.com/
#--------------------------------------------------------------------------------------

$url = "http://www.sqlsaturday.com/99/networking.aspx" #Change this for any SQLSaturday Networking Page
[int]$StartCount = 0
[int]$PageCount = 4 #note this is 0 relative, so this plus 1 for number of tabs to be opened

$chrome = (gi ~\AppData\Local\Google\Chrome\Application\chrome.exe ).FullName
#This didn’t work on one of my machines, so I just set it to the full path of chrome and it worked.
$webclient = New-Object system.net.webclient
$file1="c:\temp\SQLSatDownload.txt"
$file2="c:\temp\SQLSatList.txt"
$file3="c:\temp\SQLSatListwithAddress.txt"
$TURL = "www.twitter.com/"
$file4="c:\temp\SQLSatCounter.txt"

#Create the files if they don't exist
If (!(Test-Path $file1) )
{New-Item $file1 -Type file}
If (!(Test-Path $file2) )
{New-Item $file2 -Type file}
If (!(Test-Path $file3) )
{New-Item $file3 -Type file}

#Set the counter to keep track for multiple runs - 0 if new
If (Test-Path $file4)
{$SCWork = (get-content $file4)
[int]$StartCount = $SCWork.ToString()}
Else
{New-Item $file4 -Type file
add-content $file4 1
[int]$StartCount = 0}

If ($StartCount -eq 0)  #Populate the local file.
{Clear-Content $file1
$webclient.DownloadFile($url,$file1)

$test = get-content $file1
Clear-Content $file2
Clear-Content $file3
$Tester = $test | Select-String -pattern "<a href=""<a href="http://www.twitter.com/"">http://www.twitter.com/"</a> |
% {$_ -replace "<span id=""ContentPlaceHolder1.*<a href="http://www.twitter.com/"">http://www.twitter.com/"</a>, ""} |
% {$_ -replace """ class=""noarrrow"">.*</span>", ""} |
% {$_ -replace "<a href="http://twitter.com/#!/"">http://twitter.com/#!/"</a>, ""} |
% {$_ -replace "                    ", ""} |
where {$_ -ne ""}

foreach ($T in $Tester)
{Add-content $file3 ($TURL + $T)}
}
$TestMethod = (Get-Content $file3)[$StartCount .. ($StartCount + $PageCount)]     $TestMethod | % { &amp; $chrome $_ }
Clear-Content $file4
Add-Content $file4 ($StartCount + $PageCount + 1)

#To restart or change url, run this:
#remove-item $file4

This has to be real easy to change for linkedin – I’m more a twitter guy at this point.  If you do alter it, to work for linkedin, let me know!

Add a Non-Nullable Column to a Table with a Non-Auto Generated Default Name

I’ve been a stickler for default names since reading Jason Strate’s (blog/twitter) post on cleaning up auto-generated names.  Today I had to create a non-nullable column with a default – can I do it in one step?  Yep – here’s an example:

ALTER TABLE <<TABLENAME>> ADD <<COLUMNNAME>> <<TYPE>> NOT NULL CONSTRAINT <<DEFAULTNAME>> DEFAULT (<<Value>>)

Here’s the example in action:

Create table Testtable
(id int)

Insert Testtable Values (1),(2),(3),(4),(5)

ALTER TABLE Testtable ADD DefaultTest BIT NOT NULL CONSTRAINT DF_Testtable_DefaultTest DEFAULT (0)

Select * from Testtable

--/*Now to drop this column, do it in this order */
Alter table Testtable alter column DefaultTest  bit null
Alter table Testtable Drop constraint DF_Testtable_DefaultTest
Alter table Testtable DROP column DefaultTest

How To: Replace a string in all files in a directory with Powershell

Today I realized I made a fairly significant mistake.  I had misspelled a column name in a bunch of procedures and views that I had updated.  Not a big deal, except each procedure and view was a file and I had about 75 files.  Only a few of them contained this change, I don’t know which ones, but most of them had other changes.  What to do…

  • I could manually check all files with a few routine of Keystrokes – that might take an couple of hours.
  • I could check sysdepends for dependancies – nope none of the procedures have been executed.
  • I could check syscomments for the column name – that would kind of work, but I would still need to manually update it.
  • Powershell!!  I could find and replace in the files and execute them as well!

I used the following sites as they have good examples.

Here’s what I came up with:

##Finds all the occurrences in the Views folder##
foreach ($f in Get-ChildItem -path "C:\Temp\Views\" -Filter *.sql | sort-object)
{$Location = $f.fullname
Select-String -path $Location -pattern "Andee"| out-file -filePath "C:\Temp\ListoObjects.txt" -append}

##Replaces all the occurrences in the Views folder##
foreach ($f in Get-ChildItem -path "C:\Temp\Views\" -Filter *.sql | sort-object)
{(Get-Content $f.fullname) |
Foreach-Object {$_ -replace "Andee", "Andy"} |
Set-Content $f.fullname}

How To: find if a stored procedure has been run recently

Today I was asked which procedure (of two with similar names) is used in production.  Looking at the naming convention, I had a guess, but I needed proof as we are looking to clean up old unused procedures.  So I found this article Monitoring Stored Procedure Usage at Database Journal.  I modified the script to this:

Select DB_NAME(st.dbid) DBName
    ,OBJECT_SCHEMA_NAME(st.objectid,dbid) SchemaName
    ,OBJECT_NAME(st.objectid,dbid) StoredProcedure
    ,max(cp.usecounts) Execution_count
FROM sys.dm_exec_cached_plans cp
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st
where DB_NAME(st.dbid) = '<<SET DBNAME HERE>>'
and cp.objtype = 'proc'
and OBJECT_NAME(st.objectid,dbid) in ('<<LIST PROCS HERE>>')
Group by cp.plan_handle, DB_NAME(st.dbid),
OBJECT_SCHEMA_NAME(objectid,st.dbid),
OBJECT_NAME(objectid,st.dbid)
order by max(cp.usecounts) desc

How To: Execute all SQL files in a Directory with Powershell

I’ve got a lot of changed altered procedures for a project I’m working on.  I’ve been altering a lot of data in my test database, so I needed to restore my database and apply the changes I’ve made.  The easy way to do would be a powershell script.  Here’s what I found.

From Martin Bell for the post, “Executing all .SQL files in a directory with Powershell”  Thank you Martin!

I also used twitter and asked #SQLHELP and SQLSoldier responded with this in about 3 minutes.  Very impressive!

Get-ChildItem -Path "C:\SQLScripts" -Filter "*.sql" | % {invoke-sqlcmd -InputFile $_.FullName}

Here’s what I altered Martin’s script to:

foreach ($f in Get-ChildItem -path "C:\SQLScripts\" -Filter *.sql | sort-object)
{
$out = "C:\SQLScripts\OUTPUT\" + $f.name.split(".")[0] + ".txt" ;
invoke-sqlcmd –ServerInstance <<ServerName>> -Database <<DBName>> -InputFile $f.fullname | format-table | out-file -filePath $out
}

Here’s all the info on the Invoke-SQLCMD from MSDN.

How to: Find the Job Step Duration History of a Scheduled Job – TSQL Style

I’ve got a new step in a job that I’m concerned about the duration.  Here’s a script to get the duration of a specific step of a job.  Note I found that whole conversion of the Run_DateTime column from Ramblings of a DBA – Tara Kizer – kudos, Tara.

Declare @JobName varchar(255),
@StepName varchar(255)
Set @JobName = '<<Enter Job Name Here>>'
Set @StepName = '<<Enter Job Step Name Here>>'

Select top 1000 run_datetime = CONVERT(DATETIME, RTRIM(run_date)) +
(run_time * 9 + run_time % 10000 * 6 + run_time % 100 * 10) / 216e4,
run_duration = Left(RIGHT('000000' + CONVERT(varchar(6), run_duration), 6), 2)+':'
+ Substring(RIGHT('000000' + CONVERT(varchar(6), run_duration), 6), 3, 2)+':'
+ Right('00' + CONVERT(varchar(6), run_duration), 2),
SJ.name,
SJH.step_name
from msdb.dbo.sysjobs SJ
Join msdb.dbo.sysjobhistory SJH on SJH.job_id = SJ.job_id
where SJ.name = @JobName
and SJH.step_name = @StepName
Order by run_datetime desc  --Use this to find the most recent
--Order by run_duration desc  --Use this to find the slowest

How To: Send a CTRL + ALT + Delete to an RDP Session

I had to change my password today and the easiest way, at my work, is to RDP to a server in each of the domains.  I couldn’t remember how to send the CTRL + ALT + Delete to a RDP/Terminal Server session. 

It is:

CTRL + ALT + End

Here’s a page from mydigitallife that has a few other keyboard short cuts.

How To: Set the Default Scripting Options in SQL Server Management Studio

I just spent 10 minutes looking for this, it’s very simple and fairly obvious.  I’m posting it so I don’t forget it and hopefully it may help others.

I’ve got to script out all tables, indexes, primary keys, foreign keys, defaults and the collation of all tables in all of our databases.  They all have to be the same style and the options I have to choose are slightly different than the defaults.  To make fast work of this, I’ll change the defaults to be exactly what I want then from my Central Management Server, I script each and every database I need.

Here’s how to set the defaults:

In SQL Server Management Studio, go to Tools –> Options.  Expand the SQL Server Object Explorer list and select Scripting.  Change what you want, close this window and Ta-Da the next time you generate scripts, the defaults are set.

 Tools --> Options

How To: Move Central Management Server Groups and Servers from one server to another

Here’s a script I came up with to move my central management server’s Groups and Server from one server to another.  I know it doesn’t make a ton of sense to do this, but I started testing the CMS setup on a test server and it’s worked so well, we wanted to put it on a production server.  There are two scripts that are run on the source server that create scripts to run on the destination server.

/*
--Verify you've got the correct groups.
Select * from dbo.sysmanagement_shared_server_groups_internal
where is_system_object = 0 --ignore the builtin groups.
*/
Select '
Declare @server_group_id int
EXEC msdb.dbo.sp_sysmanagement_add_shared_server_group @parent_id=1, @name=N''' + name
+ ''', @description=N''' + description + ''', @server_type=0, @server_group_id=@server_group_id OUTPUT'
+ CHAR(13) + CHAR(10)
+ 'Go'
from dbo.sysmanagement_shared_server_groups_internal
where is_system_object = 0 --ignore the builtin groups.

Again, run the output of this on the destination server.

Here’s the script to move the servers with their groups – note the group id is dynamic, so even if the destination server has more groups, it will figure out the correct one.

Select
'Declare @SGID int, @SGName nvarchar(255)
Set @SGName = ''' + SGI.name + '''
Select @SGID = server_group_id from dbo.sysmanagement_shared_server_groups_internal
where name = @SGName
Declare @server_id int
EXEC msdb.dbo.sp_sysmanagement_add_shared_registered_server @server_group_id=@SGID, @name=N''' +
RSI.name + ''', @server_name=N''' + RSI.server_name + ''', @description=N''' + RSI.description + ''', @server_type=0, @server_id=@server_id OUTPUT'
+ CHAR(13) + CHAR(10)
+ 'Go'
from dbo.sysmanagement_shared_registered_servers_internal RSI
Join dbo.sysmanagement_shared_server_groups_internal SGI on RSI.server_group_id = SGI.server_group_id

Finally, run the output of this on the destination server.

Here’s a couple of resources I used to figure this stuff out:

How to: Find the backup history of a DB – TSQL Style

There’s been many times I’ve tried to find the backup history of a database.  Questions like when was the last backup taken?  Where was it backed up to?  etc.  I googled a script for this and I used MSSQLTips as a baseline – found here – then altered it to this:

Declare @DBName varchar(255)

Set @DBName = '<<Database Name Here>>'

SELECT  top 10
@@ServerName AS Server,
BUS.database_name,
BUS.backup_finish_date,
CASE BUS.type
WHEN 'D' THEN 'Database'
WHEN 'L' THEN 'Log'
END AS backup_type,
BUS.backup_size,
BUMF.physical_device_name
FROM   msdb.dbo.backupmediafamily  BUMF
INNER JOIN msdb.dbo.backupset BUS ON BUMF.media_set_id = BUS.media_set_id
WHERE BUS.database_name = @DBName
And BUS.type = 'D'
ORDER BY BUS.backup_finish_date desc