Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Page 1 of 3 123 LastLast
Results 1 to 15 of 33
  1. #1
    New Coder
    Join Date
    Nov 2011
    Location
    Detroit
    Posts
    19
    Thanks
    2
    Thanked 0 Times in 0 Posts

    Need help modifying a file for application license assignments

    Hello all--

    I don't have a lot of Perl experience, so any help would be appreciated!

    Here's what I'm trying to do:
    We use an application called MirrorFolder to back up our laptops. We have a text file with machine names and the corresponding licese code for that machine:
    myMachine getsThisCode
    yourMachine getsThisOtherCode
    hisMachine ohLookAnotherCode
    ...

    In the file we have some codes that are available for use, like this:
    unassigned someOtherCode

    Now, the unassigned codes are mixed in with the assigned codes:
    myMachine getsThisCode
    unassigned someOtherCode <--the available license
    yourMachine getsThisOtherCode
    hisMachine ohLookAnotherCode

    We use MS Depolyment Toolkit to install the OS and applications (we have about 8 different loads for different job functions). When a laptop is deployed MDT installs MirrorFolder.

    The machine that's being deployed needs to be in the license file or the installation fails.

    In orer to streamline things, I'm trying to get a script going that will run before MirrorFolder is installed and assign a license for that machine.

    The way my script runs now, the code is appended to the list while leaving the available code in the file. Ideally, it should replace the word 'unassigned' with the machine name.

    How it is now:
    myMachine getsThisCode
    unassigned someOtherCode <--the available license
    yourMachine getsThisOtherCode
    deployMe someOtherCode <--the available license appended

    How it should be:
    myMachine getsThisCode
    deployMe someOtherCode <--the available license correctly assigned (the word 'unassigned' replaced with the machine name)
    yourMachine getsThisOtherCode

    After all that, here's my code:

    Code:
    #!/usr/bin/perl
    
    $strSearchFor = "unassigned";
    $setCount = 0;
    $file = "k:/MirrorFolder4.1/testlicense.txt";
    $backupFile = "k:/MirrorFolder4.1/testlicense.bak";
    
    #make a backup of the license file just in case
    open (LICENSE, "+<$file" ) or die "Cannot open file."; #open the license.txt file
    open (LICENSE_BAK, ">$backupFile") or die "Cannot open file"; #open the license.bak file 
    
    @lfile = <LICENSE>;
    
    foreach $backupline (@lfile){
    print LICENSE_BAK ($backupline);
    }
    close (LICENSE);
    close (LICENSE_BAK);
    undef (@lfile);
    
    #re-open the license.txt file to make the changes
    open (LICENSE, "+<$file" ) or die "Cannot open file.";
    foreach $line (<LICENSE>){
    	while ($setCount == 0){
    	#print ($line);
    		if ($line =~ m/$strSearchFor/){
    			print ($line);
    			$line =~ s/$strSearchFor/$ENV{'ComputerName'}/i;
    			$setCount = 1;
    			#print ($setCount);
    			print LICENSE ($line);
    		}	
    	}
     }
    Thanks for sticking it out to the end of the post
    Any help would be great!

    Thanks,
    Joe
    Last edited by FishMonger; 11-07-2011 at 09:01 PM.

  • #2
    Super Moderator
    Join Date
    May 2005
    Location
    Southern tip of Silicon Valley
    Posts
    2,953
    Thanks
    2
    Thanked 172 Times in 167 Posts
    First, use File::Copy to create the backup file and I'd include a timestamp as part of the filename to maintain a history.

    Load your text file into a hash or a HoA (hash of arrays) or a HoH (hash of hashes) where the keys are the hostnames and the values are the licenses. This will make it very easy to separate the assigned and unassigned licenses. Then take one of the unassigned licenses and move it to the assigned group. Then sort the hash and output its data to the file.

    Your substitution regex is using $ENV{'ComputerName'} and implies that the script will be run on the laptop instead of the deployment server, which doesn't make sense. Where is the laptop hostname coming from?

  • #3
    New Coder
    Join Date
    Nov 2011
    Location
    Detroit
    Posts
    19
    Thanks
    2
    Thanked 0 Times in 0 Posts
    Hi FishMonger, thanks for the hints. Now I get to learn how to use hashes (which is not a bad thing at all).

    The script will be called via another script (script-ception? sorry ) that will run on the laptop. The machine name is determined very early in the deployment process (one of the first few steps after OS installation)

    In the build process, MirrorFolder is installed towards the end (there are some dependencies and a lot of CAD and design software that are more important, so they get installed first)

    Oh, and thanks for cleaning up my post... I typed it out once in the editor, then lost it so I re-did it in Notepad++ and copied it, so the CODE tags I put in didn't do much.

  • #4
    New Coder
    Join Date
    Nov 2011
    Location
    Detroit
    Posts
    19
    Thanks
    2
    Thanked 0 Times in 0 Posts
    OK.. I tried, but my head is about to explode....

    I can't get past the ...while... statement:

    Code:
    #!/usr/bin/perl
    use File::Copy;
    
    $strSearchFor = "unassigned";
    $setCount = 0;
    $file = "k:/Packages/Packages/MirrorFolder4.1/testlicense.txt";
    $backupFile = "k:/Packages/Packages/MirrorFolder4.1/testlicense.txt.bak";
    $newFile = "k:/Packages/Packages/MirrorFolder4.1/testlicensetext.txt.";
    copy($file,$backupFile) or die "copy failed: $!";
    
    open (LICENSE, "+<$file" ) or die "Cannot open file.";
    my %hash;
    while (<LICENSE>){
    my ($key, $val) = split /" "/;
    $hash{$key} .= exists $hash{$key} ? "$val" : $val;
    }
    print "hash done...";
    $_ = <STDIN>;
    foreach $key (%hash){
    	print "foreach...";
    	$_ = <STDIN>;
    	while($setCount == 0){
    	print "while...";
    	$_ = <STDIN>;
    		if ($key{%hash} =~ m/$strSearchFor/){
    			print "found it...";
    			$_ = <STDIN>;
    			$key =~ s/$strSearchFor/$ENV{'ComputerName'}/i;
    			print "substitued...";
    			$_ = <STDIN>;
    			$setCount = 1;
    			print "setcount 1...";
    			$_ = <STDIN>;
    			open (NEWLICENSE, ">$newFile") or die "sorry.";
    			#print ($setCount);
    			print NEWLICENSE (%hash);
    			close (NEWLICENSE);
    		}	
    	}
    }
    close (LICENSE);

    I added some prints and <STDIN>s to see where I was in the code, and I can get to 'print "while..."; ' and the script 'sticks' so to speak. It seems like the 'if...' loop never gets evaluated...

    I'm very stuck. Any ideas?

    Please?

    Don't make me get on my knees... It'll help with banging my head on my desk, but still...
    Last edited by joeDetroit; 11-12-2011 at 05:12 AM.

  • #5
    New Coder
    Join Date
    Nov 2011
    Location
    Detroit
    Posts
    19
    Thanks
    2
    Thanked 0 Times in 0 Posts
    I would like to say, even though I'm at a stumbling block, I've learned a lot based on your reply...

    Thanks!
    Last edited by joeDetroit; 11-12-2011 at 05:14 AM.

  • #6
    Super Moderator
    Join Date
    May 2005
    Location
    Southern tip of Silicon Valley
    Posts
    2,953
    Thanks
    2
    Thanked 172 Times in 167 Posts
    There are a number of issues I could point out, but the main issue to fix to get you rolling is your loop initialization.

    change:
    Code:
    foreach $key (%hash){
    to:
    Code:
    foreach $key (keys %hash){

  • #7
    New Coder
    Join Date
    Nov 2011
    Location
    Detroit
    Posts
    19
    Thanks
    2
    Thanked 0 Times in 0 Posts
    Quote Originally Posted by FishMonger View Post
    There are a number of issues I could point out
    By all means, please point them out!

    As I said, I'm new to perl and I'm happy to learn more.

    I'm going to try your change now.

    THANK YOU for your help!

  • #8
    New Coder
    Join Date
    Nov 2011
    Location
    Detroit
    Posts
    19
    Thanks
    2
    Thanked 0 Times in 0 Posts
    I think I've figured out the major problem- The my ($key, $val) = split; isn't splitting the data in the file into 2 columns, i.e. the $key has the machine name and the license, and the $val is empty.

    I decide to try to break it down into smaller chunks to see where I was going wrong, so I did this:

    Code:
    #!/usr/bin/perl
    use File::Copy;
    
    $strSearchFor = "UNASSIGNED";
    $setCount = 0;
    $file = "k:/Packages/Packages/MirrorFolder4.1/testlicense.txt";
    $backupFile = "k:/Packages/Packages/MirrorFolder4.1/testlicense.txt.bak";
    
    copy($file,$backupFile) or die "copy failed: $!";
    
    #open the license.txt file to make the changes
    open (LICENSE, "+<$file" ) or die "Cannot open file.";
    my %hash;
    while (<LICENSE>){
    my ($key, $val) = split /" "/;
    $hash{$key} .= exists $hash{$key} ? "$val" : $val;
    }
    
    close (LICENSE);
    
    print "hash done, file closed...";
    $_ = <STDIN>;
    
    
    foreach $key (sort keys %hash){
    	print "key- " . $key . "value- " . $val . "\n";}
    What I get is this:
    key- myMachine getsThisCode value-
    key- yourMachine getsThisOtherCode value-
    key- hisMachine ohLookAnotherCode value-

    I tried split, split /\s+/, and split /"" ""/.

    Thoughts?

    Thanks,
    Joe

  • #9
    New Coder
    Join Date
    Nov 2011
    Location
    Detroit
    Posts
    19
    Thanks
    2
    Thanked 0 Times in 0 Posts
    I just tried split /' '/ and split /"' '"/ (double quoted single quotes) with same result- an empty $val.

    I also threw in use warnings; and got
    Use of uninitialized value $val in concatenation (.) or string at k:/Packages/Packages/MirrorFolder4.1/test.pl line 42.

    $val is (I thought) declared here:
    my ($key, $val)

  • #10
    Super Moderator
    Join Date
    May 2005
    Location
    Southern tip of Silicon Valley
    Posts
    2,953
    Thanks
    2
    Thanked 172 Times in 167 Posts
    Since you haven't posted a sample of the file you're parsing or given a clear and accurate description of its format, it's impossible for us to say why your parsing is failing.

    Start by adding these 2 pragmas (which should be in every Perl script you write) and do the best you can on fixing the problems that they point out.
    Code:
    use strict;
    use warnings;
    Then post your script and a sample of the file that you're parsing and the errors and warnings that your script generates.

  • #11
    New Coder
    Join Date
    Nov 2011
    Location
    Detroit
    Posts
    19
    Thanks
    2
    Thanked 0 Times in 0 Posts
    Since the file in question has license keys, I cannot (and will not) post it.

    I did say in the first post that the file has machine names and keys separated by a space:
    Code:
    myMachine myLicense
    yourMachine yourLicense
    I also said in my last post that I put in use warnings and got the following:
    Use of uninitialized value $val in concatenation (.) or string at k:/Packages/Packages/MirrorFolder4.1/test.pl line 42.

    This is the part of the script that seems to be failing, specifically the my ($key, $val) = split /" "/; line:

    Code:
    #open the license.txt file to make the changes
    open (LICENSE, "+<$file" ) or die "Cannot open file.";
    my %hash;
    while (<LICENSE>){
    my ($key, $val) = split /" "/;
    $hash{$key} .= exists $hash{$key} ? "$val" : $val;
    }

    I know I should be using strict and warnings. I left them out initially since I was using perl -w to run the script, which generates warnings.

    Thanks,
    Joe

  • #12
    Super Moderator
    Join Date
    May 2005
    Location
    Southern tip of Silicon Valley
    Posts
    2,953
    Thanks
    2
    Thanked 172 Times in 167 Posts
    You can obfuscate the license keys in the post. The important factor is knowing the exact format of the line, which you have not made clear.

    Are the fields separated by a single space and nothing else?

    Are the fields separated by a single quote then a space and then a closing single quote?

    Are the fields separated by a double quote then a space and then a closing double quote?

    Are the fields separated by a double quote then a single quote then a space then a single quote and then finally a closing double quote?

    Your posts so far indicate that it could be any one of those or none at all.

    This statement isn't doing what you think.
    Code:
    $hash{$key} .= exists $hash{$key} ? "$val" : $val;
    That's more cleanly written as:
    Code:
    $hash{$key} .= $val;
    or if the concatenation isn't needed (i.e., if each hostname only appears once):
    Code:
    $hash{$key} = $val;
    If a hostname appears more than once and/or has multiple license keys, then you should use a hash-of-arrays.

    You should be using the 3 arg form of open and a lexical var for the filehandle. The die statement should include what you're trying to open and the reason it failed.

    Instead of implicitly using $_ in the while loop, you should be using a named var and you should chomp the line to remove the line terminator.

  • #13
    Super Moderator
    Join Date
    May 2005
    Location
    Southern tip of Silicon Valley
    Posts
    2,953
    Thanks
    2
    Thanked 172 Times in 167 Posts
    Try this:

    Code:
    #!/usr/bin/perl
    
    use warnings;
    use strict;
    use File::Copy;
    use Data::Dumper;
    
    my $path   = 'k:/MirrorFolder4.1';
    my $file   = "$path/testlicense.txt";
    my $backup = "$path/testlicense.bak";
    my %licenses;
    
    #make a backup of the license file just in case
    #copy($file, $backup) or die "failed to copy '$file' to '$backup' $!";
    
    open my $license_fh, '<', $file or die "failed to open '$file' $!";
    
    LICENSE:
    while ( my $line = <$license_fh> ) {
        chomp $line;
        next LICENSE if $line =~ /^\s*$/;
        
        # this will need to be adjusted depending on your actual field separator
        my ($hostname, $license) = split / /, $line, 2;
        unless ($hostname and $license) {
            print Dumper $line;
            next LICENSE;
        }
        push @{ $licenses{$hostname} }, $license;
    }
    
    print Dumper \%licenses;

  • Users who have thanked FishMonger for this post:

    joeDetroit (11-17-2011)

  • #14
    New Coder
    Join Date
    Nov 2011
    Location
    Detroit
    Posts
    19
    Thanks
    2
    Thanked 0 Times in 0 Posts
    Quote Originally Posted by FishMonger View Post
    You can obfuscate the license keys in the post. The important factor is knowing the exact format of the line, which you have not made clear.

    Are the fields separated by a single space and nothing else?
    Yes, the machine name and license are separated with a single space, one machine/license key per line. As these are site licenses, there may be more than one machine assigned the same license key:

    Code:
    WPDONCND130CJ57 1111-1111-1111-1111
    WPDONCND130CJ58 2222-2222-2222-2222
    UNASSIGNED 1111-1111-1111-1111
    UNASSIGNED 1111-1111-1111-1111
    WPDONCND130CJ5C 2222-2222-2222-2222
    If a hostname appears more than once and/or has multiple license keys, then you should use a hash-of-arrays.
    Each hostname is in the file one time, however each key may appear many times.

    You should be using the 3 arg form of open and a lexical var for the filehandle. The die statement should include what you're trying to open and the reason it failed.
    Is there a performance benefit to this? I see the point (especially the 'die' statement), just curious...

    Thanks,
    joe
    Last edited by joeDetroit; 11-16-2011 at 07:33 PM.

  • #15
    Super Moderator
    Join Date
    May 2005
    Location
    Southern tip of Silicon Valley
    Posts
    2,953
    Thanks
    2
    Thanked 172 Times in 167 Posts
    Using the 3 arg form of open is not performance related. There are several reasons, but the key one is security. The 2 arg form is less secure because it opens the door for possible code injection. For example, in the 2 arg form if the filename is being supplied by the user instead of being hard coded, it's passed to and interpolated by the shell. In such a case, the user could add malicious code after the filename and it would/could be executed by the shell.

    One advantage of the lexical var is that it's block scoped and perl will do an implicit close if needed and another advantage is that since it's a lexical var, it doesn't pollute the symbol table like the bareword filehandles do.

    Since the hostnames aren't duplicated, then a simple hash will suffice instead of the hash of arrays. Before we make that change, I'd like to know the results of code I provided.

  • Users who have thanked FishMonger for this post:

    joeDetroit (11-17-2011)


  •  
    Page 1 of 3 123 LastLast

    Tags for this Thread

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •