Click here to monitor SSC
  • Av rating:
  • Total votes: 40
  • Total comments: 5
Laerte Junior

The PoSh DBA - The Attributes of Advanced Functions

19 June 2012

Once you pass that point of just hurriedly writing PowerShell scripts for immediate use and start to write PowerShell functions for reuse, then you'll want a robust set of parameters that allow functions to work just like cmdlets.

PowerShell advanced functions provide some powerful magic. In the previous article we covered some “features” that can help us to write better code, and now we are going to focus in on the magic of those features that are to do with the parameters that we pass to advanced functions.

We already know that, when we put the [CmdletBinding()] attribute in a function, it changes it into an advanced function, thereby allowing options that you don’t have in normal functions – see The PoSh DBA: Grown-Up PowerShell Functions. What I didn’t emphasize then is that all magic comes at a price. In this case, the price is that you must write code that uses the magic correctly; you must be more precise and cautious, just like any magician. To start with, the function’s parameters should be formally defined. We lose something by this: When we write a function without the [CmdletBinding()] attribute , we can be less strict, and pass more parameters than we have defined in the function, because the $args variable stores them.

function ILoveInformalParameters {
        param ($IamFirst,$IamSecond)
        Write-Host "I am The First Parameter : $($IamFirst)"
        Write-Host "I am The Second Parameter : $($IamSecond)"
        Write-Host "And I am The Rest : $($args)"
       
    }

If we now call our informal function :

ILoveInformalParameters ObiWanKenoby Yoda DarthVader DarthSidious

I am The First Parameter : ObiWanKenoby
I am The Second Parameter : Yoda
And I am The Rest : DarthVader DarthSidious

But if, without due thought, we add just the [CmdletBinding()] attribute to this without any option…

function ILoveInformalParameters {
       [cmdletbinding()]
       param ($IamFirst,$IamSecond)
       .......   
   }

…And try to run it using more parameters than we've declared…

ILoveInformalParameters ObiWanKenoby Yoda DarthVader DarthSidious

ILoveInformalParameters : A positional parameter cannot be found that accepts argument 'DarthVader'…….

Yes. It is an error in the positional parameters. You’ve just dropped the rabbit from the hat.

The CmdletBinding arguments

There are 3 arguments that are concerned with the parameters that can be passed to PowerShell functions. These are :

  • SupportsShouldProcess
    • By setting this property to $True (the default is $False), you are asking the function to be able to support the ShouldProcess method. By doing this, you allow the function to implement the Whatif common parameter that displays what the function would do, but without actually performing the operation . The Confirm option is also enabled by this property.
  • ConfirmImpact
    • In this argument, you will configure the impact level ("HIGH", "MEDIUM" or "LOW") at which the action that you are performing in your function should be preceded by a prompted confirmation request such as “Are you sure about this?”. This prompt would only be displayed if the impact level in the argument is equal to, or higher than, the value of the global $ConfirmPreference  shell variable (which defaults to ‘HIGH). The default value of the argument is ‘Medium’ and, of course, this option only make sense if you specify SupportsShouldProcess option as well.
  • DefaultParameterSetName
    • The DefaultParameterSetName argument specifies the name of the parameter set that Windows PowerShell will attempt to use when it cannot determine which parameter set to use. (for more information, use about_Functions_CmdletBindingAttribute)

So how should we code these?

   Function NowIamDoingRight {
       [cmdletbinding(
           SupportsShouldProcess=<Boolean $True or $False>
           ConfirmImpact=<String 'None' 'Low' 'Medium' 'High'>
           DefaultParameterSetName <String ParameterName>
       )]

Both SupportsShouldProcess and ConfirmImpact are part of the advanced functions confirmation methods, or as I like to call them, the “License to Kill” methods.

The License to Kill Options – Performing Highly Dangerous Operations

SupportsShouldProcess Argument

First License to Kill parameter – “My Name is If… –WHATIF”

We know that there is no such thing as a small mistake in a DBA's job. When it happens, it is always a mistake of HUGE proportions.

Fortunately we can use the whatif common parameter to help reduce mistakes, if our functions support it. This does nothing more than to show you what it would do without actually running the command in the function you are executing. It is something like asking the function: “What am I about to do?” rather than asking “Holy Saints. Do I have a backup?” after the function does something unexpected.

To illustrate this, we’ll create two advanced functions, Get-MSSQLTable and GET-MSSQLProcedure. The former outputs the SQL Server table objects that you specify, and the latter outputs stored procedure objects.

 function Get-MSSQLTable {
   [CmdletBinding()]
 
     param(
     [Parameter(Position=0, Mandatory=$true)] [String]$Server,
     [Parameter(Position=1, Mandatory=$true)] [String]$Database,
     [Parameter(Position=2, Mandatory=$false)] [String]$TableName
     )
 
     begin {
 
         [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | out-null 
          $ServerName=New-Object "Microsoft.SqlServer.Management.Smo.Server" $server
      }    
      Process {
      
          $ServerName.Databases | where {$_.name -eq "$Database" } | % {
               
              foreach ($table in $_.tables) {
                     if ($tableName) {
                     $tables = $table | where {$_.name -like "$tablename*"}
                     } else {
                     $tables = $table
                    }
  
                    Write-Output $tables
              }
  
          }
  
     }
  
  }   
  
  function Get-MSSQLStoredProcedure {
  
      [CmdletBinding()]
  
      param(
          [Parameter(Position=0, Mandatory=$true)] [String]$Server,
          [Parameter(Position=1, Mandatory=$true)] [String]$Database,
          [Parameter(Position=2, Mandatory=$false)] [String]$ProcedureName
  
      )
      Begin {
          [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | out-null 
         $ServerName=New-Object "Microsoft.SqlServer.Management.Smo.Server" $server
     }    
     Process {
 
         $ServerName.Databases | where {$_.name -eq "$Database" } | % {
         foreach ($Proc in $_.storedprocedures) {
             if ($ProcedureName) {
                 $procs = $Proc | where {$_.name -like "$ProcedureName*"}
             } else {
                 $procs = $proc
             }
             Write-Output $procs
            }
         }    
     }
 }

There is not much that to say about them. They are simple functions.

Now, we will write a more dangerous function that drops the objects. Now, you’ll probably have noticed that this is not a pair of related functions; one to drop Tables and other to drop Procedures. This is a function to drop a database object no matter what it is, just as long as the object has the drop method, or will accept being dropped.

The first name that I thought of was Drop-SQLObject, but Drop it is not an approved PowerShell verb, so I replaced the ‘Drop’ verb with something similar and approved. Remove-SQLObject. (You can get a list of approved verbs by using the Get-Verb cmdlet).

My first step towards using this function was, of course, to enable the -whatifand -confirm parameters by adding SupportsShouldProcess=$true in the CmdletBinding attribute:

function Remove-SQLObject
   {
       [CmdletBinding(SupportsShouldProcess=$true)]

And I created it so that it receives an SMO object as a parameter and drops the object inside a process block, but I encountered a problem with Foreach enumerators in the Pipeline, and to retrieve the Database Objects (tables, stored procedures and so on). In SMO you need to use enumerators, as I’ve shown in the “foreach$procin $_.StoredProcedures” and “foreach$table in $_tables” in the functions above. This will cause problems if you drop an object in the enumeration. This script won’t work.

function Remove-SQLObject
   {
       [CmdletBinding(SupportsShouldProcess=$true)]
       param(
           [Parameter(Position=0, Mandatory=$true, ValueFromPipeline = $true)]
           [ValidateScript({$_.GetType().Namespace -like "Microsoft.SqlServer.Management.Smo*" -and ($_.gettype().getinterfaces()|select -expand name) -contains 'idroppable'})] $SmoObject
       )
      
       Process {
           SmoObject.Drop()
       }
   }   


Basically, Enumerators can be used to read the data in the collection, but they cannot be used to modify the underlying collection. If you try to run the script, you get an error:

An error occurred while enumerating through a collection: Collection was modified; enumeration operation may not execute.

To work around to this limitation, I used an Array $MyObject and populated it completely in the process block: In the End block, I effectively dropped the items of this object one by one. The final code (before I implemented –whatif processing) is:

 

Function Remove-SQLObject
   {
       [CmdletBinding(SupportsShouldProcess=$true)]
       param(
         [Parameter(Position=0, Mandatory=$true, ValueFromPipeline = $true)]
         [ValidateScript({$_.GetType().Namespace -like "Microsoft.SqlServer.Management.Smo*" -and ($_.gettype().getinterfaces()|select -expand name) -contains 'idroppable'})] $SmoObject
       )
      
           begin {
                   $MyObject = @()
           }   
   
           process {
                   if ( $PSCmdlet.ShouldProcess("$($SmoObject.GetType().name) - $($SmoObject)") ) {
                           foreach ($drop in $SmoObject) {
                               $MyObject += $drop
                               Write-verbose "Dropping $($SmoObject.GetType().name) - $($SmoObject)"
                           }
                       }   
                   }   
           end {   
                   $count = $MyObject.count
                   for ($i = 0; $i -lt $count; $i++) {
                       $MyObject[$i].Drop()
   
                   }
   
           }   
   
   }

The code that will eventually allow the whatif argument to work properly is in the line 14 :

    if ( $PSCmdlet.ShouldProcess("$($SmoObject.GetType().name) - $($SmoObject)") ) {…}

So if the’ whatif’ parameter is supplied, then the parameter passed to theShouldProcess method will be displayed, but the code in the scriptblock that follows the IF statement won’t be executed. Otherwise, the scriptblock after the IF statement will be executed. . In this case I am displaying the type of the object (table,stored procedure...etc.) and the Schema and Name of the object so you will be clear about what will be executed if you were to leave out the -Whatif.

In my case, because I had to call the drop method on the database object in the end block and not in the Process block, you might think, as I did, that I would need a variable to hold a flag as to whether I’d passed -whatif or not: Maybe Something like this?

   begin {
                   $MyObject = @()
                   $whatif = $true
           }   
   
           process {
                   if ( $PSCmdlet.ShouldProcess("$($SmoObject.GetType().name) - $($SmoObject)") ) {
                           $whatif = $False
                           foreach ($drop in $SmoObject) {
                               $MyObject += $drop
                               Write-verbose "Dropping $($SmoObject.GetType().name) - $($SmoObject)"
                          }
                      }   
                  }   
          end {   
                  if ($whatif) {
                      $count = $MyObject.count
                      for ($i = 0; $i -lt $count; $i++) {
                          $MyObject[$i].Drop()
                      }       

Wrong. Just by passing the –whatif as a parameter, no operation or method will be performed in all the code of the function. I do not need to worry.

The function requires that an SMO object is passed to it. This required validation. I therefore had to add this rather daunting line that checks that the parameter is an SMO object and that it is droppable:

[ValidateScript({$_.GetType().Namespace -like "Microsoft.SqlServer.Management.Smo*" -and ($_.gettype().getinterfaces()|select -expand name) -contains 'idroppable'})] $SmoObject

Don´t worry, I will cover the parameters’ metadata, and the ValidateScript attribute, in the next article. For now it is good to know that the $SmoObject parameter accepts only SMO Objects that can be dropped.

Now it is time to see the magic:

 

   create table ThePoshDBA_1 (id int)

   go

   create table ThePoshDBA_2 (id int)

   go

   create table ThePoshDBA_3 (id int)

   go

   create table ThePoshDBA_4 (id int)

   go

   create table ThePoshDBA_5 (id int)

   go

   create table ThePoshDBA_6 (id int)

Get-MSSQLTable -Server . -Database "ThePoshDBA" -TableName "ThePoshDba*" | Remove-SQLObject -whatif

Do not be scared if all that you see displayed is ....

What if: Performing operation "Remove-SQLObject" on Target "Table - [dbo].[ThePoshDBA_1]".
What if: Performing operation "Remove-SQLObject" on Target "Table - [dbo].[ThePoshDBA_2]".
What if: Performing operation "Remove-SQLObject" on Target "Table - [dbo].[ThePoshDBA_3]".
What if: Performing operation "Remove-SQLObject" on Target "Table - [dbo].[ThePoshDBA_4]".
What if: Performing operation "Remove-SQLObject" on Target "Table - [dbo].[ThePoshDBA_5]".
What if: Performing operation "Remove-SQLObject" on Target "Table - [dbo].[ThePoshDBA_6]".

… because your tables still will be in the Database ThePoshDBA. No operation was performed; it is just saying to you what it would do.

And of course to effectively drop the tables, you need only remove the whatif parameter.

Get-MSSQLTable -Server . -Database "ThePoshDBA" -TableName "ThePoshDba*" | Remove-SQLObject

Bear in mind that the problem I faced by using the Foreach enumerator when deleting the objects is a particular problem for this function, and it is unlikely that you would ever need to write your -whatif implementation the same way, that is, by using the begin and end blocks of the function. The usual way to implement whatif processing is:

   .....
   process {
       if ( $PSCmdlet.ShouldProcess("Something In Here to Display") ) {
           Perform the action
           ......
       }   
   }   
   .....

In fact, you can take advantage of using Enumerators. Let’s go a bit off-topic to look at a nice trick. Have you noticed that, for the cmdlet get-eventlog, you can either use an array as the parameter for the Servers or pass it in the pipeline? In this case when a parameter is defined as string[] you can do this ...

Get-EventLog Application -computer (Get-Content Servers.txt)

... instead of this ...

Get-content  Servers.txt | foreach {Get-EventLog Application –computer $_}

You can implement the same functionality in your Function. Let´s see the part of the code of Chad Miller´s Get-SqlWmi; (thanks to him for teaching me this trick). This function uses the WMI ManagedComputer cmdlet to get port, instance and service account WMI information for all SQL instances on a computer.

function Get-SqlWmi
    {
        [CmdletBinding()]
        param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
       [ValidateNotNullorEmpty()]
       [string[]]$ComputerName
       )
   
       #Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer only works on SQL 2005 and higher. If we fail to gather info at least output
       #null values and computername for 2000 servers in catch block
       BEGIN {}
       PROCESS {
           foreach ($computer in $computername) {
               try {
                   $wmi = new-object "Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer" $Computer -ErrorAction 'Stop'
                  
   ........

By using the foreach enumerator , the parameter $Computername as string[]and of course understanding the ValueFromPipelineByName and ValueFromPipelineByValue, you can simulate the same thing that Get-EventLog does.

You can call the Get-SQLWmi by passing in an array directly :

Get-sqlwmi (get-content names.txt)

…or through the pipeline by value :

 Get-content names.txt | Get-sqlwmi

…or by through the pipeline name :

Invoke-sqlcmd –ServerInstance "yourServer" –database "YourDb" –query “Select server_name AS 'ComputerName' FROM ServersTable” | Get-SqlWmi

Don’t worry my friends, in the next part of these series, we will cover the ValueFromPipeline property and the related attributes.

But, back to our subject, according to the Don Jones, there is something else to consider as well:

“Don’t forget that -confirm and -whatif are also passthrough parameters. That is, if your function declares SupportsShouldProcess=$True, and someone runs the function with -whatif or -confirm, those will be passed to any other cmdlets WITHIN YOUR FUNCTION that also support -confirm and -whatif. Since your change isn’t being made by a cmdlet, you can’t take advantage of that, so the If construct and using $psCmdlet.ShouldProcess() is indeed the right way to go”.

Second License To Kill parameter– “Sir, you asked for a martini shaken not stirred. Do you -CONFIRM ?”

Sometimes even if we really are sure about an action, why not ask again? For this case we have the common parameter -confirmand as it is also enabled by SupportsShouldProcess we can use it as well.

Get-MSSQLTable -Server . -Database "ThePoshDBA" -TableName "ThePoshDba*" | Remove-SQLObject -verbose -confirm

And a prompt will be displayed to allow you to confirm your murder. No problems, we have license to kill.

ConfirmImpact Argument

To finish the ‘License To Kill’ options, there are some actions that are so dangerous that I want to prompt the user with the same –confirm question, but I want to do it every time that the function is called. I don’t want the user to be obliged to explicitly pass the –confirm parameter.

In this case, we can use the ConfirmImpact option just adding in the [CmdletBinding()] code :

[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact=LevelOfImpact)]

As we see in the beginning of this article, The default is ‘ Medium’ but there are a choice of four impact levels ,'None', 'Low', 'Medium' or 'High'. We’ll code our function to specify ‘High’:

[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='High')]

This operation can be so potentially catastrophic that I am declaring that the impact is HIGH. Every time that I call the function I’ll be asked to confirm the operation.

‘Ha Laerte’, I hear you say, ‘this function is generic. I need this confirmation all the time, but not for all objects. I need confirmation for my tables, but not for the stored procedures. Is there some way for me to suppress this confirmation?’

‘Sure!’, I reply, ‘just pass the parameter –confirm:$false‘.

Get-MSSQLStoredProcedure -Server . -Database "ThePoshDBA" -ProcedureName "Proc_ThePoshDba*" | Remove-SQLObject -verbose -confirm:$

VERBOSE: Dropping StoredProcedure - [dbo].[Proc_ThePoshDBA_1]

VERBOSE: Dropping StoredProcedure - [dbo].[Proc_ThePoshDBA_2]

VERBOSE: Dropping StoredProcedure - [dbo].[Proc_ThePoshDBA_3]

Technically we can create a new parameter –force to suppress this prompt, but again, in the words of the Don Jones :

-Force is usually used to override a permissions problem, read-only, or something else; using it to suppress auto-confirm is a bit nonstandard, but it is comprehensible.

Colleagues, we are about the business of learning how to write advanced code in PowerShell. It is time to be more than just “comprehensible”; right ?

DefaultParameterSetName Argument

There are cmdlets that cannot be called with two or more parameters from different Parameter Sets at the same time. Some parameters depend on others in the same set. I confess that this concept was a bit difficult to understand for me, but after a talk with the Jedi Council (Chad, Ravi, Shay, Jeffery), the apple fell on my head. I felt the gravity of the situation.

Yes. It is a privilege to me have the power to invoke the Jedi Cmdlets as Invoke-ChadMiller, Invoke-Ravikanth, Invoke-ShayLevy, Invoke-JefferyHicks, Invoke-Boe, and so on.

(Ed: Focus Laerte, let’s get back to an example )

Function ImAGrownUpManNow {
  
      [cmdletbinding(
          SupportsShouldProcess=.....
          ConfirmImpact=....
          DefaultParameterSet = "GroupSet1"
      )]
      param (
          [Parameter(ParameterSet="GroupSet1",....) [String] $P1,
          [Parameter(ParameterSet="GroupSet1",....) [String] $P2,
          [Parameter(ParameterSet="GroupSet2",...) [String] $P3,
          [Parameter(ParameterSet="GroupSet2",...) [String] $P4,
         
      )   
  ....
  }

The DefaultParameterSetName in the GroupSet1t means that if you have some positional parameters with default values, and the user doesn't specify any parameter names, then the default set will be used.

The DefaultParameterSetName is bound to the ParameterSetName option that you can specify in the parameter set metadata. There is no sense in using the one without the other.

As you can see, the parameters P1 and P2 are from GroupSet1,and P3 and P4 are from GroupSet2. This means that  P1 or  P2 cannot be passed together with P3 or P4; but all of them are in the same Function.

I guess that you know the Get-Process cmdlet of course. I can get a process by ID OR by Name, not both. Without using multiple distinct parameter sets, you’d need something like Get-ProcessByID and Get-ProcessByName – Thanks to Shay Levy for this example.

In my case, if I Try ...

Get-Process -id 1916

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

------- ------ ----- ----- ----- ------ -- -----------

63 3 772 2812 33 0,02 1916 armsvc

...or ...

Get-Process -Name armsvc

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

------- ------ ----- ----- ----- ------ -- -----------

63 3 772 2812 33 0,02 1916 armsvc

But If I try ...

Get-Process -Id 1916 -Name armsvc

Get-Process : Parameter set cannot be resolved using the specified named parameters……

Other great examples are in the SQLPSX – Invoke-SQLRestore. Take a look at the code : - The parts with “…” was truncated by me to fit on the page.

  function Invoke-SqlRestore
  {
      param(
      [CmdletBinding(DefaultParametersetName="Restore")]
      [Parameter(Position=0, Mandatory=$true)] $sqlserver,
      [Parameter(ParameterSetName="Restore",...)] [string]$dbname,
      [Parameter(Position=2, Mandatory=$true)] [string]$filepath,
      [Parameter(ParameterSetName="Restore",...)] [...]$action='Database',
      [Parameter(ParameterSetName="Restore",...)] [string]$stopat,
      [Parameter(ParameterSetName="Restore",...)] [hashtable]$relocatefiles,
      [Parameter(ParameterSetName="Restore",...)] [switch]$force,
      [Parameter(ParameterSetName="Restore",...)] [switch]$norecovery,
      [Parameter(ParameterSetName="Restore",...)] [switch]$keepreplication,
      [Parameter(ParameterSetName="FileList",...)] [switch]$FileListOnly
      )

The parameters $dbname, $action, $stopat, $realocatefiles, $force, $norecovery, and $keepreplication are parts of the Restore ParameterSet that is the DefaultParameterSetName. The $FileListOnly is from FileList, $Sqlserver and Filepath are not part of any parameter set.

Why is this useful? Well, if I specify the FileListonly in a restore backup , there is no need to use $action, $stopat or the entire Restore set. I just want FileListOnly or, in a T-SQL example a Restore FileListOnly. The same applies to FileListParameterSet. But using either Parameters Set in this function also requires a SQL Server Connection and a File path. This is why these options do not belong to any Parameter Set.

One last example: Do you remember when I said that “if you have some positional parameters with default values, and the user doesn't specify any parameter names, the default set will be used”. Let’s see how this works. In the first function, the DefaultParameterSetName is “First” and in the Second ParameterSetName is “Second” :

Function TestingDefaultParameterSetName_ToFirst {
     [CmdletBinding(DefaultParameterSetName = "First")]
 
     param (
         [parameter(ParameterSetName="First")] [Int] $IamFirst = 10,
          [parameter(ParameterSetName="Second")] [int] $IamSecond = 20
     )
    
     Write-Host "------------------------------------------------------------"
     Write-Host "I am  The TestingDefaultParameterSetName_ToFirst Function"
     Write-Host "Parameter Set : $($PSCmdlet.ParameterSetName)"
    
     switch ($PSCmdlet.ParameterSetName) {
         "First" { write-host "I am First : $($IamFirst)" ; break }
          "Second"write-host "I am Second : $($IamSecond)" ; break }
     }   
    
     Write-Host "------------------------------------------------------------"
    
 
 }
 
 Function TestingDefaultParameterSetName_ToSecond {
     [CmdletBinding(DefaultParameterSetName = "Second")]
     param (
         [parameter(ParameterSetName="First")] [Int] $IamFirst = 30,
          [parameter(ParameterSetName="Second")] [int] $IamSecond = 40
     )
 
     Write-Host "------------------------------------------------------------"
     Write-Host "I am  The TestingDefaultParameterSetName_ToSecond Function"
     Write-Host "Parameter Set : $($PSCmdlet.ParameterSetName)"
 

     switch ($PSCmdlet.ParameterSetName) {
         "First" { write-host "I am First : $($IamFirst)" ; break }
          "Second"write-host "I am Second : $($IamSecond)" ; break }
     }   
 
     Write-Host "------------------------------------------------------------"
 }

Now let’s run each function without any parameters:

TestingDefaultParameterSetName_ToFirst

TestingDefaultParameterSetName_ToSecond

------------------------------------------------------------

I am The TestingDefaultParameterSetName_ToFirst Function

Parameter Set : First

I am First : 10

------------------------------------------------------------

------------------------------------------------------------

I am The TestingDefaultParameterSetName_ToSecond Function

Parameter Set : Second

I am Second : 40

------------------------------------------------------------

Do you see how this works? I am not passing any parameter to them and the parameter set default was that specified at DefaultParameterSetName

That is it my friends. In this article we covered the famous [CmdletBinding()] attribute and demonstrated how some of its magic is done. In the next article in this series, we will look at the wonderful ways that parameters can be validated with advanced functions.

References and Acknowlegements

I would like to thank some gentlemen who spared no effort to share their knowledge, either to me or to the community, and who took part, directly or indirectly, in the creation of this article. To my good friends Chad Miller, Shay Levy, Ravikanth Chaganti; and for his articles, books and blog, Sir Don Jones .

A special thanks to Sir Jeffery Hicks, Sir Phil Factor and Sir Bob Beauchemin that kindly gave your time to tech review and proofread the article.

A huge thanks to my Tech Editors Chis Massey and Andrew Clarke. The real magic is what these guys do for me

Books:

  • Bruce Payette´s Windows PowerShell in Action, Second Edition

Blogs:

Laerte Junior

Author profile:

Laerte Junior is a PowerShell MVP and, through his technology blog and simple-talk articles, an active member of the Microsoft community in Brasil. He is a skilled Principal Database Architect, Developer, and Administrator, specializing in SQL Server and Powershell Programming with over 8 years of hands-on experience. He holds a degree in Computer Science, has been awarded a number of certifications (including MCDBA), and is an expert in SQL Server 2000 / SQL Server 2005 / SQL Server 2008 technologies. He also organizes, and is a speaker at microsoft community events, attracting hundreds of attendees. Laerte has also recently become a Friend of Redgate in Brasil, has taught classes at universities, and produced webcasts for the community.

You should follow him on Twitter as @LaerteSQLDBA

Search for other articles by Laerte Junior

Rate this article:   Avg rating: from a total of 40 votes.


Poor

OK

Good

Great

Must read
Have Your Say
Do you have an opinion on this article? Then add your comment below:
You must be logged in to post to this forum

Click here to log in.


Subject: Great
Posted by: Shogan (view profile)
Posted on: Tuesday, June 26, 2012 at 1:40 AM
Message: Hi Laerte,

Cracking stuff! Great read and must for those interested in PoSh. (Anyone who isn't, should be!)

Cheers,
Sean

Subject: Thanks
Posted by: laerte (view profile)
Posted on: Tuesday, June 26, 2012 at 7:36 AM
Message: Hey Man, glad you liked it :) Thanks my friend

Subject: How to check CPU/Mem/swap/Volume Free space on AIX / Linux using powershell?
Posted by: cletocs (not signed in)
Posted on: Sunday, July 01, 2012 at 1:59 AM
Message: I am new to powershell scripting, am able to find scripts to find cpu/mem/diskspace for window.

But could not find much on Linux/Aix using powershell.

How to check CPU/Mem/swap/Volume Free space on AIX / Linux using powershell?

Thanking you all for all the resources you have provided to us, which is very helpful.



Subject: Re- How to check CPU/Mem/swap/Volume Free space on AIX / Linux using powershell?
Posted by: Laerte Junior (not signed in)
Posted on: Sunday, July 01, 2012 at 7:58 AM
Message: Cletocs, In fact I am a SQL Server DBA, then the world outside Windows it is not my knowledge. I believe you have answers posting on forums such as Stackoverflow. I'm sorry my friend.

Subject: Great
Posted by: Shogan (view profile)
Posted on: Monday, July 02, 2012 at 2:39 AM
Message: Hi Laerte,

Cracking stuff! Great read and must for those interested in PoSh. (Anyone who isn't, should be!)

Cheers,
Sean

 

Phil Factor
Searching for Strings in SQL Server Databases

Sometimes, you just want to do a search in a SQL Server database as if you were using a search engine like Google.... Read more...

 View the blog

Top Rated

Searching for Strings in SQL Server Databases
 Sometimes, you just want to do a search in a SQL Server database as if you were using a search engine... Read more...

The SQL Server Sqlio Utility
 If, before deployment, you need to push the limits of your disk subsystem in order to determine whether... Read more...

The PoSh DBA - Reading and Filtering Errors
 DBAs regularly need to keep an eye on the error logs of all their SQL Servers, and the event logs of... Read more...

MySQL Compare: The Manual That Time Forgot, Part 1
 Although SQL Compare, for SQL Server, is one of Red Gate's best-known products, there are also 'sister'... Read more...

Highway to Database Recovery
 Discover the best backup and recovery articles on Simple-Talk, all in one place. Read more...

Most Viewed

Beginning SQL Server 2005 Reporting Services Part 1
 Steve Joubert begins an in-depth tour of SQL Server 2005 Reporting Services with a step-by-step guide... Read more...

Ten Common Database Design Mistakes
 If database design is done right, then the development, deployment and subsequent performance in... Read more...

SQL Server Index Basics
 Given the fundamental importance of indexes in databases, it always comes as a surprise how often the... Read more...

Reading and Writing Files in SQL Server using T-SQL
 SQL Server provides several "standard" techniques by which to read and write to files but, just... Read more...

Concatenating Row Values in Transact-SQL
 It is an interesting problem in Transact SQL, for which there are a number of solutions and... Read more...

Why Join

Over 400,000 Microsoft professionals subscribe to the Simple-Talk technical journal. Join today, it's fast, simple, free and secure.