2009/12/23

Delete the WSUS Client ID's from registry by Powershell script

CURRENT CONFIGURATION: Microsoft Windows 2003 with Powershell 1.0; WSUS 3; OS distribution method is cloning (imaging) of computers or virtual machines copying.
OBJECTIVE: Fix the issue with computer name overlapping in WSUS
ISSUE: Computers override each other or not appear in WSUS console.
SOLUTION: When you clone (re-image) new computer from different either disk or clone image WSUS Client ID would be the same for either both or all recloned (reimaged) computers.
I wrote Powershell script to delete WSUS client ID's in registry.
DeleteWSUSid.ps1
# *****************************************************************************
# Windows Powershell script
# Author:  Vadim Zenin http://vadimszenins.blogspot.com
# Version:  1.00
# Date:     27/11/2009 13:47:06
# Purpose: Delete the WSUS Client ID's from the registry.
#
# Do not forget: Set-ExecutionPolicy RemoteSigned
#
# Arguments:
#
# Tested platform:
# Windows Powershell v 1.0,
# Windows 2003 R2 x64 SP2
#
# Version 1.00 revision:
#
# This code is made available as is, without warranty of any kind. The entire
# risk of the use or the results from the use of this code remains with the user.
# *****************************************************************************

Param(
)

# Require
# =============================================================================

# =============================================================================
# Function that returns true if the incoming argument is a help request
# =============================================================================
function IsHelpRequest
{
    param($argument)
    return ($argument -eq "-?" -or $argument -eq "-help");
}

# =============================================================================
# Function: Get-Usage
# Author: Vadim Zenin
# Created: 30/10/2009 13:01:21
# Purpose: Script usage explanation and examples.
# Arguments: none
# Returns:
# =============================================================================
function Get-Usage()
{
@"

USAGE:

NAME:
$ScriptNameOnly.ps1

SYNOPSIS:
Delete the WSUS Client ID's from the registry.

PARAMETERS:

EXAMPLES:
.\$ScriptNameOnly.ps1

"@
}

# =============================================================================
#  MAIN SCRIPT
# =============================================================================

$ScriptPath = $MyInvocation.MyCommand.Path
$ScriptNameOnly = [system.io.path]::GetFilenameWithoutExtension($ScriptPath)
#write-host " ScriptNameOnly: $ScriptNameOnly"

# Check for Usage Statement Request
$args | foreach { if (IsHelpRequest $_) { Get-Usage; exit; } }

write-host "Deleting the WSUS Client ID's from the registry"
$RegPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate"
$RegProperties = "AccountDomainSid", "PingID", "SusClientId", "SusClientIdValidation"
foreach ($RegProperty in $RegProperties) {
    remove-itemproperty -path $RegPath -name $RegProperty -erroraction silentlycontinue
}
#Get-ItemProperty $RegPath

Write-Host -ForegroundColor DarkGreen " Script $ScriptNameOnly has finished"
Download md5: 1bdfcbd25c3b78d204110ace9d89bb8e

2009/11/10

Powershell: Fix Active Directory Permission Inheritance


CURRENT CONFIGURATION: Microsoft Windows 2003 Active Directory, Windows 2003 R2 x64 SP2 Domain Controller with Windows Powershell v 1.0

OBJECTIVE: Delegate AD permissions for some OU.

ISSUE: Some OU, Users, Group and Computers in AD have unchecked permissions settings "Inherit from parent the permission entries that apply to child objects. Include these with entries explicitly defined here"

SOLUTION: I wrote a Powershell script AD_Permission_Inheritance_Enable.ps1
# *****************************************************************************
# Windows Powershell script
# Author:  Vadim Zenin http://vadimszenins.blogspot.com
# Version:  1.00
# Date:     10/11/2009 18:18:43
# Purpose: Restore Active Directory Permission Inheritance on Active
# Directory Objects
#
# Arguments:
# Args[0] OU distinguished Name
#
# Tested platform:
# Windows Powershell v 1.0,
# Windows 2003 R2 x64 SP2,
#
# Version 1.00 revision:
#
# This code is made available as is, without warranty of any kind. The entire
# risk of the use or the results from the use of this code remains with the user.
# *****************************************************************************
# http://www.experts-exchange.com/Software/Server_Software/File_Servers/Active_Directory/Q_23214970.html
# http://www.powershell.nu/wp-content/uploads/2009/02/get-ad.ps1

Param($DN)
# Modify the string to exclude some classes
[string[]]$AllClasses = 'OrganizationalUnit','Computer','Person','Group'

# =============================================================================
#  FUNCTION LISTINGS
# =============================================================================

# =============================================================================
# Function that returns true if the incoming argument is a help request
# =============================================================================
function IsHelpRequest
{
    param($argument)
    return ($argument -eq "-?" -or $argument -eq "-help");
}

# =============================================================================
# Function: Get-Usage
# Author: Vadims Zenins
# Created: 30/10/2009 13:01:21
# Purpose: Script usage explanation and examples.
# Arguments: none
# Returns:
# =============================================================================
function Get-Usage()
{
@"

USAGE:

NAME:
$ScriptNameOnly.ps1

SYNOPSIS:
Restore Active Directory Permission Inheritance on Active Directory Objects:
 'OrganizationalUnit', 'Computer', 'Person', 'Group' under either OU or
 Active Directory root
To exclude some class of object just modify next line on the top:
 $AllClasses = 'OrganizationalUnit','Computer','Person','Group'

PARAMETERS:
`t"OU distinguished Name"

EXAMPLES:
Enable Active Directory Permission Inheritance for "OU=TestOU,DC=MyCompany,DC=local"
.\$ScriptNameOnly.ps1 "OU=TestOU,DC=MyCompany,DC=local"
.\$ScriptNameOnly.ps1 "OU=TestOU,DC=MyCompany,DC=local" > report.log

Enable Active Directory Permission Inheritance for AD root
.\$ScriptNameOnly.ps1 "DC=MyCompany,DC=local"
.\$ScriptNameOnly.ps1

"@
}

# =============================================================================
#  MAIN SCRIPT
# =============================================================================

$ScriptPath = $MyInvocation.MyCommand.Path
$ScriptNameOnly = [system.io.path]::GetFilenameWithoutExtension($ScriptPath)

# Check for Usage Statement Request
$args | foreach { if (IsHelpRequest $_) { Get-Usage; exit; } }

$yes = new-Object System.Management.Automation.Host.ChoiceDescription "&Yes",""
$no = new-Object System.Management.Automation.Host.ChoiceDescription "&No",""
$choices = [System.Management.Automation.Host.ChoiceDescription[]]($yes,$no)
$caption = "Question..."

# Prompt user if argument is empty to start search from AD root
if ($DN -eq $null) {
    $message = "Would you enable Active Directory Permission Inheritance for root?"
    $result = $host.ui.PromptForChoice($caption,$message,$choices,0)
    if($result -eq 0) {
        Write-Host "You answered YES"
        $DN = ([ADSI]"").distinguishedName
    } else {
        Get-Usage
        exit
    }
}

Write-Host "Started in: $DN"

$ds = new-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$DN")

foreach ($aa in $AllClasses) {
    Write-Host "= $aa ="
    $ds.Filter = "(objectClass=$aa)"
    $AllItems = $ds.FindAll()
    foreach($ii in $AllItems) {
            $item = $ii.GetDirectoryEntry()
#        Write-Host "Processing $aa: $($item.sAMAccountName)"
            Write-Host "Processing $aa : $($item.distinguishedName)"
#            Enable Permission Inheritance on an Active Directory Object
            $item.psbase.ObjectSecurity.SetAccessRuleProtection($false,$true)
            $item.psbase.CommitChanges()
    }
}

Write-Host " Script $ScriptNameOnly has finished"


Download md5: f03b9338d5267977d5c6c16a7c7981f9

2009/10/29

Perl script to monitor ports services monitor.pl

CURRENT CONFIGURATION: Windows 2003 Server x64, Perl

OBJECTIVE: Monitor ports and services inside data centre,  send notification by email, keep statistics in log files

SOLUTION: I wrote monitor.pl scripts to check are services, network and Internet connections alive. The Perl script based on Jonathan Eisenzopf moniker.pl script. Configuration file is in csv format.

Monitor.pl script:
#!/usr/bin/perl
#
# Changed by Vadims Zenins http://vadimszenins.blogspot.com
# Date 28/03/2007 18:02
# Version 1.00
#
# This script based on idea
# moniker.pl - monitors named server ports
# by Jonathan Eisenzopf. v0.2 20000107
#
# Description: Script to monitor ports (services), send notification by email,
# keep statistics in log files
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#

# INCLUDES
use strict;
use Net::Telnet;
use Getopt::Std;
use Text::CSV_PP;
use Mail::Sender;
use Sys::HostIP;
use Sys::Hostname;
use Cwd;
use Archive::Zip;
use File::Find;
use File::Basename;
require "ctime.pl";

# CONSTANTS
my $timeout = 4;
my $emailsender = 'monitor@mycompany.com';
my $report_email = 'sysadmin@mycompany.com';
# Write Yours report folder name
my $report_folder = "reports";
# Write Your Reports type
my $report_file = "ServicesFaultReport";
# Write Your Reports file extension
my $report_file_ext = "csv";
# Write Your log name
my $log_folder = "logs";
my $log_temp = '_temp.txt';
# Write SMTP server addresse
my $serversmtp = 'smtp.mycompany.com';
# Write email subjects
my $email_alarm_subj = "Services Monitor Alarm";
my $email_warning_subj = "Services Monitor Warning";
my $email_report_subj = "Services Monitor Report";
# Write fault quantity for warning email
my $email_warning_quantity = 1;
# Write fault quantity for alert email (for data centre)
my $email_alarm_quantity = 3;


#******************** END of config ********************
my ($host, $service, $_ERR, $sock, $send_to_warning, $send_to_alarm);
my ($quantity_current, $conf_alarm_quantity, $conf_warning_quantity);
my ($listfile, $extensions, @files);
my ($tmp, $temp, @tmp);
my ($Date, $report_archive);
#my $report = ();


my $services = {
    ftp    => { port => 21,   print => "", waitfor => '/220/' },
    ssh    => { port => 22,   print => "", waitfor => '/SSH/' },
    telnet => { port => 23,   print => "", waitfor => '/(login|username)/' },
    domain => { port => 42,   print => "", waitfor => '' },
    http   => { port => 80,   print => "HEAD / HTTP/1.0\n\n", waitfor => '/200/' },
    https  => { port => 443,  print => "HEAD / HTTP/1.0\n\n", waitfor => '/200/' },
    pop    => { port => 110,  print => "", waitfor => '/\+OK/' },
    nntp   => { port => 119,  print => "", waitfor => '/200/' },
    imap   => { port => 143,  print => "", waitfor => '/OK/' },
    irc    => { port => 6667, print => "", waitfor => '' },
    smtp   => { port => 25,   print => "", waitfor => '/SMTP/' }
};

# MAIN
# get the command line arguments
my %opts = ();
getopt('hsef', \%opts);

##$service  = $opts{s};
##$host     = $opts{h};
##$send_to_warning    = $opts{e} if exists $opts{e};
##$listfile = $opts{f} if exists $opts{f};
##print "Host: $host; Service: $service; Email: $send_to_warning\n";

&get_time();

my $myipaddress = hostip; # get (text) dotted-decimal ip
my $myhostname = hostname; # get hostname
# change email subjects
$email_alarm_subj = "Services Monitor Alarm from $myhostname";
$email_warning_subj = "Services Monitor Warning from $myhostname";

# --- Set final log file name ---
#--- replace / OR : with - in the string ---
($temp = $Date) =~ s/[\/:]/-/g;
#--- delete first space and all after one in the string ---
$temp =~ s/[" "].*//g;
#--- replace " "  with , in the string ---
#$temp =~ s/[ ]/,/g;
my $finallog_name = "log-$myhostname-$temp.log";
print "finallog name: $finallog_name\n";

# --- Set report file name ---
#--- replace first / to - in the string ---
($temp = $Date) =~ s/[\/:]/-/o;
#--- delete first / and all after one in the string ---
$temp =~ s/\/.*//g;
my $log_archive = "log-$temp.zip";
$report_archive = "$report_file-$myhostname-$temp.zip";
my $report_file = "$report_file-$myhostname-$temp.$report_file_ext";

print "report_file name: $report_file\n";

# get working directory
my $current_dir = dirname($opts{f}) if (exists $opts{f})   ;
# change '\' to '/' (avoids trouble in substitution on Win2k)
$current_dir =~ s|\\|/|g;
#my $current_dir = getcwd; # get pathname of current working directory
print "Working dir: $current_dir\n";

$report_folder = "$current_dir/$report_folder";
$log_folder = "$current_dir/$log_folder";

# --- Check Log folder ---
&folder_check_create($log_folder);
print "log name: $log_folder/$log_temp\n";

# --- Delete old temporary log file ---
&dirfile_delete ($log_folder, $log_temp);

# --- Check report folder ---
&folder_check_create($report_folder);

# Check if Final log file exists, archive old if does not
if (-e "$log_folder/$finallog_name") {
    print "Final log name: $log_folder/$finallog_name\n";;
} else {
    &archive_reports($log_folder,"log",$log_archive,'move');
#    my $finallog_exist = 0;
}

# Check if Report file exists, archive old if does not
if (-e "$report_folder/$report_file") {
#    my $finallog_exist = 1;
    print "File $report_folder/$report_file exists\n";
} else {
    &archive_reports($report_folder,$report_file_ext,$report_archive,'move');
    &send_mail ($report_folder, $report_archive, $serversmtp, $emailsender,
        $report_email, '', "$email_report_subj $report_archive", ' ');
    $tmp = "Number of consecutive failed requests,Date,Host,Service,Error,Monitor ip address,Monitor hostname\n";
    &file_open_add_close($report_folder,$report_file,$tmp);
    #    my $reportfile_exist = 0;
}

# --- Start temporary log file ---
$tmp = "--- Start of programm on $myhostname ---\n";
&PrintAndWriteToLog($log_folder,$log_temp,$tmp);

# --- Check for file operators -f ---
$listfile = $opts{f} if exists $opts{f};
#$tmp = "Config filename (-f): $listfile\n";
#&PrintAndWriteToLog($log_folder,$log_temp,$tmp);

# --- if they passed us a filename ---
if (exists $opts{f} && -e $opts{f}) {
    # --- create new Text::CSV object ---
  my $csv = new Text::CSV_PP;
  # --- open the file they specified ---
  open(SERVERSFILE, "< $listfile")
      or die "&PrintAndWriteToLog($log_folder,$log_temp,Cannot open file $listfile: $!\n)";
  while () {
        #--- skip the line if it's empty ---
        next unless /\S+/;
        #--- get the columns for the line ---
        $csv->parse($_);
            ($host,$service,$send_to_warning,$conf_warning_quantity,
            $send_to_alarm,$conf_alarm_quantity) = $csv->fields;
#        $tmp = "Host: $host; Service: $service;
#            send_to_warning: $send_to_warning; conf_warning_quantity: $conf_warning_quantity;
#            send_to_alarm: $send_to_alarm; conf_alert_quantity: $conf_alarm_quantity\n";
#        &PrintAndWriteToLog($log_folder,$log_temp,$tmp);       
       
        # overwrite email_*_quantity from config file
        if ($email_warning_quantity != $conf_warning_quantity && 1 <= $conf_warning_quantity) {
            $email_warning_quantity = $conf_warning_quantity };
        if ($email_alarm_quantity != $conf_alarm_quantity && 1 <= $conf_alarm_quantity) {
            $email_alarm_quantity = $conf_alarm_quantity };
        # Check $email_warning_quantity > $email_alarm_quantity, bu should be <=
        $email_warning_quantity = $email_alarm_quantity if $email_warning_quantity > $email_alarm_quantity;
#        $tmp = "Host: $host; Service: $service;
#            send_to_warning: $send_to_warning; warning_quantity: $email_warning_quantity;
#            send_to_alarm: $send_to_alarm; alert_quantity: $email_alarm_quantity\n";
#        &PrintAndWriteToLog($log_folder,$log_temp,$tmp);
       
        next unless ($host =~ /\S+/ && $service =~ /\S+/);

        #--- check the service and alert ---
        &check_service_and_alarm($host,$service,$send_to_warning,$email_warning_quantity,$send_to_alarm,$email_alarm_quantity);
  }
    close(SERVERSFILE);
}
#else {
#    &usage unless exists($opts{h}) && exists($opts{s});
#
#    $service = $opts{s};
#    $host    = $opts{h};
#    $send_to   = $opts{e} if exists $opts{e};
#    print "Host: $host; Service: $service; Email: $send_to\n";
#
#    # check the service
#    if (&check_service($host,$service)) {
#    print "$host:$service is operational.\n";
#    } else {
##    &alert($send_to,$host,$service,$_ERR);
#    print "$host:$service is NOT operational.\nError: $_ERR.\n";
#    }
#}

$tmp = "--- End of programm. ---\n\n";
&PrintAndWriteToLog($log_folder,$log_temp,$tmp);
addfile1tofile2("$log_folder/$log_temp","$log_folder/$finallog_name");

### SUBROUTINES

#**** Archive reports *****
sub archive_reports {
my ($dir,$report_file_ext,$archive_name,$arcaction) = @_;
@files = ();
cwd $dir;
$extensions = $report_file_ext;
find(\&files_list_short, $dir);
$tmp = scalar @files;
$tmp = "Found $tmp $extensions file(s) for archiving\n";
&PrintAndWriteToLog($log_folder,$log_temp,$tmp);
if (@files <= 0) {
    return 2;
    } else {
my $zip = Archive::Zip->new();

my $zippath = "$dir/$archive_name";
# read-in the existing zip file if any
if (defined $zippath && -f $zippath) {
    my $status = $zip->read($zippath);
    warn "Read $zippath failed\n" if $status != "AZ_OK";
}
# add files
cwd $dir;
foreach my $memberName (@files) {
    if (-d $memberName ){
        warn "Can't add tree $memberName\n"
#        if $zip->addFile( $memberName ) != "AZ_OK";
        if $zip->addTree( $memberName, $memberName ) != "AZ_OK";
    } else {
#        print "dir,file: $dir, $memberName\n";
            $zip->addFile( $memberName )
            or &PrintAndWriteToLog($log_folder,$log_temp,"Can't add file $memberName\n");
    }
}
# prepare the new zip path
my $newzipfile = genfilename();
my $newzippath = "$dir/$newzipfile";
# write the new zip file
my $status = $zip->writeToFileNamed($newzippath);
if ($status == "AZ_OK") {
    # rename (and overwrite the old zip file if any)?
    if (defined $zippath) {
        my $res = rename $newzippath, $zippath;
        if ($res) {
            &PrintAndWriteToLog($log_folder,$log_temp,"Updated file $zippath\n");
        } else {
            &PrintAndWriteToLog($log_folder,$log_temp,"Created file $newzippath, failed to rename to $zippath\n");
        }
        } else {
        &PrintAndWriteToLog($log_folder,$log_temp,"Created file $newzippath\n");
        }
        } else {
        &PrintAndWriteToLog($log_folder,$log_temp,"Failed to create file $newzippath\n");
        }
        if ($arcaction eq 'move') {
#            print " Moving to archive\n";
            if  (-e $zippath) {
                foreach my $memberName (@files) {
                    &file_delete($memberName);
                }
            }
        }
    }
}
#**** list all files in folder *****
sub files_list_short {
#my ($dir, $extensions) = @_;
#    print "directory: $File::Find::dir\nExtentions: $extensions\n";
my $filename = ();
    if (/\.($extensions)$/) {
        cwd $File::Find::dir;
        return if -d $File::Find::name; # skip directories
#        my $fileagedays = fileAgeDays($_);
#        if ($fileagedays < $maxFileAgeDays) {
#            printf STDERR "$File::Find::name    (%.3g)\n"; #, $fileagedays;
            (my $filename = $File::Find::name) =~ s/^[a-zA-Z]://;  # remove the leading drive letter:
        push @files, $filename;
        print "$extensions file: $filename\n";
#        push @files, "./$_";
#        print "$extensions file: $_\n";
#        }
return @files;
    }
}
#**** Generate file name *****
sub genfilename {
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
    sprintf "%04d%02d%02d-%02d%02d%02d.zip", $year+1900, $mon+1, $mday, $hour, $min, $sec;
}
#**** Check folder *****
sub folder_check_create {
my ($temp) = @_;
    if (-e $temp) {
        print "Folder $temp already exists\n";
        } else {
            mkdir ($temp);
            print "Folder $temp was created\n";
    }
}
#**** get time *****
sub get_time() {
$Date = &ctime(time);
return $Date;
}

# ***** Send Mail *****
sub send_mail {
my ($dir,$file_name,$smtp,$emailsender,$send_to,$send_cc,$email_subj,@message) = @_;
# print "dir,file,to = @_  \n";
chdir("$dir");
open my $DEBUG, ">> $log_folder/$log_temp"
    or die "Can't open the debug file: $!\n";
ref (my $sender = new Mail::Sender({from => $emailsender,
smtp => $smtp})) or die &PrintAndWriteToLog($log_folder,$log_temp,"$Mail::Sender::Error\n");
if ($send_to ne 0){
    if ($file_name eq 'not_file')
    {
        ref ($sender->MailMsg(
        {to => $send_to,
        cc => $send_cc,
        subject => $email_subj,
#        debug => $DEBUG'
        msg => "@message"
        }));
        $tmp = "Mail sent TO: $send_to CC: $send_cc without attachment\n";
        &PrintAndWriteToLog($log_folder,$log_temp,$tmp);
    } else {   
    ref ($sender->MailFile(
    {to => $send_to,
    cc => $send_cc,
    subject => $email_subj,
    msg => "@message",
    file => $file_name    }));
    $tmp = "Mail sent TO: $send_to CC: $send_cc with attachment $file_name\n";
    &PrintAndWriteToLog($log_folder,$log_temp,$tmp);
    }
}
else {
    $tmp = "! Dont sent to $send_to $Mail::Sender::Error\n";
    &PrintAndWriteToLog($log_folder,$log_temp,$tmp);}
}

#***** Message print & write to log *****
sub PrintAndWriteToLog
{
my ($dir,$filename,$temp) = @_;
&get_time();
$temp = "$Date $temp";
print "$temp";
&file_open_add_close($dir,$filename,$temp);
}

# ***** Delete file if specified directory and file name *****
sub dirfile_delete {
my ($rdir, $filename) = @_;
$temp = "$rdir/$filename";
if (-e $temp) {
    unlink($temp) ;
    &PrintAndWriteToLog($log_folder,$log_temp,"Deleted File: $temp\n");
    } else {
        &PrintAndWriteToLog($log_folder,$log_temp,"can not delete file: $temp, because file does not exist\n");
    }
}

# ***** Delete file if specified full file name *****
sub file_delete {
my ($temp) = @_;
if (-e $temp) {
    unlink($temp) ;
    &PrintAndWriteToLog($log_folder,$log_temp,"Deleted File: $temp\n");
    } else {
        &PrintAndWriteToLog($log_folder,$log_temp,"can not delete file: $temp, because file does not exist\n");
    }
}

#***** Check the Service & Alert ******
sub check_service_and_alarm {
    ($host,$service,$send_to_warning,$email_warning_quantity,
    $send_to_alarm,$email_alarm_quantity) = @_;
   
        if (&check_service($host,$service)) {
          $tmp = "$host:$service is operational.\n";
          &PrintAndWriteToLog($log_folder,$log_temp,$tmp);
          &dirfile_delete ($log_folder,"$host.$service") if (-e "$log_folder/$host.$service");
          return 1;
        } else {
        &Check_repeating_of_error($log_folder,$host,$service,$email_warning_quantity,$email_alarm_quantity);
        $_ERR = "$quantity_current,$_ERR";
#        print "quantity_current:$quantity_current\n";
        &PrintAndWriteToLog($log_folder,$log_temp,"quantity_current:$quantity_current\n");
            &file_open_add_close($report_folder,$report_file,"$_ERR\n");
        $tmp = "! $host:$service is NOT operational.
        ! Error:\n  $_ERR
        Test number is $quantity_current from $email_warning_quantity/$email_alarm_quantity\n";
        &PrintAndWriteToLog($log_folder,$log_temp,$tmp);

my @message_warning = <<"END_MESSAGE";
This is a Warning email from $myhostname IP: $myipaddress

$host:$service is NOT operationalafter $quantity_current number(s) of consecutive failed requests.
Error is:
$_ERR

Regards,
Systems Administrator
END_MESSAGE

my @message_alarm = <<"END_MESSAGE";
! This is a ALARM message from $myhostname IP: $myipaddress

$host:$service is NOT operational after $quantity_current numbers of consecutive failed requests.
Error is:
$_ERR

Regards,
Systems Administrator
END_MESSAGE

        if ($quantity_current >= $email_warning_quantity && $quantity_current < $email_alarm_quantity) {
            &send_mail ($report_folder, 'not_file', $serversmtp, $emailsender,
            $send_to_warning, '', $email_warning_subj, @message_warning);
        } else {
#        if ($quantity_current >= $email_alarm_quantity) {
            &send_mail ($report_folder, 'not_file', $serversmtp, $emailsender,
            $send_to_alarm, $send_to_warning, $email_alarm_subj, @message_alarm);
        }

#            &send_mail ($report_folder,'not_file',$serversmtp,$emailsender,$send_to_warning,$email_warning_subj,$tmp);
        return 0;
        }
}   
#***** Check repeating of error ******
sub Check_repeating_of_error {
my ($dir,$file_name,$file_extension,$email_warning_quantity,$email_alarm_quantity) = @_;
if (-e ("$dir/$file_name.$file_extension")) {
#    $temp = "File $dir/$file_name.$file_extension exists\n";
#    &PrintAndWriteToLog($log_folder,$log_temp,"$temp");
    &fault_file_replace("$dir/$file_name.$file_extension");
    return $quantity_current;   
    } else {
#        $temp = "File $dir/$file_name.$file_extension does not exist\n";
#        &PrintAndWriteToLog($log_folder,$log_temp,"$temp\n");
        &file_open_add_close($log_folder,"$host.$service",pack("A","1"));
        $quantity_current = 1;
        return $quantity_current;
    }
}
#***** replase fault File *****
sub fault_file_replace {
my ($dir,$fault_file,$fault_file_ext) = @_;
open(FAULT_FILE, "< $dir/$fault_file.$fault_file_ext")
    or die PrintAndWriteToLog("Couldn't open file $dir/$fault_file.$fault_file_ext: $!\n");
#sysopen(FAULT_FILE, "$dir/$fault_file.$fault_file_ext", "O_WRONLY|O_TRUNC")
#    or die PrintAndWriteToLog("Couldn't open file: $!\n");
@tmp = ;
close FAULT_FILE;
@tmp[0] =~ s/^\D//g;
$quantity_current = unpack("A",@tmp[0]);
#&PrintAndWriteToLog($log_folder,$log_temp,"quantity_old:$quantity_current\n");
$quantity_current = $quantity_current + 1;
#&PrintAndWriteToLog($log_folder,$log_temp,"quantity_current:$quantity_current\n");
open(FAULT_FILE, "> $dir/$fault_file.$fault_file_ext")
    or die PrintAndWriteToLog("Couldn't open file $dir/$fault_file.$fault_file_ext: $!\n");
print FAULT_FILE pack("A","$quantity_current");
close FAULT_FILE;
return $quantity_current;
}
#***** Open or create, Add and Close Report File *****
sub file_open_add_close {
my ($report_folder,$report_file,@report) = @_;
#--- open report File ---
open(REPORT_FILE,">> $report_folder/$report_file");
#--- Add to Report File ---
print REPORT_FILE @report;
#--- Close Report File ---
close REPORT_FILE;
}
#***** Check Service ******
sub check_service {
    ($host,$service) = @_;

    #--- make sure user specified a valid service ---
    die &PrintAndWriteToLog($log_folder,$log_temp,"! Service $service does not compute.\n")
        unless defined $services->{$service};
       
    my $port    = $services->{$service}->{port};
    my $sock    = new Net::Telnet (Telnetmode => 0);
    my $waitfor = $services->{$service}->{waitfor};
   
    #--- Create a connection to the remote host ---
    eval {
    $sock->open(Host    => $host,
        Port    => $port,
        Timeout => $timeout
        );
    };

    #--- Catch any errors ---
    if ($@) {
        &get_time();
        $_ERR = "$Date,$host,$service,Can not establish connection,$myipaddress,$myhostname";
        return 0;
    }
   
    # send data to remote host
    $sock->print($services->{$service}->{print}) if $services->{$service}->{print};

    # wait for regex match
    if (!($sock->waitfor($waitfor))) {
        $_ERR = "$Date,$host,$service,Timed out waiting for $waitfor,$myipaddress,$myhostname";
        return 0;
    }
   
    # things went well
    return 1;
}

#*** Add File1 to File2 ****
sub addfile1tofile2 {
my ($file1, $file2) = @_;
open(IN,$file1) || die "cannot open $file1 for reading: $!";
open(OUT,">>$file2") || die "cannot create $file2: $!";
while () {     #read line from $file1 to $_
    print OUT $_; # write line $_ to file $file2
    }
close(IN) || die "can't close $file1: $!";
close (OUT) || die "can't close $file2: $!";
}

sub usage {
    die <
Usage: monitor -h host -s service [-e email]
       monitor -f
DIE
}

1;
__END__


Configuration file:
#hostname/IP,service,send_to_warning,conf_warning_quantity,send_to_alarm,conf_alarm_quantity
myserver.mydomain.com,http,"sysadmin@mycompany.com",1,"notifications@mycompany.com",3
myserver.mydomain.com,smtp,"sysadmin@mycompany.com",1,"notifications@mycompany.com",4
12.12.12.12,ssh,"sysadmin@mycompany.com",1,"notifications@mycompany.com",5
www.mydomain.com,http,"sysadmin@mycompany.com",1,"notifications@mycompany.com",5
www.eircom.ie,http,"sysadmin@mycompany.com",1,"notifications@mycompany.com",3
home.btireland.ie,http,"sysadmin@mycompany.com",1,"notifications@mycompany.com",3
www.magnet.ie,http,"sysadmin@mycompany.com",1,"notifications@mycompany.com",3
11.11.11.11,http,"sysadmin@mycompany.com",1,"notifications@mycompany.com",3
ftp.mydomain.com,ftp,"sysadmin@mycompany.com",1,"notifications@mycompany.com",5


DOWNLOAD: monitor.zip
Download md5: 2f982b123f93926aeca5f521bacf7185

2009/10/15

Batch: delete files older than X days

CURRENT CONFIGURATION: Windows XP, Windows 2003, Windows 2008

OBJECTIVE: Delete by batch scrip files older than X days. Call this script from different scripts or from scheduled task.

SOLUTION:
I wrote batch file for that. The script requires forfiles.exe. Forfiles.exe exist by default on Windows 2003, 2008 servers.  Can be downloaded with Microsoft Windows NT Server 4.0 Resource Kit.

--- Start of delete_old_files.cmd batch file ---

@echo on
:: *****************************************************************************
:: Author:  Vadim Zenin http://vadimszenins.blogspot.com
::  Version: 1.02
::  Date:     15/09/2009 10:21:31
::
::  delete files in folder with extentions
::  with/without recurse into subdirectories
::  with/without logging
::
:: This code is made available as is, without warranty of any kind. The entire
:: risk of the use or the results from the use of this code remains with the user.
:: *****************************************************************************
@echo off
::echo Variables 1: %1; 2: %2; 3: %3; 4: %4; 5: %5

@SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

:: Grab a file name and extension only
SET SCRIPTNAME=%~nx0
:: Grab a file name only (prefix)
SET SCRIPTONLYNAME=%~n0
:: Replace "
SET SCRIPTNAME=%SCRIPTNAME:"=%
SET SCRIPTONLYNAME=%SCRIPTONLYNAME:"=%
:: Replace spases
SET SCRIPTONLYNAME=%SCRIPTONLYNAME: =%
SET TOOLS=C:\tools
SET LOGDIR=%TOOLS%\logs

SET SOURCEDIR=%1
SET SOURCEFILEEXT=%2
SET DAYSOLD=%3
SET RECURSE=%4
SET LOGGING=%5
:: Replace "
SET SOURCEDIR=%SOURCEDIR:"=%
:: "
SET FILENAME1=%SOURCEDIR%
:: Replace \
SET FILENAME1=%FILENAME1:\=%
:: Replace :
SET FILENAME1=%FILENAME1::=%
:: Replace -
SET FILENAME1=%FILENAME1:-=%
:: Replace _
SET FILENAME1=%FILENAME1:_=%
:: cut to 32 symbols
SET FILENAME1=%FILENAME1:~0,32%
SET LOGFILE=%LOGDIR%\%SCRIPTONLYNAME%_%FILENAME1%.log
SET TEMPLISTFILE1=%LOGDIR%\%SCRIPTONLYNAME%_%FILENAME1%.txt
:: Require
:: forfiles.exe
:: =============================================================================
SET RETURN=0

if not exist %LOGDIR% md %LOGDIR%
echo. >>%LOGFILE%
echo ============================================================================= >>%LOGFILE%
echo %DATE% %TIME% %SCRIPTNAME% has started >>%LOGFILE%
echo ============================================================================= >>%LOGFILE%
echo Variables SOURCEDIR: %1; SOURCEFILEEXTENTION: %2; DAYSOLD: %3; RECURSE: %4; LOGGING: %5 >>%LOGFILE%
@if "%1"=="" goto usage
@if "%1"=="/?" goto usage
@if "%1"=="-?" goto usage
@if "%4"=="" goto usage

@echo Delete files older then %DAYSOLD% days with %RECURSE% in directory >>%LOGFILE%
@echo %SOURCEDIR%\%SOURCEFILEEXT% >>%LOGFILE%
if "%RECURSE%"=="NORECURSE" SET RECOPT=
if "%RECURSE%"=="RECURSE" SET RECOPT=/s
@echo RECOPT (recursive option): %RECOPT% >>%LOGFILE%

FORFILES /p %SOURCEDIR% %RECOPT% /d -%DAYSOLD% /m %SOURCEFILEEXT% /c "CMD /C Echo @PATH" > %TEMPLISTFILE1%
type %TEMPLISTFILE1% >>%LOGFILE%
echo. >>%LOGFILE%
@Sleep 1

FOR /f %%u IN (%TEMPLISTFILE1%) DO (
    if exist %%u @ERASE /F /Q %%u >>%LOGFILE% )
@Sleep 1
@goto END

:USAGE
@echo Usage: >>%LOGFILE%
@echo  %SCRIPTNAME% ^ ^ ^ ^ ^(optinal) >>%LOGFILE%
@echo Examples: delete all *.zip in folder x:\archive older than 7 days
@echo           %SCRIPTNAME% x:\archive *.zip 7 RECURSE LOGGING (into subfolders with log file) >>%LOGFILE%
@echo           %SCRIPTNAME% x:\archive *.zip 7 NORECURSE (in current folder only with log file) >>%LOGFILE%
@echo           %SCRIPTNAME% x:\archive *.zip 7 RECURSE NOLOG (into subfolders without log file) >>%LOGFILE%
@echo. >>%LOGFILE%
::@notepad %LOGFILE%
exit /b 128

:END
echo %DATE% %TIME% %SCRIPTNAME% has finished with code %RETURN% >>%LOGFILE%
::notepad %LOGFILE%
echo. >>%LOGFILE%
if "%LOGGING%"=="NOLOG" ERASE /F /Q %LOGFILE%
exit %RETURN%



--- The end of delete_old_files.cmd batch file ---



DOWNLOAD:
Download delete_old_files.zip md5: e695867259b0956488bd37448f2be44e

2009/09/18

Change the display language on iTunes Store

CURRENT CONFIGURATION: MacBook Air, Mac OS 10.5.8, iTunes 8.2.1(6)
OBJECTIVE: Change the display language on iTunes Store back.
ISSUE: iTunes changed language to different during a trip to different country. Preferences of iTunes don not have any display language settings.

SOLUTION:

Open iTunes. Select iTunes Store. Scroll down, more down. At the bottom select Country in My Store with your language.


Is it miracle? I think it is user UNFRIENDLY design.

Entourage 2008 Calendar is empty

CURRENT CONFIGURATION: MacBook Air, Mac OS 10.5.8, Microsoft Entourage 2008 for Mac 12.2.0 (90605) with update 12.2.1, Microsoft Exchange 2007

OBJECTIVE: Use Entourage for Exchange Calendar

ISSUE: Entourage Calendar is empty, but events are exist and viewable on Exchange OWA page.

SOLUTION:
Open Entourage 2008. Enable Folder List. Open Calendar (under your Exchange account name). Create new test event. Expand Calendars Views --> All Events. Find and select the test event. Menu Event --> Move to --> Choose Calendar --> Select Calendar under your Exchange account name.
Select calendar under your Exchange account name in Folder List and check all events.

Is it miracle? I think it is software bug.

2009/06/16

Fixing space in Public Folder name issue in Excahnge 2007 built-in scripts

CURRENT CONFIGURATION: Exchange 2007 Standard with Public folders

OBJECTIVE: Remove or add user permissions from or to Exchange Public folder and all folders under it (recursive) with Exchange built-in PowerShell scripts RemoveUserFromPFRecursive.ps1 and AddUsersToPFRecursive.ps1.

ISSUE: Scripts RemoveUserFromPFRecursive.ps1 and AddUsersToPFRecursive.ps1 don't work if Exchange Public Folder name contains space(s).

SOLUTION:
Create vbackup copy of original RemoveUserFromPFRecursive.ps1 and AddUsersToPFRecursive.ps1 scripts.

In scripts RemoveUserFromPFRecursive.ps1 and AddUsersToPFRecursive.ps1

find
"get-publicfolder -identity $TopPublicFolder -Recurse -resultsize unlimited"
replace by
#Fixing name with space problem:
'get-publicfolder -identity "$TopPublicFolder"-Recurse -resultsize unlimited'

find
$permission | remove-PublicFolderClientPermission -identity $_.Identity -server $_.OriginatingServer
replace by
#Fixing confirmation problem
$permission | remove-PublicFolderClientPermission -identity $_.Identity -server $_.OriginatingServer -Confirm:$false

DOWNLOAD:
Download AddUsersToPFRecursive_vz.zip md5: 2bc7416556e60958b25a4d9f9648111f
Download RemoveUserFromPFRecursive_vz.zip md5: f247fd6c7951309b9b8d0d0e4b37dff0

2009/06/11

BlackBerry activation email goes to Junk E-mail folder

CURRENT CONFIGURATION: Microsoft Exchange 2007 Standard SP1 with enabled "Content Filter Agent", Blackberry Professional Server

OBJECTIVE: Activate BlackBerry Bold device

ISSUE: Activation emails from RIM appear in Junk E-mail folder in Microsoft Outlook as spam. RIM server EVERY time sends activation emai with DIFFERENT from DOMAIN address. User can not make either email sender or domain to Safe Sender List in Microsoft Outlook.

SOLUTION:
On Exchange 2007 execute next commands in Exchange Power Shell

Add-ContentFilterPhrase -Phrase "This message is used to carry data between the BlackBerry handheld and an associated server" -Influence GoodWord

Set-ContentFilterConfig -BypassedSenderDomains *.blackberry.net

LINKS: Microsoft Technet
How to Configure Allow Phrases for Content Filtering
How to Specify Recipient and Sender Exceptions for Content Filtering

2009/03/31

Change folder of Default SMTP

CURRENT CONFIGURATION: Microsoft Windows 2003 Server, IIS, SMTP Service, Message Queuing

OBJECTIVE: Change folder of Default SMTP

ISSUE: ISS Manager Console cannot configure all of IIS SMTP directories

SOLUTION:
We can use adsutil.vbs.
I wrote simple batch file for that

--- Start of IIS_SMTP_folder_relocate.cmd batch file ---

@echo on
:: *****************************************************
:: Author: Vadim Zenin http://vadimszenins.blogspot.com
:: Version: 1.00
:: Date: 25/03/2009 10:37
:: Change IIS SMTP directory location
::
:: Usage: %SCRIPTNAME%
::
:: Version 1.00 revision:
::
:: *****************************************************
::@echo off

@SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

FOR %%I IN ( "%0" ) DO SET SCRIPTNAME=%%~nxI
SET TOOLS=C:\tools
SET LOGDIR=%TOOLS%\logs
SET LOGFILE=%LOGDIR%\%SCRIPTNAME%.log

SET DESTINATIONDISK=D:
SET DESTINATIONFOLDER=mailroot
SET DESTINATION=%DESTINATIONDISK%\%DESTINATIONFOLDER%

:: Require
SET ADSUTIL=%SYSTEMDRIVE%\inetpub\adminscripts\adsutil.vbs
:: ==============================================================

if not exist %LOGDIR% md %LOGDIR%
echo ====================== >> %LOGFILE%
echo %DATE% %TIME% %SCRIPTNAME% is started >> %LOGFILE%

SC stop smtpsvc >> %LOGFILE%

:: Check requirements
if not exist %ADSUTIL% ( echo %ADSUTIL% is required >>%LOGFILE%
exit 128)

if not exist %DESTINATION% md %DESTINATION% >>%LOGFILE%
if not exist %DESTINATION%\Badmail md %DESTINATION%\Badmail >>%LOGFILE%
if not exist %DESTINATION%\Drop md %DESTINATION%\Drop >>%LOGFILE%
if not exist %DESTINATION%\Pickup md %DESTINATION%\Pickup >>%LOGFILE%
if not exist %DESTINATION%\Queue md %DESTINATION%\Queue >>%LOGFILE%

:: Relocate IIS SMTP folders
cscript %ADSUTIL% SET /SmtpSvc/1/BadMailDirectory %DESTINATION%\Badmail >> %LOGFILE%
cscript %ADSUTIL% SET /SmtpSvc/1/DropDirectory %DESTINATION%\Drop >> %LOGFILE%
cscript %ADSUTIL% SET /SmtpSvc/1/PickupDirectory %DESTINATION%\Pickup >> %LOGFILE%
cscript %ADSUTIL% SET /SmtpSvc/1/QueueDirectory %DESTINATION%\Queue >> %LOGFILE%

SC start smtpsvc >> %LOGFILE%

:END
::SET RETURN=0
echo %DATE% %TIME% %SCRIPTNAME% is finished>> %LOGFILE%
@notepad %LOGFILE%
echo. >> %LOGFILE%
exit /B %RETURN%


--- The End of IIS_SMTP_folder_relocate.cmd batch file ---

All IIS SMTP service settings we can check in file %SYSTEMROOT%\system32\inetsrv\MetaBase.xml

DOWNLOAD:
Download IIS_SMTP_folder_relocate.zip md5: 10ed6dc64d6f8822a4031b94b43b622e

2009/01/16

CURRENT CONFIGURATION: Microsoft Outlook 2003 or 2007

OBJECTIVE: Synchronise with Salesforce

ISSUE: Salesforce icons does not appear in Microsoft Office Outlook. Re installation of Salesforce add-on doesn't help.
User can’t synchronise mails to Salesforce accounts from outlook.
I used to have Salesforce on my outlook but it has somehow mysteriously disappeared.

SOLUTION:
Microsoft Office Outlook --> Help --> Disabled Items. Enable Salesforce add-on.
Logoff, login or restart PC.

2009/01/12

How to allow non-administrator to run scheduled tasks remotely

CURRENT CONFIGURATION: Windows 2003 server SP2

OBJECTIVE: allow non-administrator to run scheduled tasks remotely.

ISSUE: By default non-administrator, INTERACTIVE and TelnetClients only can run scheduled tasks remotely.

SOLUTION:
- Create scheduled task with system account
schtasks /create /tn TASKNAME /tr "cmd.exe /c echo %%DATE%% %%TIME%% %%COMPUTERNAME%% >> %%TEMP%%\TASKNAME.log" /ru System /sc minute /mo 60 /st 00:03 /et 23:45

- Change account for the scheduled task
schtasks /change /tn TASKNAME /s %COMPUTERNAME% /ru TASKUSER /rp TASKPASS

- Assign permissions to execute scheduled task to non-administrative user or group
cscript.exe XCACLS.vbs %systemroot%\tasks\TASKNAME.job /E /G YUORDOMAIN\TASKUSER:X

- Give permission to execute %SystemRoot%\system32\cmd.exe to the non-administrative user or group
cscript.exe XCACLS.vbs %systemroot%\system32\cmd.exe /E /G YUORDOMAIN\TASKUSER:X

- Assign to the non-administrative user or group "Log on as a batch job" rights.
Open "Local Security Settings" --> "Local Policies" --> "User rights Assignment" --> "Log on as a batch job" and add the non-administrative user or group.

Test result with next command
notepad %TEMP%\TASKNAME.log

--- Star of bat file --

@echo off
:: *************************************************
:: File: task-create_test1.cmd
:: Author: Vadims Zenins (http://vadimszenins.blogspot.com)
:: Version: 1.00
:: Date: 09/01/2009 12:07
:: Task create for non-administrator user or group
:: Usage: task-create_test1.cmd PASSWORD
:: Requirements: XCACLS.vbs
:: ************************************************

:: @IF ERRORLEVEL 1 PAUSE
::echo 1: %1

@SETLOCAL
SET SOURCEPC=%COMPUTERNAME%
SET TASKNAME=task_test1
SET LOGDIR=E:\tools\logs
SET LOGFILE=%LOGDIR%\%TASKNAME%.log
SET TASKUSER=MyDomain\MyTaskUser
SET TASKGROUP=MyDomain\MyTaskGroup
SET TASKPASS=%1
SET TASKCOMMAND="%%systemroot%%\system32\cmd.exe /c echo %%DATE%% %%TIME%% %%COMPUTERNAME%% >> %LOGFILE%"
SET XCACLS=E:\tools\XCACLS.vbs
:: ==============================================================

if not exist %LOGDIR% md %LOGDIR%

echo ====================== >> %LOGFILE%
echo %DATE% %TIME% >> %LOGFILE%
echo SCRIPT is started >> %LOGFILE%

@if "%1"=="" goto usage
@if "%1"=="/?" goto usage
@if "%1"=="-?" goto usage

schtasks /delete /tn %TASKNAME% /f >> %LOGFILE%
schtasks /create /tn %TASKNAME% /tr "cmd.exe /c echo %%DATE%% %%TIME%% %%COMPUTERNAME%% >> %LOGFILE%" /ru System /sc minute /mo 60 /st 00:03 /et 23:45 >> %LOGFILE%
schtasks /change /tn %TASKNAME% /s %COMPUTERNAME% /ru %TASKUSER% /rp %TASKPASS% >> %LOGFILE%
cscript.exe %XCACLS% %systemroot%\system32\cmd.exe /E /G %TASKGROUP%:X /L %LOGFILE%
cscript.exe %XCACLS% %systemroot%\tasks\%TASKNAME%.job /E /G %TASKGROUP%:X /L %LOGFILE%
@goto end

:USAGE
@echo Usage: >> %LOGFILE%
@echo task-create_test1.cmd ^ >> %LOGFILE%
::exit 1

:END
echo %DATE% %TIME% >> %LOGFILE%
echo SCRIPT is finished >> %LOGFILE%
echo. >> %LOGFILE%

--- End of bat file --


Links
Extended Change Access Control List Tool (Xcacls). Xcacls.vbs is an unsupported tool that provides additional capabilities not provided with the supported utility, Xcacls.exe.
Schtasks