Thursday, March 21, 2013

Why Python Needs Perl's use strict

Having been playing with Python again after a couple of years away from it I had a good bunch of people to teach it too, and they had some good questions.  One of which came up during exceptions.

Now we all know that Python allows you to create variables on the fly and to declare them you must assign to them first;
myvar="hello world"

But imagine the following scenario where you have declared your variable such as a file handle to open a file, but you have used an exception to capture the fact that the file does not exist and in your except section have a typo for the file handle object.



try:
        fh=open("usestrict")
        for x in fh:
                print x,"\n"
except IOError:
        print "File could not be opened"
        ofh.close()

ofh.close()



So the Python Guy had a post at the following;
http://pythonguy.wordpress.com/2008/09/18/perl-really-sucks-and-they-dont-even-realize-it/

Well, clearly from the above code I would not get a compile error and my exception would happen and even if I didn't get the exception my my code would run and when it came to closing the file I'd get a NameError exception from Python.

Are you sure Python doesn't need a use strict?  Are Python developers that confident that they don't make typos?

Thursday, September 20, 2012

Listing all hosts in Active Directory using PowerShell

PowerShell is now a mature scripting language. I've enjoyed watching it flourish from it's early conception and the many ways in which people were convinced that it was better than Perl, or the Unix KornShell.  Well for Windows that is definitely the case as it puts the operating system in the league of serious enterprise systems especially now Server Core comes with the .Net framework and PowerShell making the command line offering more attractive than it's earlier attempt.  There are some great features that PowerShell provides which make it an enterprise suitable automation language, such as the ability to interact with WMI for remote and local host manipulation and ADSI for automating your Active Directory tasks.  Why would you want to click another mouse button, apart from to launch your PowerShell script to update 1000s of hosts, or change a particular aspect of all 5 million users in your enterpirse?  Clicking is for wimps, that's those of you who still like Windows Icons Menus and Pointers :-)

One thing I found great the other day was how simple and easy it is to get a list of all the properties from your hosts registered in Active Directory in so few lines;

$DirSearcher = New-Object System.DirectoryServices.DirectorySearcher([adsi]'LDAP://CN=Computers,DC=xx,DC=xxxx')


foreach ($hostObject in $DirSearcher.FindAll())
{
        echo $hostObject.Properties;    # Will list all hosts and their AD properties
        # echo $hostObject.Properties.name; # List just the hostname, dnshostname for FQDN name
}

If you simply want to grab a particular object from the directory you only need do the following;
$AD=[adsi]’LDAP://CN=xxxx,OU=xxxx,OU=xxx,DC=xxxx,DC=xxxx’
$AD.Properties


Couldn't be simpler.  And as long as the object has methods you can perform various actions to update values and more.

Tuesday, October 4, 2011

Ajax - Reminder for me - Multiple calls

This is more a reminder for me, rather than a useful post.

The ability to call different backend programs and have live updates into divs on a page, and here is the code that does it and works on Windows, Firefox and Google Chrome.


<html>
<head>
<style>
#time { position: absolute; top: 100px; left: 10px; border-left: 2px solid grey; border-bottom: 2px solid black; width: 200px; height: 200px }
#blob { position: absolute; top: 100px; left: 300px; border-left: 2px solid gray; border-bottom: 2px solid black; width: 200px; height: 200px }
</style>
</head>


<script type="text/javascript">
function ajaxFunction(myURL,myDIV)
{
var xmlHttp;
try
{
// Firefox, Opera 8.0+, Safari, Chrome
xmlHttp=new XMLHttpRequest();
}
catch (e)
{
// Internet Explorer 2 versions, capture both
try
{
xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e)
{
alert("Your browser does not support AJAX!");
return false;
}
}
}
xmlHttp.onreadystatechange=function()
{
if(xmlHttp.readyState==4)
{
document.getElementById(myDIV).innerHTML=xmlHttp.responseText;
}
}
xmlHttp.open("GET",myURL,true);
xmlHttp.send(null);
}
</script>
<body>
<form name="myForm">
<p>Magic updating data, go edit the file
<div id=time></div>
<div id=blob></div>
</form>
<script>setInterval("ajaxFunction('cgi-bin/time.pl','time')",5000);</script>
<script>setInterval("ajaxFunction('cgi-bin/stuff.pl','blob')",5000);</script>
</body>
</html>

Sunday, October 2, 2011

Perl DBI and Sybase IMAGE fields

Sybase IMAGE fields and TEXT fields can be a right pain when working with Perl and the ct_ libraries. The manual pages are a little rough and don't give full examples, often missing out essential parts. So here it is in one section.

NOTE: Your LANG variable must be unset!

I noticed whilst identifying the issue for them that Sybase will allow dumps up to a certain size, e.g. the /etc/passwd file would quite happily fit into an IMAGE field if you use the following;


use strict;
use DBI;

# Open the connection to the database
my $dbh=DBI->connect('dbi:Sybase:server=STEVE;database=test','sa','') || die "Can't connect";

sub Insert
{
# Insert data
open(FH,"/etc/passwd");
local $/; # Slurp mode to suck in the file into one scalar
my $filename=<FH>; # read in the data
$/=1; # Return to normal newline mode
close FH;
$filename=unpack("H*",$filename); # Hex convert the entire file
my $length=length($filename);
$dbh->do("INSERT INTO data VALUES(4,'$filename')"); # Note the single quotes '
print "Insert done\n";
}

sub GetData
{
# Get data
my $sth=$dbh->prepare("SELECT * from data where id=4");
$sth->execute();
open(OFH, ">mytcap"); my $line;
while ( $line = $sth->fetchrow_hashref() )
{
my $data=$line->{'file'};
$data=pack('H*',$data); # Unpack the hex data
while ( $data =~ /(.{2})/g ) # Take each 2 characters from the hex code
{
print chr(hex($1)); # Turn the hex back into text
}
}
close(OFH);
$sth->finish();
}

Insert();
GetData();
$dbh->disconnect();

However, if the data became larger, e.g. the /etc/httpd/conf/httpd.conf file then you would start to see complaints from Sybase saying that the maximum size is only 30. That is, it can't move the point to the next available page size for the IMAGE. Which lead to the need for the ct_ functions as below;

use strict;
use DBI;

my $dbh=DBI->connect('dbi:Sybase:server=STEVE;database=test','sa','') || die "Can't connect";

sub Insert
{
# Insert data
$dbh->do("INSERT INTO data VALUES(4,'0xab')"); # Put some rubbish in the IMAGE field
}

sub Update
{
my $size = -s '/etc/httpd/conf/httpd.conf'; # Open a large file
open(FH,"/etc/httpd/conf/httpd.conf");
local $/;
my $filename=<FH>;
$/=1;
close FH;
$filename=unpack("H*",$filename); # Convert it to hex

my $sth=$dbh->prepare("select file from data where id=4"); # Grab the inserted new row
$sth->execute();
while($sth->fetch) # Fetch an array reference
{
$sth->syb_ct_data_info('CS_GET',1); # Set the pointer
}
$sth->syb_ct_prepare_send();
# Tell Sybase how much data we plan to send and turn the log on
$sth->syb_ct_data_info('CS_SET',1, {total_txtlen => length($filename), log_on_update => 1});
$sth->syb_ct_send_data($filename, length($filename)); # Send the data
$sth->syb_ct_finish_send();
}

sub GetData
{
# Get data
my $data;
my $sth=$dbh->prepare("SELECT datalength(file) AS len from data where id=4");
$sth->execute();
my $length=${$sth->fetchrow_hashref()}{'len'},"\n"; # Get the length of the IMAGE data
$sth->finish();
$dbh->{LongReadLen}=$length+1; # Tell Sybase how much data we plan to fetch

$sth=$dbh->prepare("SELECT id,file from data where id=4"); # What record do we want
$sth->{syb_no_bind_blob}=1; # Tell Sybase we are fetching binary
$sth->execute();
my ($len,$d);
while ( $d = $sth->fetch ) # Get array ref of data
{
$len = $sth->syb_ct_get_data(2,\$data,0); # Fetch all the data, $len contains number of bytes
# NOTE: \$data is the reference that will capture the data
while ( $data =~ /(.{2})/g ) # Do our favourite conversion on the returned data
{
print chr(hex($1)); # Print out the converted characters
}
}
$sth->finish();
}

Insert();
Update();
GetData();
$dbh->disconnect();

Note that with these examples I use Perl's unpack function to place the data into hex form before inserting it into the database, so that no quote or special character conversions are required. On retrieving the data I make use of the chr and hex functions to convert every 2 hex values into their decimal number and then chr to get the real character.

Saturday, October 30, 2010

Perl action indicator using Term::Cap

If you are wondering how to make one of those whirling "I'm doing something" indicator on a screen in Perl, here is some code that will get you going. There are many libraries out there, but for those of you in companies where they won't let you use just any old CPAN library, here is a Termcap version which is standard with all Unix/Linux distributions of Perl.

use Term::Cap;
use POSIX;

# Load terminal IO library
my $termios = new POSIX::Termios;
# Get terminal settings
$termios->getattr;
# Get terminal speed
my $ospeed = $termios->getospeed;

$|=1;
$terminal = Tgetent Term::Cap { TERM => undef, OSPEED => $ospeed };
$terminal->Trequire(qw/ce ku kd/);

# Array for spinning thingy
my @seq=qw(| / - | \ -);
my $count=0;

# Position on the screen left to right (0 being left of screen)
my $x = 0;
# Position on the screen top to bottom (0 being top of screen)
my $y = 10;

while (1)
{
$terminal->Tputs('cl',1,*STDOUT); # Clear screen
$terminal->Tputs('cd',1,*STDOUT); # Clear data

# Set cursor position on screen
$terminal->Tgoto('cm',$x,$y,*STDOUT);
# Print one of the chars | / - \
print "$seq[$count++]";
sleep 1;
if ( $count > 5 )
{
$count = 0;
}
}

Friday, October 29, 2010

Interactive Password on Console app with C#

If you've ever used C# for application development and needed to get a password into your program but don't want to display it to the screen, you'll realise that you will need to use some COM objects and kernel functionality.
This simple example provides you with a template to get the password from a user without displaying on the screen what they typed, and also accepting the backspace key when they press it.
The code;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace FirstOne
{
class Program
{
// Get the kernel function for setting console modes
[System.Runtime.InteropServices.DllImport("kernel32 ")]
private static extern int SetConsoleMode(IntPtr hConsoleHandle, int dwMode);
// Get the kernel function for getting console modes
[System.Runtime.InteropServices.DllImport("kernel32 ")]
private static extern int GetConsoleMode(IntPtr hConsoleHandle, ref int dwMode);

// Some useful constants for the console values
private const int ENABLE_LINE_INPUT = 2;
private const int ENABLE_ECHO_INPUT = 4;
// Standard input file handle
private const int CONIN = 3;

// Ensure that our process is single threaded as we as using COM and need to ensure communication
[STAThread]
static void Main(string[] args)
{
IntPtr hStdIn = new IntPtr(CONIN);
int myMode=0;
char inputChar;
string password = "";
Console.Write("Password: ");
// Get the current console settings
GetConsoleMode(hStdIn, ref myMode);
// Turn off echo
myMode = (myMode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
SetConsoleMode(hStdIn, myMode);

do
{
inputChar = (char)Console.Read();
if (inputChar == '\b') // Can also use 8 instead of '\b'
{
// Delete character if user has pressed backspace
password=password.Remove(password.Length-1);
}
if (inputChar >= 32)
{
// Store password characters
password += inputChar;
}
} while (inputChar != '\r');

// Reset terminal echo
myMode = (myMode | (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
SetConsoleMode(hStdIn, myMode);
Console.WriteLine("");
Console.WriteLine("Password was: {0}", password);
}
}
}

Tracing a Web Reference

  1. First you will need SvcTraceViewer.exe which should be some where similar to;
    C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\SvcTraceViewer.exe
  2. Add your Web Reference to the project and code as normal
  3. To trace the service you will need to modify your app.Config file
The essential parts required to get a trace that can be viewed with SvcTraceViewer are;
  • <diagnostics> section which should be added after the <system.servicemodel> tag and before the <bindings> tag

<diagnostics>messagelogging logentiremessage="true"
logmalformedmessages="true" logmessagesatservicelevel="true"
logmessagesattransportlevel="true" maxmessagestolog="100"
maxsizeofmessagetolog="10000000"</diagnostics>

  • After the </system.serviceModel> tag you should then add the following <system.Diagnostics> section

<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Information,ActivityTracing" propagateActivity="true">
<listeners>
<add name="xml" />
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging" switchValue="All" propagateActivity="true">
<listeners>
<add name="xml" />
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="c:\abc.svclog" type="System.Diagnostics.XmlWriterTraceListener" name="xml" />
</sharedListeners>
<trace autoflush="true" />
</system.diagnostics>

  • Run your application and then locate your c:\abc.svclog file
  • Note that you should name and locate the initializeData attribute in a sensible location and a meaning full name.