20
Oct
09

VB vs. PHP

Recently I have been developing web sites and web apps using Visual Basic in Visual Studio 2008. This isn’t a huge leap for me since I have training in C# in VS 2005. I think there have been plenty of comparisons between C# and VB, so I thought I would take the other road of comparing VB to PHP for those who are wondering.

First of all, to be clear, the architecture I have chosen on both sides is in line with the MVC philosophy of separation of presentation and business logic. I am using ASP MVC in Visual Basic. I am not using Webforms. Why? Because they don’t seem to be meant for high traffic, highly customized web sites. If you have used them before, even if you take the time to configure them properly, they are still heavy on the download. Also, if you want to customize them, even with CSS you need to cut open the welded hood to get to the engine so to speak.

Some have expressed envy in the PHP community for drag and drop programming. Hopefully they have found satisfaction in either using Delphi for PHP, Flex Builder, or actually moving to Visual Studio. As I have said before, DND “programming” does not satisfy my requirements of fitting my chosen methodologies. In addition, I chose the ASP.NET MVC that comes with .NET 3.5 SP1 (aka 3.5.1) as my framework for Visual Basic ASP.NET development. This precludes even having the option of using Webforms controls due to the fact that it does not support the method of state storage required for such controls. The ASP.NET MVC tends toward a more Restful nature, and so the two frameworks do not work together well.

To continue this MVC tangent, it is a respectable project. It seems to be developing in a linear manner making breaks only where it makes sense, and versioning appropriately. Since I started using 1.x, the API has only grown. I hear there are some differences in 2.x although minor.

I wont get into comparing ASP.NET MVC to any PHP MVC frameworks, but it compares relatively directly to most with the addition of some elaborate (some times daunting) routing.

You may think it foolhardy to compare a dynamic language to a strongly typed language. It is interesting how both languages lean toward each other. PHP is the dynamic language that lets you type hint. VB is the strongly typed language that tries to let you get away with being dynamic. VB 2008 has many feature that are new to .NET land. Features that C# doesn’t even have. Although C# wont be left out for long since the .NET Framework team has pledged to bring them parallel in the 4.0 series.

As language stability and consistency goes, .NET has seen some turbulent times through 3.x. This is similar to what PHP5 saw around the 5.1 time frame. Both have seemed to level out with those rocking boat looking to the next versions. VB on .NET 3.5sp1 wont be the time lasting version though. It seems to me that the 4.0 series is going to settle down for maturity a bit. At least that is my hope, and what I gather from what I read. We will see. PHP 5.3 feels like a click off center too, like 4.3 of old it has the feature set, but we seem to be waiting for a security release. Or, maybe that is the 90’s Linux Kernel hacker in me.

The one thing I like about PHP above all others is the clean sensible style one can achieve. The object structure allows you restrict where you need, and permit where you want. If you want to lock down your classes so you only get exactly what you need, you can type hint on the objects you want. If you want to build a uber smart method that takes anything you can throw at it, you can. The syntax is fundamentally clear. Statements end in semi-colons, curly braces delimit blocks without getting in your way. If you have seen very much C# you can see how curly braces can be taken to the extreme.

VB on the other hand is a ambiguous pile of goo. You can quote me on that. Why do I say that? If I were using VB what does the following statement do?

Return (A = B)

That is right, this is were the rant starts. VB uses the equal sign (=) for both comparisons and assignment. You may be thinking that this can be dealt with, for the most part you are correct. Usually when you are doing comparisons you accompany it with ‘IF’ or the like. Also, in both VB and PHP there is a function that is like EmptyOrNull(). However, VB ALSO calls Null, “Nothing”. On top of that it doesn’t allow the ‘=’ operator during comparisons all the time. Usually it requires the use of ‘is Nothing’ similar to the SQL operator of ‘IS NULL’.

That brings us to scope. Scope in PHP is a rule that some like to blatantly violate. Newcomers to the language sometimes decide to forgo learning the rules and start shoving data in global vars. As with my over all feeling of VB, the use of ‘Me’ in self referencing is cute. It is not really an issue, but rarely do programmers use it. The scope within a class is so that it encourages you not to. The use of name spaces can also cause issues. I know PHP just added this feature, and I see little use for it. When abused though it can cause further ambiguity. A referenced function or class may be found in multiple places, and only visiting the “Imports” section can clarify, but not always.

There is wide diversity in the PHP community over which IDE they use, and some advocate an editor over an IDE. The VB community for the most part uses Visual Studio or Visual Web Developer. I have found that most of what I actually use is present in Visual Web Developer 2008 Express, one of the free (as in beer) versions from Microsoft. There are several things completely amiss in all the variants of Visual Studio. Editing of Javascript is a nightmare. The IDE is incapable of editing Javascript. It tries to format it as you type while actually shoving your cursor around to different locations. It is sad to think that Microsoft cant handle such a simple task as leaving things alone that it doesn’t understand. If you have a Javascript file open when you run the debugger it tries to debug your javascript as jscript. The second is that it violates Microsoft’s standard keyboard shortcuts out of the box. Then there is the lack of version control support.

.NET throws exceptions that sometimes have what they call “inner exceptions”. While this adds flexibility to your exceptions, the IDE nearly fails to handle them. When halted on the exception, the common dialog tells you to view the inner exception. When you view the exception it comes up in an archaic grid that does not even let you scroll to read the whole error. You are forced to use the mouse tool tip to read it, which only stays on the screen for a couple seconds. If your debugging doesn’t work, why use it at all. Further, if your debugger doesn’t work, what good is your IDE. You should drop back to an editor that you didn’t pay $1,200 for.

That being said, there are some other tools that can shield you from programming in VB. VS is relatively adept at code generation using the T4 templating engine. If you get adept at scripting your code generation, it can be a quite satisfying practice. Also the Entity Framework is a nice ORM for use with a supported RDMS. Although it suffers from the common ORM code generation problems it offers a respectable interface to your business logic. This is especially the case when combined with Linq queries. Things get a little hairy when you start to get sophisticated with your business logic though. A highly flexible platform VB ASP.NET may not be.

Although I do concede I have 10+ years experience with PHP and about a total of two with VB .NET, you cant overlook the fundamental issues of ambiguous syntax in Visual Basic .NET and a poor web integrated development environment.

Since I have learned both languages by using the web on my own, in the next few posts I will try to impart my experiences in both languages and gift you my learning resources.

05
Aug
09

Code Generation

Code Generation has long been an interest of mine.  No matter if it is PHP, C# or now VB.NET code generation can gets me up to speed with the basics fast.  RAD is something that left a bad taste in my mouth.  In fact most anyone who actually supports their work cringes when you say RAD or mention code generation.  With the Framework craze these days though, there are many places where code isn’t generated, but the same problems are encountered with the convention over configuration crowd.  So I approach code generation with caution.  The sad fact is that there are things that we repeat over and over again.

How many times have you typed “SECT * FROM foo”?  The key is keeping code generation extensible.  Where technology in general falls apart is where it tries to think for you and have it’s own preference where preference is the only deciding factor.  Frameworks that are good but require you to conform to their school  of thought only find acceptance amongst those who already think that way or don’t have enough experience under their belt to have an opinion yet.  The more generic and customizable the better.

Enter T4, the new code template system in Visual Studio 2008.  This is a great technology. As I learn it I find myself weaving more repeditive code, but with better quality.  It makes CRUD controllers a dream to deal with, and holds the potential for saving alot of time.  As I come across usefull T4 resources I will post them here.

I am interested to see how this changes my perception of my own code generation.  The T4 template usage is interesting.  They really allow for alot of logic within the template makign complicated generation possible.  Already I see this making it’s way into my own generator.

05
Aug
09

OOD In an MVC Land

If you are familiar with asp you are probably familiar with the concept of code behind and more recently MVC. Over the years I have bounced around using many different languages, frameworks and technologies. Using the pattern in another language emphasizes that this is best implemented as a conceptual pattern. OOD is best done first if you have any logic at all. If you are just editing a list and it IS just a CRUD app, an MVC up front approach might work fine. Every where I look the MVC is pushed as THE solution. When, like any other design pattern, it is never more than a piece. Try to think outside the MVC box and do what works. Don’t try to cram everything you want to do into the MVC or you will then need to create classes called ‘helpers’ and then the only business object you really have is the MVC, and you might as well have not done OOP in the first place, and you should have stuck with Clasic ASP or PHP4 and your procedural, monolithic methodologies.

Remember to keep your business logic out of your display logic. If you call it a template or a view is up to you. Just don’t be caught with your pants down when you find out your model is hard-coded to your business logic. Or worse, you find application has become a big string of classes that are untestable and codependent on your control structure. I always keep focused on being loosely coupled and dynamic without being magic.
Which brings me to the ASP MVC.NET implementation. As with many things in .NET, it seems to be a situation of ‘we want that buzzword tech. too!’. There are many advantages, and as usual I get the feeling it is a step in the right direction. Also not a surprise, it feels like it is not what is supposed to be. Like the point was lost in the translation. The .NET crowd wanted Ajax, they got the word but missed the point. their websites were freed from having to load the whole page, but they still were cursed with throning the state string back and forth and never got the benefit of good efficient client side processing with JavaScript.
Oh man, I don’t want to get started on JavaScript in the MS camp. Almost all the MS shops I have talked to in the last year think ‘Java’ and ‘JavaScript’ are terms that are interchangeable. To their credit, for all they knew of either they might as well be.
Then the .NET crews whined about not having flash, so they got Silverlight. (which I like what I have seen, but why cant every one just love SVG???)
My largest point of contention with ASP.NET is that all the training and documentaiton pushes you to use the built in controls. The built in controls are obviously not meant for the Internet, but are for LAN apps. Thus ASP.NET is best suited for application developers moving into the Web Interface realm. I once saw a ASP.NET application that fed 6MB HTML (not including graphics) at the user. This was the worst case, but was far from atypical.
Enter the ASP MVC. None of the state dependent controls work. Pat them on the back for destroying the only thing the rest of the web development world envies them for. Wait, this isn’t a totally negative rant. ASP MVC encourages you to be conscious and intentional with your HTML. It also opens the door for using jQuery instead of Microsoft Ajax. Thus, as far as the client/browser side you are free to do as you please.
But, then you may think that all is well. Until you start dealing with the server side. I am not going to get down on it, since it is still in development. Although, as with any software if it is out of development it is dead, so take that as you will. The real problem that I do see is that it tries too hard to be an MVC. Your Controllers end up getting huge with ‘actions’ (and where is that /really/ in the pattern). There is only one layer of organization in the controller. This means you cant go beyond controller/action. Granted you can customize your routing, which feels like you are configuring someone else’s app, instead of building your own. Then all your views tend to be one per action which defeats at least the bulk of the benefit of application and presentation separation.
Hear again, another MS team tries to step in and save the day. The Entity Framework (EF) is the official flavor of the day. This essentially is your ORM Model to supply your CRUD. None of which lend themselves to good OOD. You still are encouraged to draw up a action that feels oddly procedural mashing your EF object lists into a view. EF does not allow for any type of static extension so there is no natural way to build business objects. The solution to this is to just build your business objects facade over the EF ORM. But no examples encourage this, neither does any of the community publicize this. So you should shove your monolithic processing in an action and pray you can rewrite instead of maintain. Now to add to the sadness of it all, there is no straight forward way to call and render an action from another controller. So now that you have a huge controller class you now start copy and pasting code between actions. I have seen Quick Basic apps that are better.
Maybe I am just jumping the gun. It is still in development after all. Maybe the ASP MVC community will get there.
Currently the way I am dealing with everything is having a nice thick jQuery driven client. I load partial views in via Ajax and call JSON services. No community so far has dogged the MVC fail bullet. I just want to know when everyone is going to move on from MVC and realize OOP != OOD

02
Jul
09

Back in .NET Land

So I am working a gig that brings me back to the .NET word. This is not to the C# world I am familiar with but even deeper into M$ territory: VB.NET. Oh, the horror!
Seriously though I am going to make the best of it. One of the things I notice as I strip back the layers is that .NET has gone through some great improvements since I last used it. It is really important that jQuery is more widely accepted. Back in the days of Atlas jQuery usage was difficult at best, although still better than Atlas.
I noticed too that a great number of the examples on the net are C#, and that community has grown. I sometimes find it comical that there exist many C# to VB and back converters. Anyone with any experience knows this is a horrible thing to do. Even if it does ‘work’ the result is anything but optimal. Usually it isn’t even practical. Despite all that I find myself using them to follow .NET tutorials written for C# thinking I can make it work the same in VB, right? Am I nuts? You bet. The differences are too great to ignore. You may be able to call a lib the same, but functional logic becomes awkward. Suffice it to say I spend more time trying to find resources than using them right now. If you have some favorite ones, feel free to share. :)

03
Jun
09

Remote Error Messages IIS

By default IIS does not display detailed errors to anything but a browser on the local server.  This can be a pain if you are using a VM or server with IDE and Browser are on a different machine.  This should obviously only be done on a development machine.  This being said, open IIS Manager and navigate to Error Pages.IIS_ErrorPages

remote_errors

Then Click ‘Edit Feature Settings. Then select ‘Detailed Errors’ to display them to the client.  Click OK and restart your web server service to make sure, and develop quicker.  For more information look on the official IIS Blog.

31
May
09

Dante Job Scheduler: Sending Paralell Email with the Crossley Framework

Delaying actions until times of lower traffic and completely offloading jobs to specialized servers are classic ways to scale. Also, the classic way to demonstrate how this works and the benefits is by sending an email. So here is the obligatory email example with the Crossley framework:

$oJob = new X_Scheduler_Job(X_Scheduler_Job::TYPE_PHP);
$oJob->setScript('email_script.php');
$oJob->setVariable('sFrom', 'me@example.com');
$oJob->setVariable('sTo', 'you@example.com');
$oJob->setVariable('sSubject', 'A Test Email');
$oJob->setVariable('sBody', 'This is a test, Yo!');
$oJob->register();

Let me explain what is happening here. We are creating a PHP task by passing the PHP Type constant to the Scheduler Job class. We set the PHP script to ‘email_script.php’. The contents of this script could be something as simple as the following:


$sHeaders = 'From: ' . $sFrom . "\r\n" .
'Reply-To: ' . $sFrom . "\r\n" .
'X-Mailer: PHP/' . phpversion();
mail($sTo, $sSubject , $sBody, $sHeaders);

You notice the php variables used here, one way to set these values is via the setVariable() method of the X_Scheduler_Job object. These are then reset within it’s scope prior to executing the script.

While this functionality is very much at an alpha stage, you can watch Dante and The Crossley Framework develop on Google code or at dante.drydenproject.com.

30
May
09

Creating Windows Task with PHP

Recently I have looked at how to list windows accounts via PHP with an eye to administration, read the windows registry, and list scheduled jobs on Microsoft Windows with PHP.  This time around I want to advance the Dante PHP Job Scheduler to the next logical level:  creating scheduled tasks.

Remember that writing the most basic COM related PHP could be as simple as translating from VBS to PHP.  However, VBS+COM is very involved and threatens the simplicity that is the reason we are using PHP in the first place.  So we will be concentrating on initial implementation (VBS translated to PHP) and I will be wrapping this functionality in PHP 5 classes later.

Once more taking a look at MSDN there is an example of adding a task to run at a certain time.  Also the example has given us an outline of the steps to accomplish this:

  1. Create a TaskService Object and Get a task folder
  2. Create a task (with TaskService.NewTask)
  3. Define information about the task
  4. Create a time-based trigger
  5. Create an action for the task
  6. Register the task

Looking at the example on MSDN, the first thing that strikes me about this process is that it is really messy and complicated to code.  Here is how I want to use it to register a notepad to run in 30 seconds.

$oTask = new X_Scheduler_Task('C:\\Windows\\System32\\notepad.exe');
$oTask->schedule(time()+30); // 30 seconds from now
$oTask->register();

Create a TaskService Object and Get a Task Folder

Now lets start with a TaskService object and selecting the folder.

$oSchedule = new COM("Schedule.Service");
$oSchedule->Connect();
$oFolder = $oSchedule->GetFolder("\\");

Create a task

Then create the new Task variant (refer to previous post for TaskService explination):

$oTaskDefinition = $oSchedule->NewTask(0);

Now we have an empty Task Definition variant ready to define. What is the ‘0′ (zero) for? MSDN says for the future. That is right, no reason, you just have to pass it. One of the nice things about it being wrapped the class will just handle it and I wont see it, as it mocks my OCD.

Now the TaskDefinition object is different from the RegisteredTask object.  Take a look at what the documentation gives us:

TaskDefinition Properties:

Actions Read/write Gets or sets a collection of actions that are performed by the task.
Data Read/write Gets or sets the data that is associated with the task. This data is ignored by the Task Scheduler service, but is used by third-parties who wish to extend the task format.
Principal Read/write Gets or sets the principal for the task that provides the security credentials for the task.
RegistrationInfo Read/write Gets or sets the registration information that is used to describe a task, such as the description of the task, the author of the task, and the date the task is registered.
Settings Read/write Gets or sets the settings that define how the Task Scheduler service performs the task.
Triggers Read/write Gets or sets a collection of triggers that are used to start a task.
XmlText Read/write Gets or sets the XML-formatted definition of the task.

Define Information About The Task

TaskDefinition is simply a meta style object and does not have any methods. The Data property looks interesting, I might look at that later.   So now that we have that, we will want to add some useful information in the ‘RegistrationInfo’ which is itself a meta style object.  The MSDN documentation falls flat here, but we get an idea from the example:

$RegistrationInfo = $oTaskDefinition->RegistrationInfo;
$RegistrationInfo->Description = "Start notepad";
$RegistrationInfo->Author = "Author Name";

You can also find the Principal docs if you fish arround on your own.  Now we need to define who the task will be run as.  The example uses interactive login which is a little awkward on a webserver.  So our Task Logon Type options are:

ASK_LOGON_NONE
0
The logon method is not specified. Used for non-NT credentials.
TASK_LOGON_PASSWORD
1
Use a password for logging on the user. The password must be supplied at registration time.
TASK_LOGON_S4U
2
Use an existing interactive token to run a task. The user must log on using a service for user (S4U) logon. When an S4U logon is used, no password is stored by the system and there is no access to either the network or encrypted files.
TASK_LOGON_INTERACTIVE_TOKEN
3
User must already be logged on. The task will be run only in an existing interactive session.
TASK_LOGON_GROUP
4
Group activation. The userId field specifies the group.
TASK_LOGON_SERVICE_ACCOUNT
5
Indicates that a Local System, Local Service, or Network Service account is being used as a security context to run the task.
TASK_LOGON_INTERACTIVE_TOKEN_OR_PASSWORD
6
First use the interactive token. If the user is not logged on (no interactive token is available), then the password is used. The password must be specified when a task is registered. This flag is not recommended for new tasks because it is less reliable than TASK_LOGON_PASSWORD.

The easiest to use is TASK_LOGON_SERVICE_ACCOUNT since we are running the task under IIS. Note this registers and executes the task under the ‘IUSR’ user’s permissions or whatever account IIS is running under.  You can use TASK_LOGOON_PASSWORD to register the task to run under a different account.  This would be the best practice since you will want to track this user seperate from IIS and you may want to elevate the rights of this user.  If you use this method, you will need to supply valid user credentials when registering the task later.

define('TASK_SERVICE_ACCOUNT', 5);
$oPrincipal = $oTaskDefinition->Principal;
$oPrincipal ->LogonType = TASK_SERVICE_ACCOUNT;

Now there are some basic settings we need to set:

$oSettings = $oTaskDefinition->Settings
$oSettings->Enabled = true;
$oSettings->StartWhenAvailable = true;
$oSettings->Hidden = false;

Here is what TaskSettings are available:

AllowDemandStart Read/write Gets or sets a Boolean value that indicates that the task can be started by using either the Run command or the Context menu.
AllowHardTerminate Read/write Gets or sets a Boolean value that indicates that the task may be terminated by using TerminateProcess.
Compatibility Read/write Gets or sets an integer value that indicates which version of Task Scheduler a task is compatible with.
DeleteExpiredTaskAfter Read/write Gets or sets the amount of time that the Task Scheduler will wait before deleting the task after it expires.
DisallowStartIfOnBatteries Read/write Gets or sets a Boolean value that indicates that the task will not be started if the computer is running on battery power.
Enabled Read/write Gets or sets a Boolean value that indicates that the task is enabled. The task can be performed only when this setting is True.
ExecutionTimeLimit Read/write Gets or sets the amount of time allowed to complete the task.
Hidden Read/write Gets or sets a Boolean value that indicates that the task will not be visible in the UI. However, administrators can override this setting through the use of a “master switch” that makes all tasks visible in the UI.
IdleSettings Read/write Gets or sets the information that specifies how the Task Scheduler performs tasks when the computer is in an idle state.
MultipleInstances Read/write Gets or sets the policy that defines how the Task Scheduler deals with multiple instances of the task.
NetworkSettings Read/write Gets or sets the network settings object that contains a network profile identifier and name. If the RunOnlyIfNetworkAvailable property of TaskSettings is True and a network propfile is specified in the NetworkSettings property, then the task will run only if the specified network profile is available.
Priority Read/write Gets or sets the priority level of the task.
RestartCount Read/write Gets or sets the number of times that the Task Scheduler will attempt to restart the task.
RestartInterval Read/write Gets or sets a value that specifies how long the Task Scheduler will attempt to restart the task.
RunOnlyIfIdle Read/write Gets or sets a Boolean value that indicates that the Task Scheduler will run the task only if the computer is in an idle state.
RunOnlyIfNetworkAvailable Read/write Gets or sets a Boolean value that indicates that the Task Scheduler will run the task only when a network is available.
StartWhenAvailable Read/write Gets or sets a Boolean value that indicates that the Task Scheduler can start the task at any time after its scheduled time has passed.
StopIfGoingOnBatteries Read/write Gets or sets a Boolean value that indicates that the task will be stopped if the computer begins to run on battery power.
WakeToRun Read/write Gets or sets a Boolean value that indicates that the Task Scheduler will wake the computer when it is time to run the task.
XmlText Read/write Gets or sets an XML-formatted definition of the task settings.

Several of these are more than scalar values so if you decide to use others check the documentation.  With the settings above we are explicitly saying that the task is enabled, not hidden, and that it can be run any time after the scheduled time if something would delay the execution.   One property that I know will come in handy later is the XmlText.

Create a time-based trigger

Tasks can be triggered in various ways other than being triggered at a certain time.  This really makes Windows Task Scheduler 2 stand out from previous versions and various others like cron.  We will take a look at these later.

To create a trigger we need to use the trigger collection from the newly created task.  This is because the factory for triggers is kept on the collection to simultaneously register the trigger as it constructs it. Before we take a look at the code, lets take a look at the TriggerCollection methods and properties:

TriggerCollection Methods:

Clear Clears all triggers from the collection.
Create Creates a new trigger for the task.
Remove Removes the specified trigger from the collection of triggers used by the task.

TriggerCollection Properties:

Count Read-only Gets the number of triggers in the collection.
Item Read-only Gets the specified trigger from the collection.

So here is how we would translate the example code to PHP:

define('TRIGGER_TYPE_TIME', 1);
$oTrigger = $oTaskDefinition->Triggers->Create(TRIGGER_TYPE_TIME);

The various trigger types are as follows:

TASK_TRIGGER_EVENT
0
Triggers the task when a specific event occurs.
TASK_TRIGGER_TIME
1
Triggers the task at a specific time of day.
TASK_TRIGGER_DAILY
2
Triggers the task on a daily schedule. For example, the task starts at a specific time every day, every-other day, every third day, and so on.
TASK_TRIGGER_WEEKLY
3
Triggers the task on a weekly schedule. For example, the task starts at 8:00 AM on a specific day every week or other week.
TASK_TRIGGER_MONTHLY
4
Triggers the task on a monthly schedule. For example, the task starts on specific days of specific months.
TASK_TRIGGER_MONTHLYDOW
5
Triggers the task on a monthly day-of-week schedule. For example, the task starts on a specific days of the week, weeks of the month, and months of the year.
TASK_TRIGGER_IDLE
6
Triggers the task when the computer goes into an idle state.
TASK_TRIGGER_REGISTRATION
7
Triggers the task when the task is registered.
TASK_TRIGGER_BOOT
8
Triggers the task when the computer boots.
TASK_TRIGGER_LOGON
9
Triggers the task when a specific user logs on.
TASK_TRIGGER_SESSION_STATE_CHANGE
11
Triggers the task when a specific session state changes.

Each trigger type yields a trigger object with properties specific to its type.  For more information on the trigger types, see the Trigger Types entry on MSDN.

Since we are creating a time trigger, we need to make sure the trigger time string is in the correct format.  In the example VBS has a XmlTime() function.  You should use your favorite date class, but for clarity we will just use the date function.
$iTime = time()+30;
$sStartTime = date('Y-m-d', $iTime).'T'.date('H:i:s', $iTime);
$iTime += (60*5);
$sEndTime = date('Y-m-d', $iTime).'T'.date('H:i:s', $iTime);

This will give us a start time 30seconds in the future and an end time five minutes later.  You can see that the time string will end up being something like "2009-05-30T14:12:46".

Now we can set these times on the trigger we created:

$oTrigger->StartBoundary = $sStartTime;
$oTrigger->EndBoundary = $sEndTime;
$oTrigger->ExecutionTimeLimit = "PT5M";   //Five minutes;
$oTrigger->Id = "TimeTriggerId";
$oTrigger->Enabled = true;

Above we set a five minute execution time limit.  According to MSDN this string is format is "PnYnMnDTnHnMnS" so P1M4DT2H5M specifies one month, four days, two hours, and five minutes.  Yes, we will be happy to not worry about that string later.  You will also notice the Id property which is a string that is used for logging, and then we explicitly enable this trigger with "Enabled = true".

Create an action for the task

For the purposes of this demonstration we have selected to run notepad.  However the 'IUSR' account is not allowed to interact with the logged in user.  So we will fire the task, but you will not get Notepad to popup on the server.  So this makes our example a informal demonstration of windows security.  Here is the code:

define('ACTION_TYPE_EXEC', 0);
$Action = $oTaskDefinition->Actions->Create(ACTION_TYPE_EXEC);
$Action->Path = "C:\\Windows\\System32\\notepad.exe";

Again the ActionCollection object holds the factory for the ActionObject.  The types of action objects that can be passed to the factory are as follows:

TASK_ACTION_EXEC
0
This action performs a command-line operation.
TASK_ACTION_COM_HANDLER
5
This action fires a handler.
TASK_ACTION_SEND_EMAIL
6
This action sends an e-mail.
TASK_ACTION_SHOW_MESSAGE
7
This action shows a message box.

After the action is created we set the path to the executable.  You can also specify the working directory as seen in the ExecAction Object Properties:

Arguments Read/write Gets or sets the arguments associated with the command-line operation.
Id Read/write Gets or sets the identifier of the action.
Path Read/write Gets or sets the path to an executable file.
Type Read-only Gets the type of the action.
WorkingDirectory Read/write Gets or sets the directory that contains either the executable file or the files that are used by the executable file.

Register The Task

As the final action we will register the task.  We will use a unique identifier for the task and set it to update or create new so that we keep things clean. As mentioned before we are going to simply let the task run under the 'IUSR' group account in this example so we will leave the username and password fields blank.  For some reason 'null' is not always recieved well by COM methods. To work arround this we make an empty Variant:

$empty = new VARIANT();

Then we use this in the registering of our task:

define('TASK_LOGON_GROUP', 4);
$oFolder->RegisterTaskDefinition('NotePad', $oTaskDefinition, TASK_CREATE_OR_UPDATE, $empty, $empty, TASK_LOGON_GROUP);

The Task Creation Flags can be any of the following:

TASK_VALIDATE_ONLY
1
The Task Scheduler checks the syntax of the XML that describes the task but does not register the task. This constant cannot be combined with the TASK_CREATE, TASK_UPDATE, or TASK_CREATE_OR_UPDATE values.
TASK_CREATE
2
The Task Scheduler registers the task as a new task.
TASK_UPDATE
4
The Task Scheduler registers the task as an updated version of an existing task. When a task with a registration trigger is updated, the task will execute after the update occurs.
TASK_CREATE_OR_UPDATE
6
The Task Scheduler either registers the task as a new task or as an updated version if the task already exists. Equivalent to TASK_CREATE | TASK_UPDATE.
TASK_DISABLE
8
The Task Scheduler disables the existing task.
TASK_DONT_ADD_PRINCIPAL_ACE
10
The Task Scheduler is prevented from adding the allow access-control entry (ACE) for the context principal. When the TaskFolder.RegisterTaskDefinition function is called with this flag to update a task, the Task Scheduler service does not add the ACE for the new context principal and does not remove the ACE from the old context principal.
TASK_IGNORE_REGISTRATION_TRIGGERS
20
The Task Scheduler creates the task, but ignores the registration triggers in the task. By ignoring the registration triggers, the task will not execute when it is registered unless a time-based trigger causes it to execute on registration.

The Login Type parameters can be any of the following:

TASK_LOGON_NONE
0
The logon method is not specified. Used for non-NT credentials.
TASK_LOGON_PASSWORD
1
Use a password for logging on the user. The password must be supplied at registration time.
TASK_LOGON_S4U
2
Use an existing interactive token to run a task. The user must log on using a service for user (S4U) logon. When an S4U logon is used, no password is stored by the system and there is no access to either the network or to encrypted files.
TASK_LOGON_INTERACTIVE_TOKEN
3
User must already be logged on. The task will be run only in an existing interactive session.
TASK_LOGON_GROUP
4
Group activation. The groupId field specifies the group.
TASK_LOGON_SERVICE_ACCOUNT
5
Indicates that a Local System, Local Service, or Network Service account is being used as a security context to run the task.
TASK_LOGON_INTERACTIVE_TOKEN_OR_PASSWORD
6
First use the interactive token. If the user is not logged on (no interactive token is available), then the password is used. The password must be specified when a task is registered. This flag is not recommended for new tasks because it is less reliable than TASK_LOGON_PASSWORD.

Run it and check your task scheduler for the listing. You should see something like Figure 1.

Figure 1

Figure 1

Conclusion

Hopefully through this tutorial you have seen that COM components expose some very useful Windows components.  MSDN is the authoritative resource for what is available by default through COM.  Many of the VBS examples can be translated directly into PHP using the COM classes. As I perfect Dante and the Crossley Framework Scheduler and Com wrappers I will post tutorials for using them, so keep watching here.

27
May
09

Installing SVN Server on Windows

What is the easiest way to install a SVN Server on Windows?  Point your browser at Visual SVN Server, download the installer and install.  Is it that simple?  Here is how it goes:

Welcome

Welcome

Here is the important part:

Configuration / Setup

Configuration / Setup

Authentication is important.  Subversion authentication is easy to manage, but segregates SVN from the server.  Using Windows authentication has great potential for being scalable and relieving the need to manage authentication in more than one place.

Installing

Installing

So the install was dirt simple right?  SVN as a whole is just that simple. But having a nice GUI can sometimes help.  What I hate is setting up a server and then every time I get back to fix something or change something I have to read all the docs again.  So for those things a GUI is nice.  The VisualSVN server has a nice one, even if you are accustomed to VSS.

VisualSVN

VisualSVN

I like the ‘Create default structure’ option.  It allows for the creation of the standard subfolders with a single click.  You will also notice that it gives you your URL and is using HTTPS.  So what are you waiting for, use a version control system already!

VisualSVN_Hooks

Also once, you have the system installed righ-click your repo and check out what is under ‘All Tasks’.  I like the ‘Manage Hooks’ option. This gives you direct acess to the pre and post-commit hooks, as well as the others.  Overall this package is a nice addition to my development stack.

Do you use a different VCS on windows?  What do you like about it? I would be interested in seeign other options.

18
May
09

Displaying Windows Task Scheduler Tasks with PHP

In building Dante, my task scheduler application, I have come across quite a bit of information about dealing with COM through PHP.  Once I gained a simple understanding of the COM system in PHP I learned the rest from Win32 and COM Development on MSDN.  I hope to share a bit of what I have learned.  The focus of Dante will be on Windows first. Later I want to be able to support UNIX systems too, so I will keep that in mind as I build my class. As I never have enjoyed VBS so implementing it in PHP will make for a much more enjoyable experience scripting.  My intention is to take everything I work on and bringing it into my framework.  Hopefully you find this information helpful, or if you just want to use this functionality check out the Crossley Framework.  Dante PHP Job Scheduler will have a project page soon, so stay tuned.

So the first piece of Dante that will always be important is displaying the tasks that are scheduled to run.  A Factory method is used with COM objects in PHP or VBS.  As discussed earlier, it is called COM() in PHP.  A quick trip over to the Task Scheduler MSDN refrence tells us there are four high-level steps we need to take.

  1. Create a TaskService object (using COM())
  2. Get a task folder (tasks are organized into a directory tree)
  3. Get the collection of tasks from that folder
  4. Count, Iterate and perform any other operations on the tasks.

These are mostly obvious.  So the first thing I need to do is checkout the TaskService object.  This will be the means for managing registered tasks.  From the documentation you can see that the TaskService object has a limited number of methods: Connect(), NewTask(), GetFolder() and GetRunningTasks().  My goal  will be to completely obfusticate the functionality passing these calls onto the instance.

On the simplest level I want to be able to call my class like this:

$oTaskService = new X_Scheduler_Win_Service();
$aTasks = $oTaskService->getTasks();
print "<ul>";
foreach ($aTasks as $oTask)
{
print "<li><b>{$oTask->sName}</b>
print "{$oTask->sPath} : {$oTask->sNextRunTime}</li>"
}
print "</ul>";

I will try to place all the connect logic in the constructor.  I will allow for D-COM pass through, but I am not going to be worried about making it work this go arround.   If you decide to experiment with it, you should know that it needs to be enabled in your php.ini.  D-COM basically allows you to connect to a different server to run COM.

One of your best friends is com_print_typeinfo().  However it can leave you high and dry if the COM object doesn’t support the introspection from com_print_typeinfo().  Sadly this seems to be the case with ‘IRegisteredTaskCollection’.  In this case you just have to trust the MSDN documentation.  If I had one wish for PHP on Windows it would be that this function be improved.  The other qualm I have is that it outputs directly and does not return a string.  I think it should at least have the option like print_r().

So lets take the first step and get a count of tasks.

$oSchedule = new COM("Schedule.Service");
$oSchedule->Connect();
$oFolder = $oSchedule->GetFolder("\");
$oCollection = $oFolder->GetTasks(0);
print "Count: " . $oCollection->Count . "n";

The first two lines you will see repeated constantly when dealing with COM.  We are basically getting an instance of the TaskService object and connecting to the running service.

Then, since the schedule is organized in a directory tree style folder structure we need to get the folder we are going to deal with.  Here we get the root folder, but later we will get organized into our own folder.  Just like dealing with the file syste, tasks concealed within folders are not visible from the parent folder.  The TaskService object also offers the following methods and properties:

TaskService methods:

GetFolder Gets the path to a folder of registered tasks.
GetRunningTasks Gets a collection of running tasks.
Connect Connects to a remote machine and associates all subsequent calls on this interface with a remote session.
NewTask Returns an empty task definition object to be filled in with settings and properties and then registered using the RegisterTaskDefinition method.

TaskService properties:

Connected Read-only Gets a Boolean value that indicates if you are connected to the Task Scheduler service.
ConnectedDomain Read-only Gets the name of the domain to which the TargetServer computer is connected.
ConnectedUser Read-only Gets the name of the user that is connected to the Task Scheduler service.
HighestVersion Read-only Gets the highest version of Task Scheduler that a computer supports.
TargetServer Read-only Gets the name of the computer that is running the Task Scheduler service that the user is connected to.

The parameter passed to GetTasks() signifies what type of tasks to list. To list all the normal tasks we pass ‘0′ (zero).  We can list hidden tasks by passing ‘1′.

Once we have a collection we can get the count from the ‘Count’ attribute.

The next step I want to take is to turn the collection into a native PHP array.  At this point it is good to take note that the first item in this collection is not 0 as with normal PHP arrays.  The first item is thus ‘1′.  Taking this into consideration we form a for loop:

$aTasks = array();
for ($i = 1; $i <= $iCollectionCount; $i++)
{
$aTasks[] = $oCollection ->Item($i);
}

The collection is also iterable in a foreach loop:

$aTasks = array();
foreach ($oTaskCollection as $oItem)
{
$aTasks[] = $oItem;
}

You may ask why I am adding a loop if it is already iterable.  The plan here is to end up with a totally native concrete object.  There may be a way to cast returned objects to PHP classes, but we will save that for later

Now lets take a look at the RegisteredTask object.  One property that seems to have great potential is ‘XML’.  Here are the RegisteredTask Properties:

Definition Read-only Gets the definition of the task.
Enabled Read/write Gets or set a Boolean value that indicates if the registered task is enabled.
LastRunTime Read-only Gets the time the registered task was last run.
LastTaskResult Read-only Gets the results that were returned the last time the registered task was run.
Name Read-only Gets the name of the registered task.
NextRunTime Read-only Gets the time when the registered task is next scheduled to run.
NumberOfMissedRuns Read-only Gets the number of times the registered task has missed a scheduled run.
Path Read-only Gets the path to where the registered task is stored.
State Read-only Gets the operational state of the registered task.
XML Read-only Gets the XML-formatted registration information for the registered task.

Notice that all the properties we mentioned before are present.  Observing the methods of this object we see everything we may ever want to do with a task:

GetInstances Returns all instances of the registered task that are currently running.
GetSecurityDescriptor Gets the security descriptor that is used as credentials for the registered task.
GetRunTimes Gets the times that the registered task is scheduled to run during a specified time.
SetSecurityDescriptor Sets the security descriptor that is used as credentials for the registered task.
RunEx Runs the registered task immediately using specified flags and a session identifier.
Stop Stops the registered task immediately.
Run Runs the registered task immediately.

In building  my class, the instanciation and connection is done in the constructor with the option to pass through the additional options.  The TaskService object also offers a connect in addition to the COM connect methods.  This allows us to use additional user credentials without going the D-COM route.  Thus, I will create a method to neatly take advantage of reconnecting with a different username and password.  Then I will stub out a Task class that we will later use for convience methods.

Next: Scheduling a Task in Windows Task Scheudler with PHP

11
May
09

Read The Windows Registry in Two Lines of PHP

This came to me via. tek-tips. Here is how to use PHP to find the path to Firefox.


$shell = new COM("WScript.Shell") or die("Requires Windows Scripting Host");
$devenvpath=$shell->RegRead("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App\\Pathsfirefox.exe");

Happy automation.




 

November 2009
M T W T F S S
« Oct    
 1
2345678
9101112131415
16171819202122
23242526272829
30  

code snob



Bookmark and Share

Top Posts

  • None