Skip navigation

Category Archives: Uncategorized

As I was reading my bible this past Saturday morning I came across these verses.

2 Kings 22:16-20 ESV

Thus says the Lord, Behold, I will bring disaster upon this place and upon its inhabitants, all the words of the book that the king of Judah has read. Because they have forsaken me and have made offerings to other gods, that they might provoke me to anger with all the work of their hands, therefore my wrath will be kindled against this place, and it will not be quenched. But to the king of Judah, who sent you to inquire of the Lord, thus shall you say to him, Thus says the Lord, the God of Israel: Regarding the words that you have heard, because your heart was penitent, and you humbled yourself before the Lord, when you heard how I spoke against this place and against its inhabitants, that they should become a desolation and a curse, and you have torn your clothes and wept before me, I also have heard you, declares the Lord. Therefore, behold, I will gather you to your fathers, and you shall be gathered to your grave in peace, and your eyes shall not see all the disaster that I will bring upon this place.’" And they brought back word to the king.

It’s so amazing to see Gods mercy poured out continually throughout the bible. Though he would be fully justified to lay Israel low, he preserves it, for a time, as a mercy to his repentant servant.

Showing again, God loves a contrite heart. Its humbling to realize how far gone we can be, yet find forgiveness in the presence of an infinitely righteous God.

Especially when we as fallen beings can find it so hard to forgive others of such minor trespasses…

I’ve always been a bit of an older person at heart.  I never really wanted to be the age I was, but older.  Even as I passed what most people consider the milestone ages; 16, 18, 21, I just wanted to be over 30.  Now I’m not saying 30 is old, quite the opposite these days, it tends to be when most individuals in our country begin to hit their stride.

What’s humorous to me now about the pending 30 is that, I’m not really sure why I ever cared?  My age since 25 (lower insurance premiums, yes) has been a number, and of no value to me.  The thing I see now, in looking back, is God’s grace in getting me here.  I can’t boast in anything I’ve done, I am merely a vessel.  With that, I can’t help but approach this milestone age with some regret that it took me over 26 years to find what I have now, not what I’ve established materially, but spiritually.  I’ve an eternal legacy that’s been building now for 4 years.  That’s infinitely more exciting to me than my born on date passing a 30 year mark. 

To so many people that sounds so foreign and I’m sure a little nuts.  If you are one of those people, I ask you this: What’s your legacy look like?  Surely you feel that desire to be, more?  Why is that?

Now, it’s time to evaluate PowerShell.  As of late, PowerShell has become my preferred method for scripting.  PowerShell is built on top of the .NET framework.  It uses cmd-lets (commandlets) to perform the majority of it’s command line actions.  It’s also fully integrated with WMI and the .NET Framework.  It works off of Objects, which we discussed previously with VBScript.  It shares a lot of similarities to the BASH Shell, but the object based pipe is one of the more powerful features.  Objects in the pipe remain objects through to output.  This is an important element to remember if you are already familiar to the BASH shell and find yourself working in a Windows environment now (such as myself).

There’s a lot of good reading over what PowerShell is, so I’ll go ahead and start with our code and break it down as we’ve done in the past.  We’ll be introducing CASE statements this time around, as well as arguments.  I hope you enjoy it.

 Function Get-PowerShell {

The purpose of this script is to start, stop, or restart services on a single machine or list of machines read from a file.


#Author Daniel Belcher
#Set-RemoteService start/stop/restart servicename filename.txt
Param
(
[parameter(Mandatory=$TRUE,
HelpMessage="You need a valid state entry. Start, Stop, or Restart")]
[string]$STATE,
[parameter(Mandatory=$TRUE,
HelpMessage="Please enter a valid service name. example: spooler")]
[string]$SERVICE,
[parameter(Mandatory=$TRUE)][AllowEmptyString()][string]$TARGET
) 
	Function SRS{
			PARAM ($SERVICE,$STATE,$MACHINE)
		$SOBJ = New-Object PSObject
$PING = gwmi -Query "select * from Win32_PingStatus where Address='$MACHINE'" 
    if ($PING.StatusCode -ne 0)
{$SOBJ | Add-Member -MemberType NoteProperty -Name MachineName -Value $MACHINE
 $SOBJ | Add-Member -MemberType NoteProperty -Name Status -Value "Unreachable"}
	else{
TRY{$ACTION = gwmi win32_service -filter "name like '$SERVICE'" `
					-computername "$MACHINE" -ErrorAction continue
switch ($STATE)
		   {stop{$ACTION.invokemethod("stopservice",$NULL) | out-null}
           start{$ACTION.invokemethod("startservice",$NULL) | out-null}
         restart{$ACTION.invokemethod("stopservice",$NULL) | out-null
                    start-sleep 2
                $ACTION.invokemethod("startservice",$NULL) | out-null}}

$ACTION = gwmi win32_service -filter "name like '$SERVICE'" -computername "$MACHINE"
    $SOBJ | Add-Member -MemberType NoteProperty -Name MachineName -Value $MACHINE
    $SOBJ | Add-Member -MemberType NoteProperty -Name Name -Value $ACTION.Name
    $SOBJ | Add-Member -MemberType NoteProperty -Name Status -Value $ACTION.State}
CATCH [System.UnauthorizedAccessException] 
   {$SOBJ | Add-Member -MemberType NoteProperty -Name MachineName -Value $MACHINE
    $SOBJ | Add-Member -MemberType NoteProperty -Name Status -Value "Access Denied"}
					}$SOBJ
}
Write-Host -foregroundcolor Yellow `nAttempting to $STATE $SERVICE
        if($TARGET -eq "")
        	{$TARGET = gc env:computername}
$FILE = test-path $TARGET -ErrorAction SilentlyContinue
if($FILE -eq $TRUE)
    {$READ = gc $TARGET
			ForEach ($MACHINE in $READ){
		SRS $SERVICE $STATE $MACHINE						
						   }}
else
	{
	SRS $SERVICE $STATE $TARGET
	}

Copy and paste the above code and save it as a .ps1 which is the standard file extension for PowerShell scripts.  Now, lets set our execution settings from the PowerShell command line:

Set-ExecutionPolicy remotesigned

You can now execute the script by right-clicking and run with PowerShell, or by launching it from within the shell by navigating to it’s directory and typing it’s name.

Now lets look at our interest areas:

  1. Sequence
  2. Command usage
  3. Output usage
  4. Conditional logic

Sequence:

Sequence inside PowerShell is as expected.  It’s all run inline, and requires everything called to be defined before it’s call.  Looking at the above code you will see that we call Set-RemoteService two times, and we’ve defined it at the beginning of the script.  In VBScript, or in Command, calling a sub, function, or a GOTO statement will find the appropriate section and run that code.  So being aware of how your scripts process instructions is very important to their functionality.

Now for something new, arguments.  Arguments, more or less, are user defined variables.  They are dynamic, and as such, need to be controlled to some degree.  With PowerShell you are capable of defining the variable type, and various restrictions.  This gives you incredible control and removes the potential for unforeseen errors by controlling the flow of input.

Param
(
[parameter(Mandatory=$TRUE,
HelpMessage="You need a valid state entry. Start, Stop, or Restart")]
[string]$STATE,
[parameter(Mandatory=$TRUE,
HelpMessage="Please enter a valid service name. example: spooler")]
[string]$SERVICE,
[parameter(Mandatory=$TRUE)][AllowEmptyString()]
[string]$TARGET
) 

As you can see, with the PARAM statement we are opening 3 variables for input.  They are $STATE, $SERVICE, $TARGET.  We are also insuring whatever is entered is a string value.  So that leaves us with 2 issues.  The user needs to enter something, and it needs to be useable.  So here we have provided a mandatory attribute that will prompt the user as well as a help message that the user can access for guidance on what to enter.  Now with our $TARGET variable, we want to leave it open for files, localhost, and remote machines so it will need to be a bit dynamic in nature.  There are ways to handle this in powershell with objects, but I will demonstrate conditional ways to handle it as well later on.

Command usage:

As we discussed at the beginning, PowerShell uses cmd-lets for the majority of it’s work.  It also allows you to call WMI and .NET methods and functions.  So similarly to to VBScript we can instantiate them for additional functionality.  The possibilities are plain astounding, and well beyond scope for this blog post.

Output usage:

Same as with our previous entries, all the work done is aimed at getting an appropriate output.  As such, capturing, reading, and modifying the output of all our commands is important.  How PowerShell does this, is similar to both VBScript and BASH.  You can pipe for output as input for other commands as well allowing for some very elegant one liner solutions.

Since PowerShell keeps everything in the pipe an object, your variables become immensely powerful since they are more than just stored returns from commands, but instead stored objects with invoke able methods, or property lookup, etc.  Lets evaluate how this works quickly:

$ACTION = gwmi win32_service -filter "name like '$SERVICE'" -computername "$MACHINE"

 

Here we are using a get-wmiobject Cmd-Let alias to grab a specific service, on a specific machine.  Now the variable service we are grabbing will have certain native METHODS and PROPERTIES we can leverage to either invoke or pull data.  What we need to understand is that the $ACTION variable is now an Object, not a Value.

$ACTION.invokemethod("stopservice",$NULL)

StartService and StopService are two methods belonging to Win32_Service objects.  So what we are doing here is saying essentially:

$SERVICE object, Invoke Method StopService

So everything you see at the above link is now callable, or retrievable through this variable.  Pretty cool huh?  One thing of note, if you invoke a method that changes the state of an object, it’s properties will not be refreshed until it is called again.  You will notice in the code I re-declare $ACTION after the service method invocation.

That’s because the state is changed so the property Status has changed.  Hence I couldn’t just recycle $ACTION with the $ACTION.State when building my Status property.  The object needs to be refreshed.

I use two methods for error handling in this script, one is try and catch.  The other is a in line command erroraction preference of silently continue:

TRY{$ACTION = gwmi win32_service -filter "name like '$SERVICE'"....
...$SOBJ | Add-Member -MemberType NoteProperty -Name Status -Value $ACTION.State}
CATCH [System.UnauthorizedAccessException]    
	{$SOBJ | Add-Member -MemberType NoteProperty -Name MachineName -Value $MACHINE     
	$SOBJ | Add-Member -MemberType NoteProperty -Name Status -Value "Access Denied"}

and

$FILE = test-path $TARGET -ErrorAction SilentlyContinue

The TRY and CATCH are fairly straight forward.  TRY (DO) the statement and CATCH if there is an error of [type] then do {statement}.

The –erroraction has 4 possibilities:

  • Continue
  • Inquire
  • SilentlyContinue
  • Stop

They are fairly straight forward, but all work to manage errors or exceptions in one way or another.

Conditional logic:

We’ve discussed if statements before, and as promised, I offer you a practical case statement:

                switch ($STATE){
            stop{$ACTION.invokemethod("stopservice",$NULL) | out-null}
           start{$ACTION.invokemethod("startservice",$NULL) | out-null}
         restart{$ACTION.invokemethod("stopservice",$NULL) | out-null
                    start-sleep 2
                $ACTION.invokemethod("startservice",$NULL) | out-null}                
                                }

The syntax says switch, but the methodology is the same.  All that is happening is we are saying if $STATE = “Stop” or “Start” or “Restart” do this.  Either 3 separate if statements, or 1 case statement.  Fairly efficient manner for handling complex conditions that hinge around one variable.

So what does this PowerShell script do?

It begins by declaring 3 variables that are to be string values.  All 3 as Mandatory, while one is allowed to be an empty string.

Next it builds a function to be reused through the remainder of the script “SRS”. In this function we create a powershell object for storing property data. A ping test is done using a WQL to determine if the machine is online, or if the name is even valid. (the reason we do this, is that it’s increasingly faster to ping for response than to wait for a timeout to occur on a RPC request).

If the machine successfully pings it moves on to declare the $ACTION variable object for use in the Set-RemoteService function. We then check the $STATE string against our SWITCH (CASE) statement and perform the appropriate method.

Reset the $ACTION variable and begin creating and storing note properties to our $SOBJ for reporting.  If either the ping fails, or an unauthorized access error occurs we generate a coresponding note property to the sobj for reporting, and then the function writes the objects properties to the console, then we close the function.

Now the script writes to host a message confirming the attempted status service, ee evaluate the 3rd variable $TARGET and set it’s value to the local machines name if the value is an empty string.

        if($TARGET -eq "")
        	{$TARGET = gc env:computername }

 

Check to see if that $TARGET is a file, if it is we read it and for each item in the file we pass it to our SRS function.  If it wasn’t a file, it does the same thing without a for each statement.

}


So you want a little more?

I’m going to quickly show you how you can integrate this script, into a profile function.  It’s exceptionally easy, and I recommend it for scripts you’ve built that you find invaluable for day to day use.

Here goes the modified code:

Function Set-RemoteService{
Param
(
[parameter(Mandatory=$TRUE,
HelpMessage="You need a valid state entry. Start, Stop, or Restart")]
[string]$STATE,
[parameter(Mandatory=$TRUE,
HelpMessage="Please enter a valid service name. example: spooler")]
[string]$SERVICE,
[parameter(Mandatory=$TRUE)][AllowEmptyString()][string]$TARGET
) 
	Function SRS{
			PARAM ($SERVICE,$STATE,$MACHINE)
		$SOBJ = New-Object PSObject
$PING = gwmi -Query "select * from Win32_PingStatus where Address='$MACHINE'" 
    if ($PING.StatusCode -ne 0)
{$SOBJ | Add-Member -MemberType NoteProperty -Name MachineName -Value $MACHINE
 $SOBJ | Add-Member -MemberType NoteProperty -Name Status -Value "Unreachable"}
	else{
TRY{$ACTION = gwmi win32_service -filter "name like '$SERVICE'" `
					-computername "$MACHINE" -ErrorAction continue
switch ($STATE)
		   {stop{$ACTION.invokemethod("stopservice",$NULL) | out-null}
           start{$ACTION.invokemethod("startservice",$NULL) | out-null}
         restart{$ACTION.invokemethod("stopservice",$NULL) | out-null
                    start-sleep 2
                $ACTION.invokemethod("startservice",$NULL) | out-null}}

$ACTION = gwmi win32_service -filter "name like '$SERVICE'" -computername "$MACHINE"
    $SOBJ | Add-Member -MemberType NoteProperty -Name MachineName -Value $MACHINE
    $SOBJ | Add-Member -MemberType NoteProperty -Name Name -Value $ACTION.Name
    $SOBJ | Add-Member -MemberType NoteProperty -Name Status -Value $ACTION.State}
CATCH [System.UnauthorizedAccessException] 
   {$SOBJ | Add-Member -MemberType NoteProperty -Name MachineName -Value $MACHINE
    $SOBJ | Add-Member -MemberType NoteProperty -Name Status -Value "Access Denied"}
					}$SOBJ
}
Write-Host -foregroundcolor Yellow `nAttempting to $STATE $SERVICE
        if($TARGET -eq "")
        	{$TARGET = gc env:computername}
$FILE = test-path $TARGET -ErrorAction SilentlyContinue
if($FILE -eq $TRUE)
    {$READ = gc $TARGET
			ForEach ($MACHINE in $READ){
			SRS $SERVICE $STATE $MACHINE						
						   }}
else 
	{
	SRS $SERVICE $STATE $TARGET
	}
}

We’ve enclosed the entire thing into a Function statement now, and redefined the internal function.  The reason for this was, well, I prefer to stick with cmd-let naming patterns.  I’d rather call set-remoteservice at the command line.

Now, we need to build our profile, from inside PowerShell, at the command line type:

notepad.exe $PROFILE

Now paste the above code and save it.  If you are inside ISE press F5 to run the script and update your profile, or if you are in the standard shell type:

powershell

This will start a new shell instance inside your previous shell with the updated profile.

Be mindful, PowerShell and PowerShell ISE have two separate profiles.  So if you perform this in ISE the standard shell won’t receive the update and vice versa.


That does it for my stick to the script series.  I hope you’ve learned a lot regarding scripts through this and it’s shed some light onto what scripting is and de-mystified it for you.

I will continue to post scripts for various things over time, as well as neat tricks as I learn them so I wouldn’t say this is truly the end.

Editors:

If you intend to do a lot of scripting, I recommend you grab yourself a steady editor.  Preferably one with configurable highlighters.  Below are a list of a few free and premium editors I recommend.  I’ll start with the freebies:

  • Context – A nice, windows based, free editor (my usual windows editor). Configurable highlighters, comparison tool, and configurable execution keys.  All the basic needs of a script writer.  Minus integrated libraries.  I believe development has all but stopped since 09, so this might not be the best editor to stick to.
  • Emacs – Extremely powerful development environment built for OSS, but with Windows versions.  This is more than a simple editor, it’s a Swiss army knife.  It will require a bit of a learning curve to begin using it but is worth it in the end.
  • VIM – My preferred editor in Linux, switchable modes, highlighters, line numbers, split views, compares, command line style editing.  Like emacs, it’s extremely powerful, and has a bit of a learning curve.  I prefer VIM, but Emacs is far more extensible, just fyi.
  • NotePad++ – A really nice OSS editor for Windows.  I should probably start using this over Context, but I’ve already spent so much time with Context configuring it, I’ve become extremely comfortable with it.  I’d recommend this editor to any novice windows scripter.
  • PowerGUI – Both a free, and paid edition.  I recommend this editor for PowerShell whole heartedly because of it’s syntax and object recognition tools.  If you are going to do a lot of work with PowerShell, I recommend using this editor for it.
  • PSEdit – Included with the PowerShell ISE.  It’s the standard PowerShell editor.

Premium:

If you are interested in learning more:

Stick to the Script Parts 1 – 4:

  1. Stick to the Script…
  2. Stick to the script #!/BIN/BASH…
  3. Stick to the script CreateObject(“Wscript.Shell”)…
  4. Stick to the Script PS C:> PowerShell …

I’ve honestly been trying to post my final part to the “stick to the script” series.  However those actions have been soundly thwarted by an abundance of work, and a new workout regiment.  I hope to have it up and syndicated to myitforum before the weekend is over.

I’ve also built a nice sccm client install script, and thanks to John Marcum, I’ve built a nice remote cm wmi repair tool in powershell as well.

So stay tuned as I plan to start releasing those scripts after scrubbing them.

Three years and five months ago we welcomed a beautiful little boy into this world.  I finally met him, but you knew him for at least 4 years and 2 months, effectively giving you two a 9 month lead on daddy.

will and mommy

And 8 months ago we welcomed in a beautiful sign of God’s grace and mercy into our life with our baby girl.  You’ve known her 1 year and 5 months, again a 9 month lead.

2011-02-08_08-19-10_279

You know our children, you love, in abundance, our children.  You carry on for them when I would break from the strain and you do it time and again.  You help me to keep them in and aware of the word of God and you intercede, respectfully, on behalf of our children when they need it.

2011-05-07_18-54-37_952

You love our God, and your role as a steward to our children so much that you have gladly abandoned what the world demands of a you.  Refusing to allow any inappropriate secondary influences take precedence in our children’s lives.  You inspire me to be a better father, as you inspire me to be a better husband, which inspires me to be a better man and Christian.

You care for me with a love and a heart that is greater than you even have for our children, and for that I give glory to God.  Our children don’t know it now, but one day they will realize how amazing their Mother is, and see her Father reflected in her.  In that way, they could have no better mother.

Happy mothers day baby.

 

2011-05-07_10-08-59_812

Here I am riding to find your present mommy!

2011-05-07_11-16-11_276

Here I am holding your presents from me my mommy!

And uh, this may not make sense yet, but it will.

shipped

I love you.