“PowerShell Query for the T-SQL Developer” Slide deck and samples

Once again, Thanks! to Patrick LeBlanc for allowing me to present at today’s (02/15/2012) SQLLunch.com.  It was a Great! turned out with over 60 people attending.  To You All THANKS!!  (Recorded session will be available)

Well, here’s my slide deck presentation, and the sample Demo scripts:

Also, I included the following comparison chart that help in your quest to adopt PowerShell.  This excel file is also included in the zipped file.  This is what I covered today except for “Sum”.

I just realized that this topic could evolved to include a Part II where I could show more on: Group, Sum, Logic, and Functions.  So, later on, I will be posting more information the next “PowerShell Query for the T-SQL Developer” Part II.

Stay Tuned!!

PowerShell Start-Demo now allows multi-lines one-liner

Well, I just couldn’t stop making necessary changes to this great presenter tool.  So, now Start-Demo will process your multi-lines one-liners which this couldn’t be done in the previous version.

So, a good example of a one-liner having line continuation, using the Send-MailMessage cmdlet, where we can use the “`” tick to separate the long command line with its parameters:

[sourcecode language=”powershell”]
## – Send email notification:
Send-MailMessage `
-To ‘Userto@Company1.com’ `
-From ‘SenderFrom@Company2.com’ `
-Subject ‘Test send from email’ `
-Body ‘Check email!’ `
-SmtpServer ‘Exchnage.Mailserver.com’
[/sourcecode]

Here’s an example of how it look like using “Start-Demo” in StudioShell:

And, here’s the updated Start-DemoSS.ps1 Version 2.0A 2.0B (02/12/2012):
(apologies for the previous code posted here. It somehow I posted a bad code but I fix it tonight)

[sourcecode language=”powershell”]
###########################################################################
# Original Version: 1.1
# Updated to Version 2.0B, Maximo Trinidad, 02/12/2012
#————————————————————————–
# Comments:
# 1. Customized the foreground color to Cyan and backgroundColor to Black.
# 2. Created a Dump color to default to White.
# 3. Added to put back the default foreground and background colors.
# 4. Commented out the ‘(!) Suspense’ option because Studio Shell can’t
# handle "$host.NestedPrompt".
# 5. Modify the Help menu to acomodate changes.
# 6. Commented out all "$Host.UI.RawUI.WindowTitle".
# 7. Replaced all "[System.Console]::ReadLine()" with "Read-Host".
# 8. Added an end of results ‘write-host"– Press Enter to continue –"’
# follow with a read-host similate a pause.
#
# Modifications:
# 02/10/2012 – Add section identify oneliners with continuation tick "`".
# 02/10/2012 – Cleanup all unused V1 lines.
# 02/10/2012 – Make code to properly display continuation lines.
# 02/12/2012 – Fix info on Start time and duration.
# 02/12/2012 – Adjust execution message spacing.
#
###########################################################################

function Start-Demo
{
param($file=".\demo.txt", [int]$command=0)

## – Saved previous default Host Colors:
$defaultForegroundColor = $host.UI.RawUI.ForegroundColor;
$defaultBackgroundColor = $host.UI.RawUI.BackgroundColor;

## – Customizing Host Colors:
$host.UI.RawUI.ForegroundColor = "Cyan";
$host.UI.RawUI.BackgroundColor = "Black";
$CommentColor = "Green"
$MetaCommandColor = "Cyan"
$DumpColor = "White"
$otherColor = "Yellow"
Clear-Host

## – setting demo variables:
$_Random = New-Object System.Random
$_lines = @(Get-Content $file)
$Global:starttime = [DateTime]::now
$_PretendTyping = $true
$_InterkeyPause = 100
$Global:Duration = $null

Write-Host -for $otherColor @"
Start-Demo: $file – Start time: $starttime
Version 2.0B (02/12/2012)
NOTE: Start-Demo replaces the typing but runs the actual commands.
.

"@
$continuation = $false;

# We use a FOR and an INDEX ($_i) instead of a FOREACH because
# it is possible to start at a different location and/or jump
# around in the order.
for ($_i = $Command; $_i -lt $_lines.count; $_i++)
{
if ($_lines[$_i].StartsWith("#"))
{
Write-Host -NoNewLine $("`n[$_i]PS> ")
Write-Host -NoNewLine -Foreground $CommentColor $($($_Lines[$_i]) + " ")
continue
}
else
{
# Put the current command in the Window Title along with the demo duration
$Global:Duration = [DateTime]::Now – $Global:StartTime
Write-Host -NoNewLine $("`n[$_i]PS> ")
$_SimulatedLine = $($_Lines[$_i]) + " "

for ($_j = 0; $_j -lt $_SimulatedLine.Length; $_j++)
{
Write-Host -NoNewLine $_SimulatedLine[$_j]

if ($_PretendTyping)
{
if ([System.Console]::KeyAvailable)
{
$_PretendTyping = $False
}
else
{
Start-Sleep -milliseconds $(10 + $_Random.Next($_InterkeyPause))
};
};

} # For $_j
$_PretendTyping = $true

} # else

if($_Lines[$_i] -notmatch ‘`’)
{
#Write-Host "Yes $($_Lines[$_i])" -BackgroundColor white -ForegroundColor red;
$_input = Read-Host;
} #else { $continuation = $true}

switch ($_input)
{
################ HELP with DEMO
"?"
{
Write-Host -ForeGroundColor Yellow @"
——————————————————————————–
Start-Demo – Updated to Version 2.0B (12/12/2012)
Help Running Demo: $file
.
(#x) Goto Command #x (b) Backup (?) Help
(fx) Find cmds using X (q) Quit (s) Skip
(t) Timecheck (d) Dump demo (px) Typing Pause Interval
.
NOTE 1: Any key cancels "Pretend typing" for that line. Use unless you
want to run a one of these meta-commands.
.
NOTE 2: After cmd output, enter to move to the next line in the demo.
This avoids the audience getting distracted by the next command
as you explain what happened with this command.
.
NOTE 3: The line to be run is displayed in the Window Title BEFORE it is typed.
This lets you know what to explain as it is typing.
.
NOTE 4: Although this script is functional try not to "Goto" a continuation
one-liner or it will go to a continues loop. I will correct this sympton
soon. (02/12/2012)
———————————————————————————
"@;
Write-Host "– Press Enter to continue –" -BackgroundColor white `
-ForegroundColor Magenta;
Read-Host; cls;
$_i -= 1
}

#################### PAUSE
{$_.StartsWith("p")}
{
$_InterkeyPause = [int]$_.substring(1)
$_i -= 1
}

#################### Backup
"b"
{
if($_i -gt 0)
{
$_i —

while (($_i -gt 0) -and ($_lines[$($_i)].StartsWith("#")))
{
$_i -= 1
}
}

$_i —
$_PretendTyping = $false
}

#################### QUIT
"q"
{
Write-Host -ForeGroundColor $OtherColor ""
$host.UI.RawUI.ForegroundColor = $defaultForegroundColor;
$host.UI.RawUI.BackgroundColor = $defaultBackgroundColor;
cls;
return
}

#################### SKIP
"s"
{
Write-Host -ForeGroundColor $OtherColor ""
}

#################### DUMP the DEMO
"d"
{
for ($_ni = 0; $_ni -lt $_lines.Count; $_ni++)
{
if ($_i -eq $_ni)
{
Write-Host -ForeGroundColor Yellow "$("*" * 25) >Interrupted< $("*" * 25)"
}
Write-Host -ForeGroundColor $DumpColor ("[{0,2}] {1}" -f $_ni, $_lines[$_ni])
}
$_i -= 1
Write-Host "– Press Enter to continue –" -BackgroundColor white `
-ForegroundColor Magenta;
Read-Host; cls;
}

#################### TIMECHECK
"t"
{
$Global:Duration = [DateTime]::Now – $Global:StartTime
Write-Host -ForeGroundColor $OtherColor $("Demo has run {0} Minutes and {1} Seconds`nYou are at line {2} of {3} " `
-f [int]$Global:Duration.TotalMinutes,[int]$Global:Duration.Seconds,$_i,($_lines.Count – 1))
$_i -= 1
}

#################### FIND commands in Demo
{$_.StartsWith("f")}
{
for ($_ni = 0; $_ni -lt $_lines.Count; $_ni++)
{
if ($_lines[$_ni] -match $_.SubString(1))
{
Write-Host -ForeGroundColor $OtherColor ("[{0,2}] {1}" -f $_ni, $_lines[$_ni])
}
}
$_i -= 1
};

##################### SUSPEND # –> not working in StudioShell: help (!) Suspend (not working)
#
# {$_.StartsWith("!")}
# {
# if ($_.Length -eq 1)
# {
# Write-Host -ForeGroundColor $CommentColor ""
# function Prompt {"[Demo Suspended]`nPS>"}
# $host.EnterNestedPrompt()
# }else
# {
# trap [System.Exception] {Write-Error $_;continue;}
# Invoke-Expression $(".{" + $_.SubString(1) + "}| out-host")
# }
# $_i -= 1
# }
# ——————————————————————————–

#################### GO TO
{$_.StartsWith("#")}
{
$_i = [int]($_.SubString(1)) – 1
$Scriptline = $null;
$continuation = $false;
continue
}

#################### EXECUTE
default
{
trap [System.Exception] {Write-Error $_;continue;};
## – 02/10/2012-> Commented out original line below
# Invoke-Expression $(".{" + $_lines[$_i] + "}| out-host")

## – add section identify oneliners with continuation tick:
[string] $Addline = $null;
if($_lines[$_i] -match ‘`’)
{
#Write-Host " Found tick = $($_lines[$_i])" -ForegroundColor yellow;
$Addline = $_lines[$_i].replace(‘`’,”).tostring()
$Scriptline += $Addline;
$continuation = $true;
}
else
{
$Scriptline += $_lines[$_i].ToString();
$continuation = $false;
};
if($continuation -eq $false)
{
## – Executive:
Write-Host " `r`n`t Executing Script…`r`n" -ForegroundColor $otherColor;
Invoke-Expression $(".{" +$Scriptline + "}| out-host")
}
## – ——————————————————————–
if($continuation -eq $false)
{
Write-Host "`r`n";
Write-Host "– Press Enter to continue –" -ForegroundColor Magenta `
-BackgroundColor white;
$Global:Duration = [DateTime]::Now – $Global:StartTime
Read-Host;
$Scriptline = $null;
};
}
} # Switch
} # for
## Next three list to put backl the console default colors and do a clear screen:
$host.UI.RawUI.ForegroundColor = $defaultForegroundColor;
$host.UI.RawUI.BackgroundColor = $defaultBackgroundColor;
cls;
$Global:Duration = [DateTime]::Now – $Global:StartTime; Write-Host "`r`n";
Write-Host "Start-Demo of $file completed:" -ForegroundColor $otherColor;
Write-Host -ForeGroundColor Yellow $("Total minutes/sec: {0}.{1}, Date: {2}" `
-f [int]$Global:Duration.TotalMinutes, [int]$Global:Duration.Seconds, [DateTime]::now);
} # function
[/sourcecode]

Have Fun with it!

PowerShell Start-Demo makeover for StudioShell

I blogged about a nice Visual Studio addon “StudioShell” that fits very well with SSMSSQL Server Management Studio 2012“, and I found this tool very useful for presenting.  But, when I try running the (long time) famous “Start-Demo” script, it gave me some errors.  Well, Thanks (again) to StudioShell developer Jim Christoper, he gave me a hint to why this was happenning.  Basically, this old “Start-Demo” uses some .NET calls which StudioShell can’t interpret because of the way it was develop, so it need a makeover.

So, I proceed to dive into the code and make some basic changes so it can work inside StudioShell.  Here’s how it looks running it from SSMS executing a demo script, and asking for (?) Help:

Start-Demo running in StudioShell

I change the color scheme, and added a message pause after displaying the result of the onliner.

Showing some of the changes

Also, the new function will work on a normal PowerShell console, and at the end of the start-demo it will put back your default console colors.

Here’s the updated “Start-DemoSS.ps1“code:

[sourcecode language=”powershell”]
###########################################################################
# Original Version: 1.1
# Updated to Version 2.0, Maximo Trinidad, 02/09/2012
#————————————————————————–
# Comments:
# 1. Customized the foreground color to Cyan and backgroundColor to Black.
# 2. Created a Dump color to default to White.
# 3. Added to put back the default foreground and background colors.
# 4. Commented out the ‘(!) Suspense’ option because Studio Shell can’t
# handle "$host.NestedPrompt".
# 5. Modify the Help menu to acomodate changes.
# 6. Commented out all "$Host.UI.RawUI.WindowTitle".
# 7. Replaced all "[System.Console]::ReadLine()" with "Read-Host".
# 8. Added an end of results ‘write-host"– Press Enter to continue –"’
# follow with a read-host similate a pause.
###########################################################################

function Start-Demo
{
param($file=".\demo.txt", [int]$command=0)

## – Saved previous default Host Colors:
$defaultForegroundColor = $host.UI.RawUI.ForegroundColor;
$defaultBackgroundColor = $host.UI.RawUI.BackgroundColor;

## – Customizing Host Colors:
$host.UI.RawUI.ForegroundColor = "Cyan";
$host.UI.RawUI.BackgroundColor = "Black";
$CommentColor = "Green"
$MetaCommandColor = "Cyan"
$DumpColor = "White"
Clear-Host

## – setting demo variables:
$_Random = New-Object System.Random
$_lines = @(Get-Content $file)
$_starttime = [DateTime]::now
$_PretendTyping = $true
$_InterkeyPause = 100
Write-Host -for $CommentColor @"
NOTE: Start-Demo replaces the typing but runs the actual commands.
.
<Demo [$file] Started. Type `"?`" for help>
"@

# We use a FOR and an INDEX ($_i) instead of a FOREACH because
# it is possible to start at a different location and/or jump
# around in the order.
for ($_i = $Command; $_i -lt $_lines.count; $_i++)
{
if ($_lines[$_i].StartsWith("#"))
{
Write-Host -NoNewLine $("`n[$_i]PS> ")
Write-Host -NoNewLine -Foreground $CommentColor $($($_Lines[$_i]) + " ")
continue
}else
{
# Put the current command in the Window Title along with the demo duration
$_Duration = [DateTime]::Now – $_StartTime
#X – $Host.UI.RawUI.WindowTitle = "[{0}m, {1}s] {2}" -f [int]$_Duration.TotalMinutes, `
# [int]$_Duration.Seconds, $($_Lines[$_i])
Write-Host -NoNewLine $("`n[$_i]PS> ")
$_SimulatedLine = $($_Lines[$_i]) + " "
for ($_j = 0; $_j -lt $_SimulatedLine.Length; $_j++)
{
Write-Host -NoNewLine $_SimulatedLine[$_j]
if ($_PretendTyping)
{
if ([System.Console]::KeyAvailable)
{
$_PretendTyping = $False
}
else
{
Start-Sleep -milliseconds $(10 + $_Random.Next($_InterkeyPause))
}
}
} # For $_j
$_PretendTyping = $true
} # else

#X – $_OldColor = $host.UI.RawUI.ForeGroundColor
$host.UI.RawUI.ForeGroundColor = $MetaCommandColor
#X – $_input=[System.Console]::ReadLine().TrimStart()
$_input= Read-Host
#X – $host.UI.RawUI.ForeGroundColor = $_OldColor

switch ($_input)
{
################ HELP with DEMO
"?"
{
Write-Host -ForeGroundColor Yellow @"
——————————————————————————–
Help Running Demo: $file
.
(#x) Goto Command #x (b) Backup (?) Help
(fx) Find cmds using X (q) Quit (s) Skip
(t) Timecheck (d) Dump demo (px) Typing Pause Interval
.
NOTE 1: Any key cancels "Pretend typing" for that line. Use <SPACE> unless you
want to run a one of these meta-commands.
.
NOTE 2: After cmd output, enter <CR> to move to the next line in the demo.
This avoids the audience getting distracted by the next command
as you explain what happened with this command.
.
NOTE 3: The line to be run is displayed in the Window Title BEFORE it is typed.
This lets you know what to explain as it is typing.
———————————————————————————
"@;
Write-Host "– Press Enter to continue –" -BackgroundColor white `
-ForegroundColor Magenta;
Read-Host; cls;
$_i -= 1
}

#################### PAUSE
{$_.StartsWith("p")}
{
$_InterkeyPause = [int]$_.substring(1)
$_i -= 1
}

#################### Backup
"b" {
if($_i -gt 0)
{
$_i —

while (($_i -gt 0) -and ($_lines[$($_i)].StartsWith("#")))
{ $_i -= 1
}
}

$_i —
$_PretendTyping = $false
}

#################### QUIT
"q"
{
Write-Host -ForeGroundColor $CommentColor "<Quit demo>"
$host.UI.RawUI.ForegroundColor = $defaultForegroundColor;
$host.UI.RawUI.BackgroundColor = $defaultBackgroundColor;
cls;
return
}

#################### SKIP
"s"
{
Write-Host -ForeGroundColor $CommentColor "<Skipping Cmd>"
}

#################### DUMP the DEMO
"d"
{
for ($_ni = 0; $_ni -lt $_lines.Count; $_ni++)
{
if ($_i -eq $_ni)
{ Write-Host -ForeGroundColor Yellow "$("*" * 25) >Interrupted< $("*" * 25)"
}
Write-Host -ForeGroundColor $DumpColor ("[{0,2}] {1}" -f $_ni, $_lines[$_ni])
}
$_i -= 1
Write-Host "– Press Enter to continue –" -BackgroundColor white `
-ForegroundColor Magenta;
Read-Host; cls;
}

#################### TIMECHECK
"t"
{
$_Duration = [DateTime]::Now – $_StartTime
Write-Host -ForeGroundColor $CommentColor $(
"Demo has run {0} Minutes and {1} Seconds`nYou are at line {2} of {3} " -f
[int]$_Duration.TotalMinutes,
[int]$_Duration.Seconds,
$_i,
($_lines.Count – 1)
)
$_i -= 1
}

#################### FIND commands in Demo
{$_.StartsWith("f")}
{
for ($_ni = 0; $_ni -lt $_lines.Count; $_ni++)
{
if ($_lines[$_ni] -match $_.SubString(1))
{
Write-Host -ForeGroundColor $CommentColor ("[{0,2}] {1}" -f $_ni, $_lines[$_ni])
}
}
$_i -= 1
}

# #################### SUSPEND
# –> not working in StudioShell: help (!) Suspend (not working)
#
# {$_.StartsWith("!")}
# {
# if ($_.Length -eq 1)
# {
# Write-Host -ForeGroundColor $CommentColor "<Suspended demo – type ‘Exit’ to resume>"
# function Prompt {"[Demo Suspended]`nPS>"}
# $host.EnterNestedPrompt()
# }else
# {
# trap [System.Exception] {Write-Error $_;continue;}
# Invoke-Expression $(".{" + $_.SubString(1) + "}| out-host")
# }
# $_i -= 1
# }

#################### GO TO
{$_.StartsWith("#")}
{
$_i = [int]($_.SubString(1)) – 1
continue
}

#################### EXECUTE
default
{
trap [System.Exception] {Write-Error $_;continue;}
Invoke-Expression $(".{" + $_lines[$_i] + "}| out-host")
Write-Host "– Press Enter to continue –" -BackgroundColor white -ForegroundColor Magenta;
$_Duration = [DateTime]::Now – $_StartTime
#X – $Host.UI.RawUI.WindowTitle = "[{0}m, {1}s] {2}" -f [int]$_Duration.TotalMinutes, `
# [int]$_Duration.Seconds, $($_Lines[$_i])
#X – [System.Console]::ReadLine()
Read-Host;
}
} # Switch
} # for
## Next three list to put backl the console default colors and do a clear screen:
$host.UI.RawUI.ForegroundColor = $defaultForegroundColor;
$host.UI.RawUI.BackgroundColor = $defaultBackgroundColor;
cls;
$_Duration = [DateTime]::Now – $_StartTime
Write-Host -ForeGroundColor $CommentColor $("<Demo Complete {0} Minutes and {1} Seconds>" `
-f [int]$_Duration.TotalMinutes, [int]$_Duration.Seconds)
Write-Host -ForeGroundColor $CommentColor $([DateTime]::now)
} # function
[/sourcecode]

Please, notice I named the script as “Start-DemoSS.ps1” meaning for StudioShell, still the function will be loaded as “Start-Demo“.

Usage Syntax – To load from script folder location:

.  .\Start-DemoSS.ps1

Usage Syntax – To excute a Demo.txt file:

Start-Demo .\MyDemoScript.txt

What’s inside the demo file? This is a text file containing PowerShell oneliners, and “#” comment lines.

In case you want to try StudioShell: http://studioshell.codeplex.com/

Codeplex StudioShell in SSMS 2012 – Try it!!

If you haven’t yet try it, go ahead download and install this Visual Studio Extension to your SQL Server Management Studio 2012.  This tool will integrate a PowerShell host into your SSMS which you will love for presentations and quick scripts developement from one envirment.  But Yes! this a just a simple host and you’ll find it useful for learning SQL PowerShell.

I will be presenting with this tool in my upcoming webinar with Patrick DeBlanc SQLLunch next week on February 15th “PowerShell Query for the T-SQL Developer” at 11:30am CST / 12:30pm EST.

To download StudioShell, here’s the link: http://studioshell.codeplex.com/

After you install this application, open SSMS,  from the top menu click on “View“, and select “StudioShell“.  Then, you can place this pane anywhere inside your SSMS application.  You can copy/paste t-sql code put remember to import the SQLPS module to have access to your SQL PowerShell commands.

A word of advice! if you venture to go, under ‘Tools | Options“, to change the “Console Choice” to be “Old School“, you will crash your SSMS application when you exit the StudioShell console.  So, DON’T make any changes to your Console Choice options, or you’ll end up loose all your work.

I’m a believer of Tools that can help you be productive, and this one caught my attention.  Please, try it!

Good Job JimChristopher (StudioShell Developer)/@beefarino !!

PowerShell quick list of SQL Users with SysAdmin Role

Here’s a quick way to start getting a list of SQL Server users having “SysAdmin” Role.  Basically, I’m using SQLPS module (now available with SQL Server 2012) which loads all the SMO needed to help you script against your SQL engine.

This script does the following:

  1. Import the SQLPS Module.
  2. Connect to a SQL Server Instance.
  3. Get the SQL Logins information.
  4. Search for SQL users with “SysAdmin” Role, and builds a customized information in a PSObject.
  5. Export the information to a CSV file.
  6. Open the CSV file, which by default could open an Excel application(if installed on machine).

Here’s the code:

[sourcecode language=”powershell”]
Import-Module SQLPS -disablenamechecking

$SQLSvr = "SQLServername\Instancename";
$MySQL = new-object Microsoft.SqlServer.Management.Smo.Server $SQLSvr;
$SQLLogins = $MySQL.Logins;

$SysAdmins = $null;
$SysAdmins = foreach($SQLUser in $SQLLogins)
{
foreach($role in $SQLUser.ListMembers())
{
if($role -match ‘sysadmin’)
{
Write-Host "SysAdmins found: $($SQLUser.Name)" -ForegroundColor Yellow;
$SQLUser | Select-Object `
@{label = "SQLServer"; Expression = {$SQLSvr}}, `
@{label = "CurrentDate"; Expression = {(Get-Date).ToString("yyyy-MM-dd")}}, `
Name, LoginType, CreateDate, DateLastModified;
};
};
};

$SysAdmins | Export-Csv -Path ‘C:\temp\SQLSysAdminList.csv’ -Force -NoTypeInformation;
ii ‘C:\temp\SQLSysAdminList.csv’;
[/sourcecode]

Eventually, you could make changes to this scritp to be capable to access a list of SQL Servers and build your custom report.

Bonus:

To add the functionallity to connect to multiple servers, we can add a list of Servers and then using the “Foreach” statement to loop through the list, and with little changes to the previous code.

Here’s how it will look with just adding a few more line of code:

[sourcecode language=”powershell”]
## – Loads SQL Powerhell SMO and commands:
Import-Module SQLPS -disablenamechecking

## – BUild list of Servers manually (this builds an array list):
$SQLServers = "Server01","Server01\InstanceNameA","Server03";
$SysAdmins = $null;
foreach($SQLSvr in $SQLServers)
{

## – Add Code block:
$MySQL = new-object Microsoft.SqlServer.Management.Smo.Server $SQLSvr;
$SQLLogins = $MySQL.Logins;

$SysAdmins += foreach($SQLUser in $SQLLogins)
{
foreach($role in $SQLUser.ListMembers())
{
if($role -match ‘sysadmin’)
{
Write-Host "SysAdmins found: $($SQLUser.Name)" -ForegroundColor Yellow;
$SQLUser | Select-Object `
@{label = "SQLServer"; Expression = {$SQLSvr}}, `
@{label = "CurrentDate"; Expression = {(Get-Date).ToString("yyyy-MM-dd")}}, `
Name, LoginType, CreateDate, DateLastModified;
};
};
};
## – End of Code block

}

## – BUild and open report:
$SysAdmins | Export-Csv -Path ‘C:\temp\SQLSysAdminList.csv’ -Force -NoTypeInformation;
ii ‘C:\temp\SQLSysAdminList.csv’;
[/sourcecode]

That’s it!

QuickBlog – Use PowerShell to submit SQLServicePack job to multiple Server

This was an interesting discussion in the LinkedIn “How to Install SQL Service Pack by PowerShell?”.  I got the chance to create and test this one out. I scratched the previous script I posted trying to show probe a concept, and ended up creating a new smaller script. Funny!! I created a smaller script!

Well, I just confirmed that’s possible to submit an unattended SQL ServicePack installer as a job using PowerShell Remoting. I’m using my Hyper-V Virtual Domain I ran the script from a Windows 7 VM and submitted one job to two servers. I could see the the jobs processing on the server Task Manager.

But, it was tedious? If you’re a newbie maybe it’s a little over your head but not impossible. That’s the intention of PowerShell Remoting, to be able to do these things like this, and I’m just scratching the surface. Please, Take advantage of these features in PS V2.0, and more enhancements has been done in PS v3.0 with the inclusion of Workflows.

Still, you will need to use PowerShell “Enable-PSRemoting -force” in all the servers. I know, this may be an issue but you need to configure it on all the servers in order to take advantage of PowerShell Remoting. Now, I’m creating session on each computer so I can run as jobs, and your credential is Important to be included. All this is done from your desktop, no more running to the server room.

This time I did test the new script using Sessions in PS Remoting:

[sourcecode language=”powershell”]
## – Get your credential information top connect to servers:
$getCred = Get-Credential ‘Domain99\UserName99’
$servers = "Server1","Server2";
$Jobsession = New-PSSession -Computername $servers -Credential $getCred;

## – display the sessions:
$Jobsession

## – Submit jobs to background process on selected servers:
Invoke-Command -Session $Jobsession -AsJob -JobName ‘TestBackgroundInstall’ `
-ScriptBlock {
new-psdrive -name SQLInstallDrive -psprovider FileSystem -root \\WIN8Server1\install;
cd SQLInstallDrive:;
& ./SQLServer2008R2SP1-KB2528583-x64-ENU.exe /allinstances;
};

## To Display jobs:
get-job

## – To Close PS Sessions and remove variabler:
Remove-PSSession $Jobsession
Remove-Variable Jobsession
[/sourcecode]

In the “Invoke-Command“, the “-ScriptBlock” parameter will hold the code you’re executing on the server as a background job.  Inside the ‘-scriptblock { .. }’ parameter, I’m executing three commands:

1. Creating the PSdrive to the “Install” shared folder.
2. Changing directory (this one could be optional).
3. Finally, run the SQLServer2008R2SP1-KB2528583-x64-ENU.exe SQL Service Pack,

This way you’re not holding the PowerShell Console hostage. You could even make this script more robust. You could add the parameter “-ThrottleLimit” to specify the max number of concurrent connections, to minimize the network traffic. This is just a start, this code can be improve a lot.

You'll need to supply your Windows Credentials
Submitting the job from Windows
 For more information about PowerShell Remoting, type at the PowerShell Prompt:
get-help About_Remoting -full
get-help Invoke-Command -full

Check out the TechNet Tip link on PS Remoting:
http://technet.microsoft.com/en-us/magazine/ff700227.aspx

Added: Please, check this TechEd 2011 video of my college Don Jones talking about “Windows PowerShell Remoting: Definitely NOT Just for Servers”:
http://channel9.msdn.com/Events/TechEd/NorthAmerica/2011/WCL321

Of course, there are products out there to help manage/automate your Microsoft security, and service packs.  But you will still need to invest time configuring the application.

Well!! This was a good one.
🙂

PowerShell – Trap cmdlet errors.

Sometimes working with data can be challenging.  As a SQL Developer, creating ETL solutions, is our responsibility all this data makes it to our users.  Sometime data manipulation might be limited in SSIS, we are force to look for other alternatives.  In my case, I use PowerShell, and I need a way to trap some import processing errors during the execution of the “Invoke-SQLcmd” cmdlet.  Then, I will be able to investigate why some on my data wasn’t making it into my SQL tables.

I try to use PowerShell the “Try-Catch” to trap the error but it was wrong implementation to trap the error in the SQL Server PowerShell “Invoke-SQLcmd” command.  So, How can I trap the command errors?  Well, you can use “CommonParameters“, which are an additional set of parameters automatically provided by Windows PowerShell.  In these additional set of parameters you will find the “-ErrorVariable” parameter which allow you to stores the error information in a given variable.  The error variable you provide in any cmdlet will be overridden each time the cmdlet execute, unless you add an “+” in front of it so it can append to it and collect error information.

For more
Information about all “CommondParameters“, execute at the PS prompt:

[sourcecode language=”powershell”]

Help About_CommonParameters -full

[/sourcecode]

Now, my implementation was to use the “-ErrorVariable” parameter to trap and save the error message with the SQLquery script that failed. Also, I make sure to the variable to a null value after I saved the results to disk. In my scenario, the data imported could break my SQL query and I want to make sure I can identify these records.

So, I’m using the ErrorVariable parameter in my “Invoke-SQLcmd” command.  Here’s a code snippet sample of it:

[sourcecode language=”powershell”]
$reccount = 1; $sqlerr = $null;

:

Foreach($item in $Data)
{
:

$outfile = "C:\ImportError\TSQLQUERY_$($reccount).sql";
$SqlQuery =  "Insert into $tablename ($tblfields) values($fldsvalue);";
Invoke-Sqlcmd -Database $dbName -ServerInstance $ServerName `
-Query $SqlQuery -ErrorVariable sqlerr;

if($sqlerr -ne $null)
{
"/*Error Found – on record# [ $reccount ]:> `r`n"+$Error[0] + "*/ `r`n" `
|  Out-File $outfile -Encoding ASCII;
$SqlQuery | Out-File $outfile -Encoding ASCII -Append;
"`r`n /* "+"".padleft(45,"=")+" */`r`n" `
| Out-File $outfile -Encoding ASCII -Append;
$sqlerr = $null;
}
:
$reccount++;
}
[/sourcecode]

Basically, I want to make sure my “$sqlerr” Error Variable is initialized as $null in both the beginning and after the error have been saved to the output file. Then, we can view later the Error message and the SQL script that error out to later view the output file displaying it in your SSMS or your favorite editor.

Keep in mind, this will not stop the errors from been displayed on screen.  But, you could use another Common Parameter: ” -ErrorAction SilentlyContinue” to prevent displaying the errors.

Sample output  file image:

I hope you find this code snippet useful!

PowerShell – Sum items in a CSV file.

The fact that PowerShell gives you the ability to a build tasks in many different ways, it’s sometimes intimidating.  But, you’ll find the way to improve your coding as time goes.  I try, the best I can, to keep things simple.

So, here’s another approach on How-To “Sum” items in a CSV file:

My Data

[sourcecode language=”powershell”]
## sbData.csv:
# Date,Item,ItemType,Amount,Company
# 12/12/11,Ben Aipa 8’10,Longboard,1500,BenAipa
# 12/12/11,Walden 9’6",Longboard,1100,Walden
# 12/13/11,Channel Island 6′,Shortboard,800,ChannelIsland
# 12/13/11,Mark Richards 6’8",Shortboard,750,Surftech
# 12/14/11,Walden 7’6",Funboard,800,Walden
# – End of CSV file –
[/sourcecode]

The request is to sum the amount of the items group by Date and ItemType.  And here’s the solution:

[sourcecode language=”powershell”]
## – Working process to Sum amount in a CSV file by grouping columns:
$gdata = Import-csv sbData.csv | Group-Object -Property Date,ItemType;

## – BUild your new object with the sum items:
[Array] $newsbData += foreach($gitem in $gdata)
{
$gitem.group | Select -Unique Date,ItemType, `
@{Name = ‘SumAmount’;Expression = {(($gitem.group) | measure -Property Amount -sum).sum}}
};

## – Build back the CSV file with the Sum items
$newsbData | Export-Csv NewsbData.csv -NoTypeInformation;
ii NewsbData.csv;
[/sourcecode]

So, you can substitute the group items in ” -property ” parameter with the ones you want to be grouped on, then use  the “Select -unique …” to include the grouped items you want to list.  The magic happens when including the  “Measure” command against the already grouped items so you can sum the ‘Amount’ field.  Now, this code could become a template to sum up items when needed.

The Result:

[sourcecode language=”powershell”]
# – My CSV new Output data:
# "Date","ItemType","SumAmount"
# "12/13/11","Longboard","2600"
# "12/13/11","Shortboard","1550"
# "12/14/11","Funboard","800"
# – end of file –
[/sourcecode]

Happy PowerShelling!!

QuickBlog – Finding a value in a PowerShell Hash table – Simple!!

For this quick blog, let’s create a month hash object table containing the number and name of the month.  Then, we are going to query this Hash Table object for a specific month.

1. Creating our Month Hash Table:

[sourcecode language=”powershell”]
$MonthHashTable = @{ `
[int] "1" = "January"; `
[int] "2" = "February"; `
[int] "3" = "March"; `
[int] "4" = "April"; `
[int] "5" = "May"; `
[int] "6" = "June"; `
[int] "7" = "July"; `
[int] "8" = "August"; `
[int] "9" = "September"; `
"10" = "October"; `
"11" = "November"; `
"12" = "December"; `
};
[/sourcecode]

Notice in this example, we’ve assigned ‘Strong-typed’ values to most of the keys (month number) as Integer, and leaving the last three to default to a string data “data type“.

Keep in mind, in a Hash Table you have Keys, and Values.  So, we are going to search for a ‘Key’ in order to get the ‘Value’ so we can extract the Month name.

Here’s the Hash Table Syntax for finding the value using the key:
$yourHashTable.Item( [#key#] )

2. Lets go and Looking for the fourth and eleventh month name:

[sourcecode language=”powershell”]
## —————————————-
## – Getting "April":
## – Value stored as Integer for "April":
$mth = 4;

## – Bad, passing a string value when expecting an Integer
## -> no key found, nothing to return:
$MonthHashTable.Item("4");

## – Good, getting month name using Integer value
## -> keys found, a values are returned:
$MonthHashTable.Item(4);
April

$MonthHashTable.Item($mth);
April

## —————————————-
## – Getting "November":
## – Value stored as Integer for "November":
$mth = 11;

## – Bad, passing an integer value when expecting a string
## -> no key found, nothing to return:
$MonthHashTable.Item(11);

## – Bad, passing an integer value when expecting a string
## -> no key found, nothing to return:
$MonthHashTable.Item($mth);

## – Value stored as String for "November":
$mth = "11";

## – Good, getting month name using String value:
## -> key found, a value is returned:
$MonthHashTable.Item($mth);
November

[/sourcecode]

As the sample show, we need to make sure the variable value must have the proper “data type” so it can find the key.

Happy PowerShelling!!

SQLPASS PowerShell Virtual Chapter – “Extending T-SQL with PowerShell” Posted Slides & Scripts..

For all whom attended the SQLPASS PowerShell Virtual Chapter – “Extending Your T-SQL Scripting with PowerShell” session on Wednesday November 16th, I finally got it posted here.

My sincere Apologies for the long delay in posting my session slides and demo scripts.  I thought I lost the material after having a disk drive corruption but I was able to recorver it.

Please, click on the link :< download now>: from SkyDrive. (rename file *.zip.txt to *.zip before extracting)

Don’t hesitate to contact me if you have any issues downloading it.