Skip navigation

Category Archives: Technology

Discussion on any and all tech related items. New tech, tech usage, etc.

So as some of you may or may not know.  My wife is conducting a 365 picture project this year.  What’s a 365 picture project?  Essentially take a pic of you, or something in your life for each day of the year and compile it all together at the end of the year to sort of journal everything.  It’s, as you can imagine, a lot of pictures being taken a day.  I would say on average she has 5 to 10 pictures taken a day.  Realistically speaking, some days it’s about 2, others it’s near 30 or more. 

 

Ok, great, why are you telling me this? 

 

Well, I’m glad you asked.  She would spend a lot of time sorting, renaming, and organizing them.  I’ve been telling her a long time “just automate it” which is something I tell her about almost everything she does that’s repetitive.  Well finally after a long night or sorting through some 100+ photos she called me on it, and had me write her a script to rename all the files for her.  I also had a chance to get to show her a bit of that “computer stuff” I do everyday at work. Also, it’s been a while since I’ve done a scripting post, so I’m using this. 🙂

I figured I would go with powershell since I would have (easier) access to the .NET System.IO.DirectoryInfo class.  One of the things my wife loves is chronological accuracy, so pulling a timestamp from the image as part of its name seemed like a good idea.  She already had a routine where she copied them from her camera to an appropriate folder so specific file information was the only real concern here so this was going to be a very simple script.  Below is the code:

 


PARAM([string]$FOLDER)
$ErrorActionPreference = "silentlycontinue"
if($FOLDER -eq "")
    {$FOLDER = Read-Host "Path to picture folder?"}
    $LIST = Get-ChildItem "$FOLDER*" -Exclude *ps1 `
    -Include *jpg,*tiff,*jpeg,*gif,*bmp,*txt
            $X = 0
    ForEach($OBJECT in $LIST)
        {$EXTENSION = $OBJECT.ToString().Split("") | Select -Last 1
            $EXTENSION = $EXTENSION.Split(".") | Select-Object -Last 1
              $FILEINFO = New-Object System.IO.DirectoryInfo($OBJECT)
                $NAME = $FILEINFO.LastWriteTime.GetDateTimeFormats() `
                | Select-Object -Index 99
                    $NAME = "$($NAME) ($($X)).$($EXTENSION)"
                        Write-Output $NAME
            Rename-Item -Path "$OBJECT" $NAME
            $X = $X+1
            }       


So what’s happening?

First we run this script, either by launching it directly, or by launching it on a command line followed by the folder where our pictures reside. The folder path is our only variable here, if one isn’t entered at the start of execution, it will prompt the user for one.

Now the script will build an object list of everything inside the folder taking special care to exclude any potential powershell scripts in the directory to the $LIST variable.  I also built it to specifically include image file types (I didn’t want to rename some random non-picture files she might be storing in the directory (well, and txt for my testing purposes)). 

Now we define an integer value to $X so we can enumerate it for a counter during our ForEach loop, which we begin next.

For each file in $LIST we:

  1. Grab the extension for the file to variable $EXTENSION
  2. Retrieve the last write time of the file and store it as $NAME
  3. Set $NAME to $NAME + $X + $EXTENSION
  4. Write the final $NAME to console
  5. Rename the item to $NAME
  6. Enumerate $X by 1
  7. Loop

The outcome?

 

I showed her the way it renamed a series of text files I had placed in a test folder on my laptop.  At first, I received a rather dismissive “Oh, that’s good babe” however after I sat down at her desk and showed her the bad boy in action renaming another folder of 100 or so images in seconds, the sly grin found it’s way across her face.  The joy of automation.  The kind you can only get when you see something so small perform such a mind numbing laborious task for you.

She’s not quite ready to learn scripting, but at least now her eyes are open to other possibilities for automated solutions in her everyday computing.  And as a stay at home mother of 2, I’m more than willing to help her streamline all her recreational and productive time at the keyboard.  She is after all, my number 1 customer ;).

So this article was just posted.  I read it, and about cried.

http://tech.slashdot.org/story/11/06/06/2222226/How-To-Succeed-In-IT-Without-Really-Trying

What they are discussing here is something that truly geats at me in respect to my industry.  I’m certain its true in almost every area.  People can’t lead what they can’t understand.

I realize that sounds sort of, dark.  Generally thinking of the “aftermath”conjures thoughts of destruction and loss.  However, the only thing lost is another year of my life, but the gains were enjoyable!

Lets start with the presents (so far).  I’m going to start with the immediately tangible present my wife got me….  A nook color.

May 26 (210)

 

Here’s the thing.  I’ve been itching to buy a tablet for a while.  I’ve also been itching for another e-reader besides my droid x.  I’ve also continually talked myself out of buying a nook and rooting it.

  1. It’s a great e-reader
  2. It’s android based
  3. It can be rooted into a full tablet
  4. It’s $250 dollars (half the price of standard tablets)

However:

  1. I own a droid-x
  2. I own multiple laptops 
  3. It’s $250 dollars

When I opened it though, the inner geek in me went into immediate conflict with the responsible adult in me.  So I spent all day deciding if I should open it, or return it.  In the end, the geek prevailed and the box was open and playtime ensued.  Will loved it immediately because of some preloaded children’s books with “read to me” functionality.  Especially the story of the elephant and the crocodile.  Which he had to read again this morning:

May 27 (216)

After the kids went to bed though, Amanda and I sat down to watch a movie, while I of course watched the movie and rooted my nook at the same time.  By about midnight I had settled on and installed my image of choice.  Cyanogen mod 7, I chose this primarily because of sd expansion install and low to no risk of usage.  I do after all still enjoy the stock nook interface and features, so I didn’t want to blow it away.

May 27 (214)

May 27 (215)

Sorry for poor quality shots, dark room, camera phone, bright screen….. No Buenos.  I’ve also greatly personalized the image since this shot, this was stock image.

Second gift

Apparently my wife has been a busy woman.  Sometime back in January she began coordinating with some of my old friends back home to throw me a 30th birthday LAN Party.  Yes, this is awesome to me.  Yes, I’m that nerdy.  Yes, she raised the bar on birthday surprises and I fear I shall forever fall woefully short for her. Sad smile

May 26 (211) internet safe

Third Gift

A completely decorated 30th birthday house before I got out of bed, and a banana pudding cake….

 

May 26 (12)

May 26 (17)

May 26 (20)

May 26 (24)

May 26 (66)


So, I threw my diet a bit off yesterday.  With my birthday lunch and my banana pudding cake.  It was worth it though, now time to publish this and go ride my bike for about an hour.  God bless and have a good one!

Thanks to everyone for your birthday wishes as well (cards, etc).


Oops, almost forgot:

Keen Keen is streamlined for summer time!!!

May 24 (209)

Zoe and all her black fur is jealous!

March 27 (170)

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.

So I’ve been waiting for Brink to release for some time now.  Both my brother and I had it on pre-order and were ready to go day of release.  The day came, we grabbed it, installed it, then went to play it online together…

Now, I’ve read a lot of what people have been saying about this game and I have to agree, it fell flat, now we found a few games last night where he and I got to really throw down and have a blast, but the responsiveness was barely tolerable.  Anyone who remembers the old quake days before QWC and client detection, it was like that.

Visually the game looks great, well, most of the time.  I am still having anomalies with texture and mapping loads.  I’ve also had some bizarre issues of not being able to connect to my own game server…. yea, go figure that one out.

Overall the customization, and the play mechanics, I actually enjoy.  The slide tackling, and melee knockdowns.  The parkour (although at first rough) has really proven itself as a great new play style option.  However, if this multiplayer synching issue doesn’t get solved, I don’t think I’m going to see my money’s worth out of this title.

(Just spoke with my brother, he’s been on playing all morning, he told me that it appears to be running smooth today.)

So I’ll follow up on this, perhaps all is not lost!

So in the world of SCCM there are tons of moving parts and components.  I want to take some time to focus on some common issues with client installation and communication issues, as well as a couple of tools that make troubleshooting infinitely easier.


Tools

First up I want to list 3 of the primary tools I use for client side troubleshooting.

  1. Trace32 Log Reader
  2. SCCM Client Center
  3. JSandys CM Startup Script

Now the first item on that list, trace32 is by far the most valuable tool to the SCCM administrator outside of the console itself, perhaps even more so than the console.  It allows filtering, highlighting, real time updates, and just generally makes the logs readable.

SCCM Client Center, this tool attaches to the cm WMI Namespace and allows for nearly full control of the client on the target machine.  In terms of remediation, or even testing, there is no reason this tool shouldn’t be installed.

Config Manager Startup Script by Jason Sandys.  This script is easily configured for implementation and has fairly rich logging power for a vbscript, it’s also lighter weight than some of the other health scripts.  I highly recommend using this for maintaining client integrity, as well as offering an installer tool for the CM agent by secondary or third parties.


The Client

First, lets start with identifying the clients existence on the local machine.

Here’s where to look:

  • Control Panel > Configuration Manager (this is one of the quickest methods)
  • Task Manager (ctrl+shift+esc) > Processes > CcmExec.exe
  • Task Manager > Services > CcmExec
  • Control Panel > Admin Tools > Services > SMS Agent Host
  • c:windowssystem32ccm (32bit)
  • c:windowssyswow64ccm (64bit)
  • HKLMSOFTWAREMicrosoftSMSMobile ClientProduct Version (32bit)
  • HKLMSOFTWAREWow6432NodeMicrosoftSMSMobile ClientProduct Version (64bit)

This is a list of the primary locations to check for the presence of the client, it’s also useful for finding methods to script around identifying them.

 

The Client’s Jobs

Now lets discuss what the client does.  First lets recognize that the client is just a dictator for the most case, it tells multiple windows services what to do to complete specific tasks.  Until we need to break down what services do things specifically lets just treat the client as the primary initiator.

  • Policy updates and application
  • Manage downloads
  • System scans
  • Inventory reports

The client and server relationship relies heavily on BITS, Admin shares, RPC (at least for installation), WMI, AD, and WUA.

The client will regularly talk to the server, telling it about any changes it’s had since it’s last conversation, by way of xml.  It will also ask the server what it should be doing differently, to which the server sends the client it’s latest policy.  The client will review that policy then act, or do nothing depending on if there are any actionable changes.

Actionable changes could be installation of software, OS, OS configuration changes, even changes in the frequency of their conversations.  These exchanges of course are called policy updates, and I believe by default they are set to 90 minutes (no real reason to change it either).


Client Installation

There are multiple ways to install the SCCM client, and in a lot of ways, that method will vary depending on your environment.  I will stick to the basics and explain the process if done by server initiated push.  I will also discuss what is required.

First the server begins by initiating a PUSH, using local admin rights, it will copy down the CCMSETUP.EXE file to either c:windowsccmsetup or c:windowssystem32ccmsetup

A service named CcmSetup is made and it begins transferring the client contents to the local machine and finalizing installation and cleanup of the directory.

A log of the transaction is left in the ccmsetup folder named ccmsetup.log

Once this process is complete, the client will perform it’s first policy update and make it’s active client existence known to it’s respective primary server.

 

So what if installation fails?

This isn’t a perfect world.  If you are pushing into an existing environment, things may have accidentally found there way out of standards and or flat broken.

Lets discuss what is required on a local PC for a successful install:

  • Resolvable hostname (proper DNS entry)
  • Service account with local admin rights
  • RPC access to OS components (such as registry)
  • Admin$ shares
  • WUA (Windows Update Agent)

Instead of explaining exactly why for each of these, lets explain how to resolve potential problems with each.  I also want to treat this as an all inclusive troubleshooting guide for the client, so I won’t limit things to just install failures.  Truthfully, if any of these breaks after installation, the client will most likely not function as intended.

Improper DNS entry:

From the local machine there is little you can do to resolve this problem.  Two methods that could resolve the problem are:

ipconfig /registerdns

This will attempt to update the DNS records for all adapters of the local machine.

ipconfig /flushdns

This will dump all resolver cache data on the local machine. (long shot, but I’ve seen this clear up client DNS conflicts from the push)

Any additional resolution would need to be done by the Domain Admin on the DNS server with the improper pointer references.

Service Account with local admin rights:

This is a very simple solution.  Add the appropriate service account to the local admins group on the client PC.  For Installation and operation, this account needs to be set for the client to perform it’s jobs.

RPC Access:

This one can have you scratching your head at times, but a majority of the times it’s tied to a firewall.  Make sure that local firewalls have exceptions built in for the SCCM server.  When in doubt, disable the firewall software to verify if it’s the culprit or not.

Also ensure that the RPC (RpcSs) and RPC Endpoint Mapper (RpcEptMapper) services are Started.

Some of these changes may require a restart before taking effect so  be aware of that while troubleshooting RPC denials.  It’s also worth mentioning there are a multitude of applications that could disrupt this functionality, so be sure to thoroughly investigate the machine for potential culprits.

Admin$ Shares:

First off, the service Workstation (LanManWorkstation) is responsible for these shares, as well as all SMB protocols on the local machine.  If it’s disabled, you will not have these shares.

One of the most direct methods for enabling admin shares is in:

HKLMSYSTEMCurrentControlSetServicesLanManServerParametersAutoShareWks, 1

HKLMSYSTEMCurrentControlSetServicesLanManServerParametersAutoShareServer, 1

Then restart the PC.

Be aware this setting can be viewed as a security risk, and with that being said, some security software may actively disable them.  So treat your evaluation similarly to your RPC troubleshooting.

WUA Disabled:

The Windows Update service being disabled is a fairly simple solution provided there isn’t a GPO forcing it.  You can either enable and set the Windows Update service to Automatic (wuauserv).  Inside the control panel under Windows Update or Automatic updates set it to automatic.

WUA is responsible for system scans, patching, software delivery, essentially a vast majority of the clients functionality.  It is imperative that WUA is enabled.

Bits Admin:

During client installation you may encounter issues with bits failing to download and continuing to re-queue. The issue is generally tied to a stuck job in the bits queue.

From a command prompt you can use

bitsadmin /list /allusers

This will give you a list of jobs, if you see jobs in there:

bitsadmin /reset /allusers

will clear them all out.

For windows XP machines without bitsadmin get it here.

For Windows 7 Machines or Server 08 use the PowerShell module:

import-module bitstransfer

get-bitstransfer -allusers | remove-bitstransfer

For additional bits module cmdlets type:

get-command -module bitstransfer

WMI Failing:

WMI is an integral component of Windows, it could also be linked to issues you might be seeing with WUA being disabled, and with failing clients post and pre install.

The quickest way to verify if WMI is functioning as intended is to check it’s service under Computer Management:

Right-Click My Computer > Manage > Services and Applications > WMI Control > Properties

If you see:

Successfully Connected to: <Local Computer>

Then WMI is functioning correctly. Be mindful though, parts of WMI can fail without the whole of WMI failing, CCM classes/namespaces in WMI could still require a rebuild so be sure to investigate further if the client is installed but not functioning.

Error verbiage that would link to WMI failures will state namespace failures or WMI authentication errors etc. Fortunately repairing a CCM WMI namespace problem is fairly simple.

Open a command prompt:

net stop winmgmt

rename %systemroot%\system32\wbem\repository repository.old

net start winmgmt

Uninstall, or cleanup your CCM/CCMSETUP directories as prescribed in the uninstall section to rebuild the CCM repositories.

If you want to try and rebuild the corrupt namespaces without performing a client uninstall reinstall the following steps can be done from the command prompt as well (requires that a client be installed):

net stop winmgmt
c:
cd %systemroot%\system32\wbem


rename %systemroot%\system32\wbem\repository repository.old

regsvr32 /s %systemroot%\system32\scecli.dll

regsvr32 /s %systemroot%\system32\userenv.dll

mofcomp cimwin32.mof
mofcomp cimwin32.mfl
mofcomp rsop.mof
mofcomp rsop.mfl
for /f %%s in (‘dir /b /s *.dll’) do regsvr32 /s %%s
for /f %%s in (‘dir /b *.mof’) do mofcomp %%s
for /f %%s in (‘dir /b *.mfl’) do mofcomp %%s

net start winmgmt


Logs to Read, and Policy Updates

For the official list of log files, go here.

(http://technet.microsoft.com/en-us/library/bb693897.aspx)

 

I’m going to touch on the more immediate logs for troubleshooting the following issues.

  • Health
  • Policy
  • Connectivity
  • Licenses
  • Installs

Health:

CcmExec.Log, this log is one of the first stops for suspected bad installs.

ClientLocation.log, this log is a good place to verify that client has a healthy install with a site server.

StatusAgent.log, status messages for client components.  Also useful for connectivity issues.

Policy:

PolicyAgent.log, this holds policy request information, very helpful when pulling policy.

PolicyEvaluator.log, this log lets us know know if we are having issues applying policies.

Connectivity:

InternetProxy.log, if you are using unprotected DPs, this is the log to check.

Mpcontrol.log, logs record the state of the management point

LocationServices.log, attempted connectivity to MPs and DPs

Licenses:

Hman.log, if clients aren’t registering this is worth looking into.

Installs:

Ccmsetup.log, client installation happenings are recorded in this log.

Client.msi.log, output from the installer.


That concludes the overview of SCCM client installation and troubleshooting.  Happy problem solving.  For additional information on the client and troubleshooting check MSDN:

http://technet.microsoft.com/en-us/library/bb693982.aspx

and be sure to get involved with

http://www.myitforum.com/absolutenm/PPLSearch.aspx

 


Today we are going to examine VBScript. Now, a bit of fair warning before we start on this.  This scripting language is a departure from our standard shell scripting.  VBScript is an automation scripting language for the Windows Script Host (WSH)/Internet Explorer (IE)/Internet Information Services (IIS), in short, this is the primary Windows scripting language.

Not to get too carried away on the subject, but this language uses a Component Object Model that allows direct (or indirect) action on just about every object within the windows environment and does so natively via the windows script host interpreter ((which is extensible) (wscript.exe or cscript.exe)).  There are nuances to that statement, and I encourage you to investigate it more thoroughly, however I’m going to jump right into some of the basics of using this language, then discuss the code below as we’ve done in the previous 2 posts.

First off, what is a component object model?  Put as simply as possible, they are exposed objects that you can manipulate in the environment by invoking their methods and properties.  This scripting language brings you dangerously close to windows development at times, but at it’s heart, it’s still very much a script.  Controlling environment objects and properties, performing sequenced tasks, and no compile.

Now, I’m going to introduce 4 new things with this script, I will name them now and explain them after we’ve reviewed the code:

Arrays

WMI

Subroutines & Functions (They can be the same, but in WSH they are different)

Loops

Function VBscript (blog)

The overall activity of this script is the same as our drivemounter batch script we made.  Lets take a look at the code.


'||========================================|| 
'||Author Daniel Belcher                   || 
'||Function drivemounter                   || 
'||Date 5/4/2011                           || 
'||========================================|| 
'|Objects, Variables, and Arrays *********** 
'==========================================/ 
'|Set number of items in array             '| 
'|Example: 3 drives would be (3,1) and 4   '| 
Dim ArrDrive(6,1)                          '| 
DriveCount = 7                             '| 
’|Define the Array to read                 ‘| 
    arrDrive(0,0) = "h:"                   '| 
    arrDrive(0,1) = “\uncpath1”            '| 
    arrDrive(1,0) = "i:"                   '| 
    arrDrive(1,1) = ”\uncpath2”            '| 
    arrDrive(2,0) = "j:"                   '| 
    arrDrive(2,1) = ”\uncpath3”            '| 
    arrDrive(3,0) = "k:"                   '| 
    arrDrive(3,1) = ”\uncpath4”            '| 
    arrDrive(4,0) = "l:"                   '| 
    arrDrive(4,1) = ”\uncpath5”            '| 
    arrDrive(5,0) = "m:"                   '| 
    arrDrive(5,1) = ”\uncpath6”            '| 
    arrDrive(6,0) = "n:"                   ‘| 
    arrDrive(6,1) = "\uncpath7"            ‘| 
‘|Define the Server to Ping for Net Check  ‘| 
Dim strSvr                                 '| 
    strSvr = "servertoping"                '| 
'========================================================================== 
Const DEBUGMSG = True    'True = Debug Messages, False = No Messages 
Dim oWShell 
    Set oWShell = CreateObject("WScript.Shell") 
Dim oWNet 
    Set oWNet = CreateObject("WScript.Network") 
Dim Target 
    Target = "." 
Dim oWMISvc 
    Set oWMISvc = GetObject _ 
("winmgmts:{impersonationLevel=impersonate}!\"&Target&"rootcimv2") 
Dim oPing 
    Set oPing = oWMISvc.ExecQuery _ 
("Select StatusCode From Win32_PingStatus where Address = '"&strSvr&"'") 
'|Main Run ================================================================= 
DriveMount        'Perform Function DriveMount 
Report            'Perform Function Report 
Wscript.Quit(0)   'Close Script 
'SubRoutines and Procedures ================================================ 
Sub Mount(letter,path) 
    oWNet.MapNetworkDrive letter,path 
End Sub 
'***************************************************** 
Sub Umount(letter) 
    oWNet.RemoveNetworkDrive letter 
End Sub 
'|Functions ================================================================ 
Function DriveMount 
'http://msdn.microsoft.com/en-us/library/aa394350(v=vs.85).aspx 
    For Each item in oPing 
        If IsNull(item.StatusCode) or item.StatusCode<>0 Then 
'**********Domain not reachable, unmount drives in arrDrive 
        x = 0 
          do until x = DriveCount 
             On Error Resume Next 
                Umount arrDrive(x,0) 
                       If debugmsg then msgbox "Umount"& vbcrlf _ 
                       &"Drive Letter: "&arrDrive(x,0)& vbcrlf _ 
                       &     "Error Number: "&Err.Number& vbcrlf _ 
                       &     "Error: "&Err.Description 
              Err.Clear 
        x = x + 1 
          loop 
        else 
'**********Domain exists, mount drives from arrDrive 

        x = 0 
          do until x = DriveCount 
             On Error Resume Next 
                Mount arrDrive(x,0), arrDrive(x,1)  
                       If debugmsg then msgbox "Mount"& vbcrlf _ 
                       &"Drive Letter: "&arrDrive(x,0)& vbcrlf _ 
                       &     "Error Number: "&Err.Number& vbcrlf _ 
                       &     "Error: "&Err.Description 
              Err.Clear 
         x = x + 1 
          loop 

        End if 
   Next 
End Function 
'***************************************************** 
Function Report 
      If Debugmsg then msgbox "Script completed" 
End Function 
'End ======================================================================
 

Copy and paste the code and save as a .vbs file (unless you have a specific editor, I recommend notepad to insure formatting is properly translated.)

Lets start with our 4 areas of interest we’ve focused on with the previous posts.

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

Sequence:

Sequencing and Command usage will be the most interesting topics this time around.  Unless wscript is pointed towards a specific function or sub, it reads everything in line.  This point is rather large when you consider BASH and POWERSHELL and a lot of other script languages which will error out if something is called that hasn’t been previously declared (speaking about functions and subroutines, variables must always be declared before usage).  However, the rule remains that everything is read one after another, or AS the interpreter is directed to read.

As a habit when I write my vbscripts I will almost always write them in this format. Variables, Run sequence, subs, functions.  There is no real reason for this outside of the fact I prefer to immediately see variables and prescribed run order.

Now lets look at our variable declaration and focus on what’s new.  An array, and a multidimensional one at that (more than two columns of data).  An array is an assortment of data stored in memory, think of it like a spreadsheet.  Row 0,1,2,3,4,5,6 and Column 0,1,2,3,4,5,6.  This would be a multidimensional array.  A simple array would be 1 Column (column 0) and however many rows as you wanted.  In this script I declare this array to be limited to 7 rows and 2 columns.  That sounds weird right, cause the declare clearly says (6,1) ?  Remember that 0 counts so 6 = 7 and 1 = 2, but you declare it by the integer value of the last entry.

Dim ArrDrive(6,1)

I then declare my Array entries by defining ArrayName(row,column) = data

arrDrive(0,0) = "h:"          '| 
arrDrive(0,1) = “\uncpath1”   '| 
arrDrive(1,0) = "i:"          '| 
arrDrive(1,1) = ”\uncpath2”   '|

...

From here on out when I need to utilize any of these pieces of data I can simply call them using their array name and position.  Another way to think of this is a shared variable name perhaps?

Now lets discuss our run sequence:

'|Main Run ================================================================= 
DriveMount      'Perform Function DriveMount 
Report          'Perform Function Report 
Wscript.Quit(0) 'Close Script 

This block of code dictates the run order of my script.  The first 2 are Functions I have defined, and the last is a wscript method to insure a clean exit (more on this in command usage).

Sequence is important. For organizations sake, I will take a quick and easy VBScript and build it in this fashion.  For me, and for others, it allows for simpler review and additions to be made to the script that could and will improve it’s functionality.  It’s also far simpler to isolate bad sections of your script and to target a specific function for testing.

Now let’s discuss the iteration statements that are introduced in the DriveMount function.  I will touch on the code more specifically when we break down what the script is doing, but an iteration statement is just a loop that continually performs a task until a certain condition has been met.  That could be reaching a certain number, that could be reaching the end of a file, that could be reaching the end of an array, etc.  In this script (although not how I would naturally do it) I’ve offered 2 concrete examples of vbscript loop statements for your review.

Finally, subroutines and functions.  Similar to labels, identical to the function I showed with BASH.  They are, put succinctly, sections of code that can be called by name to perform a fixed task.  In VBScript specifically a sub routine passes back no data, a function does.  So if I need to perform mathematical operations and reuse it as a variable elsewhere, I’d use a function*.  If I just need to move a file from one location to the next, a sub.  As a safe bet inside of VBScript, declare them all as functions, there is really no benefit I’ve found one way or the other.  I declare them as Sub and Function only to offer them as an example. Syntax for this is:

 Function Name                              Sub Mount                          

        Code to use                             Code to use 

End Function                                End Sub

If you wish to use arguments with these functions/subs you would use:

Function Name (arguement1, arguement2, etc)
 
                Code using arguments provided
 
End Function 

Command Usage:

Unlike our other scripting languages so far, the WSH doesn’t really utilize commands per say.  Command usage is actually called through a COM.  So when you build a vbscript, you spend the first portion of the script defining what COMs will be utilized in the script.  This is all part of my initial variable declaration (DIM statements or Declare Into Memory)

Dim oWNet 
    Set oWNet = CreateObject("WScript.Network") 

This is essentially creating the callable object or “commandoWNet for me to use moving forward.  What’s actually happening is I am using the WScript object to instantiate (create an instance of) the WshNetwork object for later method or property usage (exposing the object for manipulation).

This is how an object based language works, call the object, use the object, (and ideally) release the object.  When I later use these objects methods I will do so by invoking them.  Syntax comes in to play in these cases.

oWNet.MapNetworkDrive letter,path

That is the invocation of the WshNetwork MapNetworkDrive method which requires drive letter then path to map.  Hopefully that makes sense, it’s an extra step but allows for some amazing control and it remains rather light weight as it depends on existing objects for it’s control base as opposed to having them already built in.  However that’s not to say there aren’t commands built into the WSH but they are for conditional and iteration statements as well as integer, string, and date functions (w3schools.com has a nice breakdown as well) etc.

Output Usage and Conditional Logic:

For this script the output usage is in reading a ping response, mapping drives, and in exception handling (error catching).  We read the status code from the WMI Win32_PingStatus class object (list of WMI Classes) then use it as our condition.  We then loop through the array and perform the appropriate action while catching and clearing any potential errors.  We also redirect that error output to a popup message if DEBUGMSG Boolean is set to TRUE in our initial variable declaration.

Our conditional logic as stated before is in the form of IF statements.  I will demonstrate case statements in my PowerShell write up.  Case statements look for something (usually a specific string type) and respond in a defined way.  However a case statement is strictly defined where an IF statement is generally this or that, it will make more sense in the future I promise.


So what does this vbscript do?

In this script we open with our declarations.  We define our Array ArrDrive as a 7 row and 2 column array (0 counts, remember though declaration will be the last integer value so in this case: 6,1) and supply it with values.  We set a Boolean for debugging messages and we set our object instance for WScript.Network to oWNet.

We also start an instance of the WMI Service, and define a WQL that reads the ping status to a targeted server (strSvr) for us (Target=”.” means the local machine, it can be changed for remote PC name, more on wmi scripting).  (WMI is Windows Management Instrumentation, similar to the WSH objects it contains a series of namespaces, classes, methods, and properties to control the windows platform.  Essentially if you can do it on the Windows machine, there is a WMI namespace/class/method involved in it.)

Dim Target 
    Target = "."
Dim oWMISvc 
    Set oWMISvc = GetObject _
("winmgmts:{impersonationLevel=impersonate}!\"&Target&"rootcimv2")
Dim oPing 
    Set oPing = oWMISvc.ExecQuery _
("Select StatusCode From Win32_PingStatus where Address = ‘"&strSvr&"’")

Now that we have all that declared we move into our run sequence.  The Function DriveMount is first and it immediately performs a For Each statement through our oPing WQL and grabs the statuscode value and compares it with an IF statement.

For Each item in oPing 
         If IsNull(item.StatusCode) or item.StatusCode<>0 Then 

If there is no value, or the status code is anything but 0 (0 is a clean exit code, success, that’s what the status code is in its simplest form) then we aren’t in our appropriate network so we will begin a Dismount loop.  If the return value is 0 and is NOT null then we will perform a Mount loop.

Lets stop here for a second so I can explain this loop line for line, first the code sample:

‘**********Domain exists, mount drives from arrDrive
 

x = 0
  do until x = DriveCount 
     On Error Resume Next
        Mount arrDrive(x,0), arrDrive(x,1)   
              If debugmsg then msgbox "Mount"& vbcrlf _
              &"Drive Letter: "&arrDrive(x,0)& vbcrlf _ 
              & "Error Number: "&Err.Number& vbcrlf _
              & "Error: "&Err.Description 
     Err.Clear
x = x + 1
   loop 

We declare x as 0, we will enumerate this integer value with each pass of our iteration (loop).  Word of warning here, if using this method make doubly sure that you set your enumerate value outside of the loop or it will be re-declared each loop and become an infinite loop.

We do until x = DriveCount, we declared DriveCount as 7 at the start of the script.  This loop will loop 7 times.

On Error Resume Next, we will not let error outputs break our function, we will perform the next in line.

We run the Mount subroutine passing the letter and path arguments which we pull from our arrDrive array.  We use x to select our row (remember we are enumerating x) and select the appropriate column for the data to pass.

Now as an extra step, we check for the DEBUGMSG Boolean, if it’s TRUE, we generate a popup window that tells us what Subroutine is being used, drive letter, error number, and error message. (if the drives are already mounted it WILL error, the error is that the drives are already mounted, so this is helpful if we are chasing something down)

We clear the errors that may or may not have been generated.

Now we take x and we add 1 to it, so 0 becomes 1, 1 becomes 2, 2 becomes 3, etc on each successive pass.

Finally we terminate the statement with loop so that the WSH knows to return to the start of the loop statement.

Easy huh?  There is a lot of power to learning how to use loops and for each statements effectively.

I would normally have just made another for each statement against the array which would read it to the end, but I felt this serves as a great learning opportunity.

At this point our DriveMount function is complete so we move to the next Function in the run sequence which is Report.  Report runs a debugmsg check and tells us the script completed if debugmsg is true.

Now back to our run sequence where we close our script with

Wscript.Quit(0) 

This insures an exit code of 0 which is a universal “everything ran great, nothing to see here” output.

End Function

Next up we will be discussing PowerShell.  A very robust shell scripting language for the newer windows platforms (xp sp3+) that utilizes commands, .net, com, wmi, dcom, and the list goes on.  I’ll try to keep it lite.


Now for some bonus material, lets take a look at the Mount loop if I had used a For Each instead of a conditional loop:

x = 0
For Each object in arrDrive
    On Error Resume Next
       Mount arrDrive(x,0), arrDrive(x,1)
            If debugmsg then msgbox "Mount"& vbcrlf _
            &"Drive Letter: "&arrDrive(x,0)& vbcrlf _ 
            & "Error Number: "&Err.Number& vbcrlf _
            & "Error: "&Err.Description 
     Err.Clear
x = x + 1  
Next

You are probably thinking “this looks the same, why is this better?”.

When you perform a conditional loop statement it needs a stop point which is another factor you have to manage.  In this case we had to declare a maximum loop count (our DriveCount variable which was 7).  A for each statement will go through a list till the end and then move on.  You can think of a for each statement as “For Each item in whatever until the end.”

If you have any questions or corrections, please leave a comment and I’ll try and get back with you about it. For an unaltered version of this script to copy and paste, go here.


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 …

Ok, so this has been out as a retail release for more than a year. (Originally released in Feb of 2010) I remember being completely psyched for this game.  A Sci-Fi FPS MMO made by a company about 2 hours from my house, what’s not to love?

 

 

Long story short, I’m not sure what happened but I never ended up buying it because of my new job and how busy I became etc.  However they just recently went FtP (Free to Play) and with a price like that it’s hard NOT to play right?

Anyway, lets keep this simple:

Graphically, the game has a very stylized look.  Nothing amazing per say, but it has a clean look about it.  The interface, although functional, feels and looks a bit clunky.  It would be nice for a native method to scale it down, but overall the games appearance is sharp enough that it remains appealing.

Sound wise, the game is alright.  Though admittedly the music gets turned down rather fast so I can hear people run around in pvp.  The sound is clear enough, and diverse enough that you can use them for audible cues.

Gameplay, well I will say this first off.  I like the gameplay, the mechanics, the pve (surprisingly) and the competitive play.  I did not however, start out liking them.  The simplest way that I can put it is this, there is an amazing simplicity to the 4 class system that works, and enough diversity play style wise to keep me entertained.  The 4 classes are:

Assault: General tank and heavy artillery.  The class take and deal a considerable amount of damage when speced properly and in pvp can be a king for offensive objective control.

Recon: Stealth? Melee? Sniper? Yea that about sums the class up.  Very very sneaky.

Medic: Poisons and heals.  Decent damage if required to fight.  Overall this class plays well in pve and pvp for their healing and general CC utility.

Robotics: Turrets, drones, heal stations, and recharge stations.  The assault in pvp can be the offensive objective king, but a robotics player is the defensive one.  Similar to medic in the amount of versatility, but forced largely to choose mobility or survivability.

Each class has 3 trees, one of which is a universal tree called balance.  The other 2 are class specific that focuses on play style specialties.  For instance, assault is: balance, tank explosive. 

I can honestly say as well from my perspective, that balance seems very real.  I have yet to be on any particular class and just feel as if I am hopelessly lost against a particular pairing.  Like any class based shooter, you should expect limitations to your role, and respond to fill it.

At the same time, the min maxing that people enjoy from other MMO titles exists here as well, so it IS capable to get an edge, it’s not the kind of thing that is out of hand.  To be honest with you, I feel CoD titles are less in balance with unlocks than this title is.

Another point of interest is the AvA system, achievements, PvE instances, and just random loot hunting that turns this into a very fun and addictive title.  I highly recommend you give it a try (it’s free after all) and just play your way up to 20.  You might be surprised, and feel free to contact me in game.

lotekness

Global Agenda

Alright, so continuing our discussion on scripting with Bash scripting in Unix and Linux.  In the same way that command interprets a script to perform actions in order so does bash.  What’s the difference then?  The sheer volume or tools available to script and manipulate the environment is greatly increased.  The manageability of output, the variety of conditionals, arrays, and integration of the shell into the environment.

It’s worth mentioning up front, I could spend days on the subject of any of these scripting languages.  However for the sake of space and interest, I will still keep things high level.  It’s ALSO worth mentioning that Bash/shell scripting is something of a nix requirement.  Not that you have to know shell scripting to use the OS, but it’s certainly a primary part of the culture.  Bash scripting also works within OSX environments (since it’s built on BSD), however some research and testing will be required to find the similarities between their nix and others which leads to my next topic…

Linux and Unix {

If you are reading this, I will assume you know what Linux and Unix are.  If not, here’s some reading material for Unix and Linux.  What you may or may not be aware of is that although there is a great level of standardization as maintained by IEEE POSIX standards, there is also a lot of distribution specific tools or practices.  In other words, a person can generally port work from one distribution to another, but should never assume a one size fits all solution across the board.  Which is precisely why there are so many distributions, because one size does not fit all, at least not to everyone’s tastes.

I also want to take a moment to point out that this is not a flaw. Although standardization is a good thing, limited options are not. There are other standards that GPL licensed software (generally linux)adheres to that gives it reliable standards or compliance. They also maintain partial POSIX compliance as well. It’s an interesting subject, and the differences are fairly minor in most cases. Do not be scared by the options, determine what it is you want and go from there if you are interested in trying.

Now a days the user experience one has come to expect from Windows or OSX is easily found with a popular Linux distribution (Ubuntu and Fedora immediately come to mind).

     Bash Scripting {

Now lets take a look at a very simple script that I’ve briefly modified from Mendel Cooper’s guide for an example on here:


#!/bin/bash#Log Cleanup
#Author: Daniel Belcher
#4/30/11
#Built for tutorial purposes
#Idea for script from beginner example
#in advanced bash scripting guide:
#http://tldp.org/LDP/abs/html/sha-bang.html#Variable declaration
LDIR="/var/log/"
DATE=`date '+%m%d%y'`
RUID=0
E_USER=1#Checking for root user, exiting with error code 1 if not root
if [ "$UID" -ne "$RUID" ]
then
          echo "User needs to be root"
exit $E_USER
fi
#Copying the current messages and wtmp logs to an archive with date code
cp $LDIR"messages" $LDIR"messages."$DATE;
     cp $LDIR"wtmp" $LDIR"wtmp."$DATE;
#Taking the last 10 lines from that log and writing it to the current
#messages and wtmp to reset them.
tail -n 10 $LDIR"messages."$DATE > $LDIR"messages"
          tail -n 10 $LDIR"wtmp."$DATE > $LDIR"wtmp"                
   sleep .5
#Finding all messages and wtmp files with an
#access time of 7 days or more and deleting them.
find $LDIR -iname messages.* -atime 7 -exec rm {} ; #could also swap –exec rm etc for –delete 
             find $LDIR -iname wtmp.* -atime 7 | xarg rm 


Save as a .sh

then

chmod +x scriptname.sh

Now same as with our batch script, lets focus on 4 things.  Hopefully some similarities begin to present themselves.

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

Sequence:

Now similarly to the command shell, Bash reads the script line for line.  However instead of GOTO statements in Bash, we would actually build functions. (I do not have an example in this script but the syntax is generally name_of_function() { work to perform }.  I’ll discuss this more with PowerShell and VB script).  All lines are read as if they were typed at the console.  Here you will see I also do something that we didn’t do within the batch file.  Variable declaration (LDIR=”/var/log/”) then I can call it again in the script as $LDIR.

This allows you to take a commonly used command, object, integer, or string and set it to something easily repeatable inside the script.  Variables can be declared at run time, as an argument, or produced from script output to name a few methods for declaration.  They are integral to programming in general.  As far as sequence is concerned, as long as the variable is declared before it’s called you are fine.

Command usage and Output usage:

Now hopefully you are seeing that the commands available in a shell are what does most of the heavy lifting in terms of work.  Something worth learning in command usage is piping.  Piping is taking the output of one command and using it as the input for another (to put it simply).  A visual I’ve always liked to use in understanding what is happening is this:

A lake brings water to your home.  A pipe exists between the lake and your faucet (very simple). On the course to your house a series of filters are applied to weed out what you don’t want from the water by the time it reaches your house.  In this case the lake is the source or original input, and the filters are the series of commands applied to the pipe before the final output at your faucet.

So in pseudo code: lake-water | filter-fish | filter-algae | filter-dirt > glass-of-water.drk

The end result is that water is transported through that pipe and all unwanted elements are removed until we finally have our desired glass of water to drink.

In this case we use:

find $LDIR -iname wtmp.* -atime 7 | xarg rm 

This will take the findings from the FIND command and pass it to xarg which initiates rm and deletes these files.

Hopefully this is beginning to paint a clearer picture of pipe and command usage.  Shells that allow for command piping are a God send and allow for some very elegant solutions to complex problems in simple one liners that a user could easily alias, but that’s another subject entirely.

Conditional Logic:

Now in an identical fashion to our batch file we are performing an IF statement.  IF statements are one of, if not the most, commonly used conditional statements.  Notice there is a very distinct difference in the syntax used here in comparison to the one we used in our batch.  The testing method and outcome are still the same however, so do not be deceived.  IF statements put simply are: if it’s this then do that.  Since conditional tests are capable of greater complexity (and will be with all other script engines we discuss going forward) it needs to be terminated so the script knows when the conditions or work statements are final. We close this IF statement in Bash script by spelling IF backwards FI.

The same is true for all conditionals within bash.  They will open spelled forward and close in reverse.  Elif … file case … esac; when you begin to learn what and how logic is applied in scripts you will know how to appropriately apply the syntax.

So what does this Bash script do?

The script opens with a shabang! (#!/bin/bash) which tells the shell that it’s a script to be interpreted by the bash shell found in the bin folder.

Next it declares 4 variables, LDIR (log directory path), DATE (current date no special characters month date year), RUID (Root user id), and E_USER (error code to use if the user fails our user check).

Now we check a shell variable $UID (current user’s ID #) and see if it’s different than the $RUID (-ne = not equal). If it’s not the root user we exit with the error code # assigned to $E_USER.

If we pass that check we will now copy the messages and wtmp files under the /var/log/ folder to their same folder as filename.currentdate.  Example: messages.050111

Now we take the last 10 lines of that file and output it to the primary log files messages and wtmp effectively overwriting the previous data and truncating that file.  > operator on the command line is a redirect (as we saw with our > nul in the batch file).

Finally we take and search that folder for all files following the archived file syntax and search for an access time greater than 7 days then we delete them.  I’ve used two different formats for deletion to show the different possible ways of doing this.

     } gnitidE shaB

} xinU dna xuniL

In my next post I’m going to break into vb scripting, which is a considerable departure from the shell relative scripting we’ve looked at so far.  However I will return to another form of shell scripting with PowerShell, stay tuned.


Just for another example, how would this script look utilizing a function?

#!/bin/bash#Log Cleanup 
#Author: Daniel Belcher 
#5/1/11#Variable declaration 
LDIR="/var/log/" 
DATE=`date '+%m%d%y'` 
RUID=0 
E_USER=1#Checking for root user, exiting with error code 1 if not root 
if [ "$UID" -ne "$RUID" ] 
then 
         echo "User needs to be root" 
exit $E_USER 
fi 
#Function to create backup, truncate, and purge old log files. 
cleanup () { 
                 cp $LDIR$1 $LDIR$1"."$DATE; 
                         tail -n 10 $LDIR$1"."$DATE > $LDIR$1 
                                 sleep .7 
                         find $LDIR -iname $1.* -atime 7 -exec rm {} ; 
                 return 0 
                 } 

#Calling function cleanup () and passing 1 argument

cleanup messages 
cleanup wtmp

exit 0

A lot cleaner.  Hopefully you can see the benefits of functions now, or even loops as we will examine in the future.


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 …