Posts RSS Comments RSS 253 Posts and 411 Comments till now

Blog Archives

Birth of a Script/Function

I know my post have been few and far between, but I have been super swamped at work and will be for a few more months at least.

That said I am writing some scripts and functions for work and as I was writing one today I though maybe I should share how I go about writing a function slash script. I like step-by-step lists so I decided at that format.

1> A purpose
– All Scripts must start with a purpose. Be it install something or check something. It needs to do something.

2> I figure the best process to do what I want
– Can what I want done be remoted?
– Do I use WMI?
– Do I use .NET?
– Do I use external Commands?
– Who is going to be doing it? What rights do they need?
– Does it have potential to break stuff (BIGGY!!!)

3> Write a function or functions that do what I want done on one Server, Device, or file
Example

function Checkhf{
   Param($srv,$ptch)
   $hf = get-WmiObject Win32_QuickfixEngineering -ComputerName $srv | where-Object{$_.HotfixID -match $ptch}
   if($hf)
   {
      return $true
   }
   else
   {
      return $false
   }
}

4> Cut and Paste function into my templates (At the bottom of post)
– Add any missing parameters
– Add any extra parsing
– Add error control if needed

5> Now it looks like this

function Check-Hotfix {
    Param([string]$server,[string]$hotfix)
    Begin{
        function PingServer {
            param([string]$srv)
            $pingresult = Get-WmiObject win32_pingstatus -f "address=’$srv’"
            if($pingresult.statuscode -eq 0) {$true} else {$false}
        }
        function Checkhf{
            Param($srv,$ptch)
            $hf = get-WmiObject Win32_QuickfixEngineering -ComputerName $srv | where-Object{$_.HotfixID -match $ptch}
            if($hf)
            {
                return $true
            }
            else
            {
                return $false
            }
        }
        Write-Host
        $process = @()
    }
    Process{
        if($_)
        {
            if($_.ServerName)
            {
                $process += $_.ServerName
            }
            else
            {
                $process += $_
            }
        }
    }
    End{
        if($Server){$Process += $Server}
        if($process.Length -eq 0){$Process += get-content env:COMPUTERNAME}
        foreach($s in $process)
        {
            if(PingServer $s)
            {
                $myobj = "" | select-Object Server,Result
                $myobj.Server = $s
                $myobj.Result = Checkhf -srv $s -ptch $hotfix
                Write-Output $myObj
            }
        }
    }
}

6> Final Test

Here are my Templates
– By default they take a Pipe, Server, or File and will process all three

Template for Script

Param([string]$server,[string]$file)
Begin{
    function PingServer {
        param($srv)
        $pingresult = Get-WmiObject win32_pingstatus -f "address=’$srv’"
        if($pingresult.statuscode -eq 0) {$true} else {$false}
    }
    function InsertFunctionHere{
    }
    Write-Host
    $process = @()
}
Process{
    if($_)
    {
        if($_.ServerName)
        {
            $process += $_.ServerName
        }
        else
        {
            $process += $_
        }
    }
}
End{
    # Check if $server is populated and add to Process Array
    if($Server){$Process += $Server}
    # Check if $file is populated and add to Process Array
    if($file)
    {
        foreach($entry in (get-content $file))
        {
            $Process += $entry
        }
    }
    # If Process Array is empty… Add self
    if($process.Length -eq 0){$Process += get-content env:COMPUTERNAME}
    foreach($s in $process)
    {
        if(pingserver $s)
        {
            InsertFunctionHere $s
        }
        Write-Host
    }
}

Template for Function

function Verb-Noun {
    Param([string]$server,[string]$file)
    Begin{
        function PingServer {
            param($srv)
            $pingresult = Get-WmiObject win32_pingstatus -f "address=’$srv’"
            if($pingresult.statuscode -eq 0) {$true} else {$false}
        }
        function InsertFunctionHere{
        }
        Write-Host
        $process = @()
    }
    Process{
        if($_)
        {
            if($_.ServerName)
            {
                $process += $_.ServerName
            }
            else
            {
                $process += $_
            }
        }
    }
    End{
        # Check if $server is populated and add to Process Array
        if($Server){$Process += $Server}
        # Check if $file is populated and add to Process Array
        if($file)
        {
            foreach($entry in (get-content $file))
            {
                $Process += $entry
            }
        }
        # If Process Array is empty… Add self
        if($process.Length -eq 0){$Process += get-content env:COMPUTERNAME}
        foreach($s in $process)
        {
            if(pingserver $s)
            {
                InsertFunctionHere $s
            }
            Write-Host
        }
    }
}

UPDATED!!! Get-Uptime (The Custom Object extravaganza!!!)

One of the most wonderful things about PowerShell is the ability to pass objects down the Pipe for further processing. In my first version of Get-Uptime I did not utilize this because I wanted to show what a huge difference it makes. I wanted to get this out pretty quick so I didn’t add the prettiness that I had in my first version, but it is easy enough to add.

Here is the new Code. After the code I give some examples of how to use it.

Function Get-Uptime{
    Param([string]$server)
    Begin {
        function PingServer {
            Param([string]$srv)
            $pingresult = Get-WmiObject win32_pingstatus -f "address=’$srv’"
            if($pingresult.statuscode -eq 0) {$true} else {$false}
        }
        function myUptime {
            param([string]$srv)
            $os = Get-WmiObject Win32_OperatingSystem -ComputerName $srv
            $uptime = $os.LastBootUpTime
            return $uptime
        }
        function ConvertDate {
            param([string]$date,[string]$srv)
            $year = $date.substring(0,4)
            $Month = $date.Substring(4,2)
            $day = $date.Substring(6,2)
            $hour = $date.Substring(8,2)
            $min = $date.Substring(10,2)
            $sec = $date.Substring(12,2)
            $RebootTime = new-Object System.DateTime($year,$month,$day,$hour,$min,$sec)
            $now = [System.DateTime]::Now
            $uptime = $now.Subtract($RebootTime)
            $uptimeval = "$($uptime.days) days, $($uptime.Hours) hours, $($uptime.Minutes) minutes, $($uptime.seconds) seconds"
            $lastReboot = $rebootTime.toString()
            $sObject = new-Object -typename System.Object
            $sObject | add-Member -memberType noteProperty -name ServerName -Value $srv
            $sObject | add-Member -memberType noteProperty -name Days -Value $uptime.days
            $sObject | add-Member -memberType noteProperty -name Hours -Value $uptime.Hours
            $sObject | add-Member -memberType noteProperty -name Minutes -Value $uptime.Minutes
            $sObject | add-Member -memberType noteProperty -name Seconds -Value $uptime.seconds
            $sObject | add-Member -memberType noteProperty -name uptime -Value $uptimeval
            $sObject | add-Member -memberType noteProperty -name LastReboot -Value $rebootTime.ToUniversalTime()
            $sObject | add-Member -memberType noteProperty -name LastRebootUtc -Value $rebootTime.ToFileTimeUtc()
            write-Output $sObject
        }
        Write-Host
        $process = @()
        $objCollection = @()
    }
    Process {
        if($_){
            if($_.ServerName ){
                $process += $_.ServerName
            }
            else{
                $process += $_
            }
        }
    }
    End {
        if($Server){$process += $server}
        $i = 1
        foreach ($Server in $process){
            write-progress $Server "Total Progress->" -percentcomplete ($i/$process.length*100)
            if(PingServer $server){
                $result = myUptime $server
                $srvObject = ConvertDate $result $server
                $objCollection += $srvObject
            }
            else {
                Write-Host "Server [$server] not Pingable" -foregroundcolor red
            }
            $i = $i+1
        }
        Write-Output $objCollection
        Write-Host
    }
}

Examples:

This get uptime on a Single Server

get-uptime server | %{$_.uptime}

This gets all servers up for more than 30 days

$sl | Get-Uptime | ?{$_.Days -gt 30} | %{write-host "$($_.ServerName) :: $($_.uptime)"}

This Displays the Last Reboot Time of a list of servers.

$sl | get-uptime | %{Write-Host "Server $($_.ServerName) rebooted on $($_.LastReboot)"}

The part of this I want to focus on is this

$sObject = new-Object -typename System.Object
 $sObject | add-Member -memberType noteProperty -name ServerName -Value $srv
 $sObject | add-Member -memberType noteProperty -name Days -Value $uptime.days
 $sObject | add-Member -memberType noteProperty -name Hours -Value $uptime.Hours
 $sObject | add-Member -memberType noteProperty -name Minutes -Value $uptime.Minutes
 $sObject | add-Member -memberType noteProperty -name Seconds -Value $uptime.seconds
 $sObject | add-Member -memberType noteProperty -name uptime -Value $uptimeval
 $sObject | add-Member -memberType noteProperty -name LastReboot -Value $rebootTime.ToUniversalTime()
 $sObject | add-Member -memberType noteProperty -name LastRebootUtc -Value $rebootTime.ToFileTimeUtc()

This is where I define my custom object. There are numerous ways to do this, but I chose this way. Notice the use of add-member cmdlets… It is extremely powerfull and extremely easy to use.

Basically what I do is create a Generic Object $sObject. Add some noteProperties and populate them. Very simple, but as you can very “POWER”ful.

Lee Holms has some excelent information on Custom Objects here:
http://www.leeholmes.com/blog/AddCustomMethodsAndPropertiesToTypesInPowerShell.aspx

I hope you enjoyed this new version… I currently actually keep both versions in my functions.ps1 file that I load in my profile. One as Get-Uptime and one as Get-UptimeExt. I get pretty and Smart 🙂

« Prev