【问题标题】:Perl script to start/stop windows service用于启动/停止 Windows 服务的 Perl 脚本
【发布时间】:2014-07-02 17:55:37
【问题描述】:

这里是检查windows服务状态的脚本,如果它们处于停止状态,它将启动服务。我可以获取服务状态,但无法启动服务。 请帮忙,让我知道我需要做什么。

#!/usr/local/bin/perl

use Win32::Service;
use strict;

sub checkService();
sub getDate();
sub getTime();
sub logEvent();

my @timeInfo = localtime(time);
my $serviceName = "TapiSrv";
my $currentDate = getDate();
my $currentTime = getTime();
my %status;
my %status_code = (1 => 'not running',
               2 => 'start pending',
               3 => 'stop pending',
               4 => 'running',
               5 => 'resume pending',
               6 => 'pause pending',
               7 => 'paused');

checkService();

########
# SUBS
########


sub checkService() {
my $startCounter = 0;

Win32::Service::GetStatus('', $serviceName,  \%status);

if($status{"CurrentState"} eq '4') {
    # Log the event
    &logEvent("$currentTime:  $serviceName is running\n");
} elsif($status{"CurrentState"} eq '1') {

    Win32::Service::StartService('', $serviceName);
    }       
    while($startCounter < 3) {
        sleep(5);

        Win32::Service::GetStatus('', $serviceName,  \%status);

        if($status{"CurrentState"} eq '2') {
            $startCounter++;
        } else {
            $startCounter = 3;
        }
    }

    if($startCounter == 3) {
        &logEvent("$currentTime:  Unable to start $serviceName in $startCounter attempts\n");
    } else {
        &logEvent("$currentTime:  Started $serviceName in $startCounter attempts\n");
    }
}

sub getDate() {
my $year = $timeInfo[5] + 1900;
my $month = $timeInfo[4] + 1;
my $day = $timeInfo[3];
return sprintf("%04d-%02d-%02d", $year, $month, $day);
} 

sub getTime() {
my $hour = $timeInfo[2];
my $min = $timeInfo[1];
my $sec = $timeInfo[0];
return sprintf("%02d:%02d:%02d", $hour, $min, $sec);
}

sub logEvent() {
# Log the event
open(OUT, ">> C:/servicestatus/$currentDate.txt");
print OUT "$_[0]";
close(OUT);
}

【问题讨论】:

    标签: windows perl


    【解决方案1】:

    基于下面的一些 cmets(包括 @Ron Bergin 的一些好点),我正在修改这篇文章以展示适合我的代码(Windows 8.1、ActivePerl 5.16)。

    #!/usr/local/bin/perl
    
    use strict;
    use warnings;
    
    use POSIX;
    use Win32::Service;
    
    my $currentDate = getDate();
    my %status;
    my %status_code = (
      Stopped => 1,
      StartPending => 2,
      StopPending => 3,
      Running => 4,
      ResumePending => 5,
      PausePending => 6,
      Paused => 7
    );
    
    checkService("Apple Mobile Device");
    
    ########
    # SUBS
    ########
    
    sub checkService {
      my $serviceName = shift || die "No arg passed";
      my $startCounter = 1;
      Win32::Service::GetStatus('', $serviceName, \%status);
      if ($status{"CurrentState"} eq $status_code{Running}) {
        logEvent("$serviceName is running\n");
      }
      elsif ($status{"CurrentState"} eq $status_code{'Stopped'}) {
        my $maxAttempts = 3;
        while ($startCounter <= $maxAttempts) {
          logEvent("Attempting to start $serviceName");
          Win32::Service::StartService('', $serviceName);
          sleep(5);
          Win32::Service::GetStatus('', $serviceName, \%status);
          if ($status{"CurrentState"} eq $status_code{Running}) {
            logEvent("Started $serviceName in $startCounter attempts\n");
            last;
          }
          $startCounter++;
        }
    
        if ($startCounter eq $maxAttempts) {
          logEvent("Unable to start $serviceName in $startCounter attempts\n");
        }
      }
    }
    
    sub getDate {
      my @timeInfo    = localtime(time);
      my $year  = $timeInfo[5] + 1900;
      my $month = $timeInfo[4] + 1;
      my $day   = $timeInfo[3];
      return sprintf("%04d-%02d-%02d", $year, $month, $day);
    }
    
    sub logEvent {
      my $msg = strftime("%H:%M:%S", localtime) . ": $_[0]\n";
      print "$msg";
      open(OUT, ">> C:/servicestatus/$currentDate.txt");
      print OUT "$msg";
      close(OUT);
    }
    

    以非管理员身份运行此命令,输出如下:

    14:11:30: Attempting to start Apple Mobile Device
    14:11:35: Attempting to start Apple Mobile Device
    14:11:40: Attempting to start Apple Mobile Device
    

    以管理员身份运行如下所示:

    14:14:29: Attempting to start Apple Mobile Device
    14:14:34: Started Apple Mobile Device in 1 attempts
    

    【讨论】:

    • 什么是“open paren”?在问题代码中的StartService 调用之后,我没有看到任何打开的括号(可能问题已被编辑)。
    • 对不起,“关闭括号”!就在 WHILE 循环之前。
    • 那里也没有看到一个接近的括号())。有一个右大括号/大括号 (}) 确实可能需要移动到其他地方。
    • 是的,大括号。不知道我在想什么!但是当我移动它时,你的代码对我有用,增加了额外的睡眠。需要以管理员身份运行,也许就是这样?
    • 我认为逻辑和编码风格非常有问题。(1)不必要地预先声明subs。 (2) 使用 [emplty] 原型 (3) 在错误范围内声明的变量。由于它们仅在子内部使用,因此应该声明它们 (4) 使用 strftime() 而不是滚动您自己的 getDate() 和 getTime() 函数会更干净、更容易。 (5) 使用 eq 代替 == 进行数值相等测试。 (6) 在调用 subs 时使用 &。 (7) 不一致和缺失的缩进。 (8) GetStatus() 和 StartService() 调用的返回值测试失败。
    【解决方案2】:

    我对这个 Win32::Service 模块的一个主要问题是它在失败时返回 undef 但是没有设置 $!所以找出它失败的原因是更多的工作。在检索该错误时我没有进行任何测试,但它可能是对 Win32 模块中的一个函数的调用。

    #!/usr/local/bin/perl
    
    use 5.010;
    use strict;
    use warnings;
    use POSIX qw(strftime);
    use Win32::Service qw(StartService GetStatus GetServices);
    
    my $service = shift || 'Apple Mobile Device';
    check_service($service);
    exit;
    
    ###############################################################################
    
    sub check_service {
        my $service = shift;
        my %status_code = (
            Stopped       => 1,
            StartPending  => 2,
            StopPending   => 3,
            Running       => 4,
            ResumePending => 5,
            PausePending  => 6,
            Paused        => 7
        );
        my (%status, %services);
    
        GetServices('', \%services) or do {
            log_event('Failed to retieve list of services');
            exit;
        };
        %services = reverse %services;
    
        if (! exists $services{$service}) {
            log_event("'$service' is not a configured Windows service");
            exit;
        }
    
        if (GetStatus('', $service, \%status)) {
            if ($status{"CurrentState"} eq $status_code{Running} ) {
                log_event("$service is running");
            }
            elsif ( $status{"CurrentState"} eq $status_code{'Stopped'} ) {
                ATTEMPT: for (1..3) {
                    log_event("Attempting to start '$service'");
                    if (StartService('', $service)) {
                        sleep 5;
                        GetStatus('', $service, \%status);
                        if ($status{"CurrentState"} eq $status_code{Running}) {
                            log_event("Started '$service'");
                            last ATTEMPT;
                        }
                    }
                    else {
                        die "StartService() function failed";
                    }
                }
            }
        }
        else {
            log_event("failed to retrieve the status of service '$service'");
            exit;
        }
        return;
    }
    
    sub log_event {
    
    # Using one of the better loging modules such as Log::Log4perl
    # would be a much better and more robust logging mechanism
    
        my $msg = shift;
        my $timestamp = strftime("%H:%M:%S", localtime);
        my $filename  = strftime("C:/servicestatus/%Y-%m-%d.txt", localtime);
    
        open(my $fh, '>>', $filename) or die "failed to open '$filename' <$!>";
        say $fh "$timestamp: $msg";
        close $fh;
        return;
    }
    

    【讨论】:

    • 感谢您的宝贵时间和帮助 jimtut 和 Ron Bergin 。但是我在这里仍然面临问题,我对执行此脚本的服务器拥有完全的管理权限。但我无法启动服务。正如 jimtut 所提到的,我只是得到了在非管理部分下显示的输出。为了确认我与我的管理团队核实,他们确认我拥有完整的管理员权限。请帮忙。
    • 你试过我的版本了吗?它可能会输出“StartService() function failed”错误消息,就像它对我一样。您可以添加我提到的附加错误处理来找出它失败的原因,但我会指出问题所在。我发现这是一个用户权限问题。我在 Win7 上对其进行了测试,即使我以管理员权限登录,它也不会重新启动服务,除非/直到我使用 runas 命令以系统级别“管理员”身份运行它,这与普通用户不同提升权限。
    • 嗨@RonBergin 是的,我试过你的版本,它显示“StartService() 函数失败”。在不使用 runas 命令直接通过程序以管理员身份登录后,我们还有其他方法可以启动/停止服务吗?可能吗?我需要做些什么来摆脱这种情况?请建议
    • @jimtut 你能在这方面帮助我吗?当我使用批处理文件调用 Perl 时,我可以看到以管理员身份运行选项。但是为什么我们可以直接以管理员身份运行 Perl 脚本呢?我没有看到任何以管理员身份运行的选项。
    • 我通常以管理员身份打开一个 DOS 提示符,然后当我需要以管理员身份运行时,在该 DOS 窗口中键入命令(像这样)。您还可以创建一个调用 Perl 脚本的 BAT 脚本,然后为 BAT 创建一个快捷方式,并在快捷方式上发送“以管理员身份运行”选项。不确定您是否也可以像这样创建 perl.exe 的快捷方式,但这也可能有效。
    猜你喜欢
    • 2018-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多