PowerShellとPythonを使用したWindowsサービスの監視

画像

背景:

私自身は、カナダのトロントにある証券会社の技術部門で働いています。 また、カルガリーに別のオフィスがあります。 どういうわけか、リモートオフィスの単一のドメインコントローラーにWindows更新プログラムを計画的にインストールした後、外部ソースとの時刻の同期を担当するW32Timeサービスが開始されませんでした。 したがって、約1週間以内に、サーバーの時間が約20秒失われました。 そのときのデフォルトのワークステーションは、コントローラーから時間を受け取りました。 あなたは何が起こったか理解しています。 入札時間は非常に重要であり、秒単位の差は多くの問題を解決できます。 残念ながら、最初の時間差はブローカーによって気づかれました。 基本的に3人で構成されるテクニカルサポート部門がこれに割り当てられました。 何かをすることが急務でした。 解決策は、CentOSを実行している内部NTPサーバーにすべてのマシンを送信するグループポリシーを適用することでした。 ドメインコントローラをWebフィルタに接続するサービスであるDC Barracuda Agentにはまだ問題があり、いくつかのサービスが不安を引き起こすことがありました。 それにもかかわらず、私たちはいくつかのサービスを追跡するために何かを考え出すことにしました。 私は少しグーグルで調べて、多くの解決策があり、ほとんどがこの問題のために商業的であることに気づきましたが、ある種のスクリプト言語を学びたかったので、私たちのローカルLinux達人を使ってPythonでスクリプトを書くことを志願しました。 その後、すべてのサービスをチェックし、その可用性とステータスを目的のサービスのリストと比較するスクリプトに変わりました。残念ながら、これらのサービスはマシンごとに個別に手動で実行する必要があります。



解決策:



Windowsサーバーの1つで、この種のPowerShellスクリプトを作成しました。

echo "Servername" > C:\Software\Services\Servername.txt get-date >> C:\Software\Services\Servername.txt Get-Service -ComputerName Servername | Format-Table -Property status, name >> C:\Software\Services\Servername.txt
      
      







私の場合、各サーバーにこのようなピースが10個ありました



次のバッチファイルがタスクスケジューラに追加されました(PowerShellスクリプトをそこから直接実行するよりも簡単に思えました)。



 powershell.exe C:\Software\Services\cal01script.ps1
      
      







現在、私は毎日、同様の形式の各サーバーの個別のファイルにすべてのサービスのリストを受け取りました。



 Servername Friday, October 26, 2012 1:24:03 PM Status Name ------ ---- Stopped Acronis VSS Provider Running AcronisAgent Running AcronisFS Running AcronisPXE Running AcrSch2Svc Running ADWS Running AeLookupSvc Stopped ALG Stopped AppIDSvc Running Appinfo Running AppMgmt Stopped aspnet_state Stopped AudioEndpointBuilder Stopped AudioSrv Running Barracuda DC Agent Running BFE Stopped BITS Stopped Browser Running CertPropSvc Running WinRM Stopped wmiApSrv Stopped WPDBusEnum Running wuauserv Stopped wudfsvc
      
      







今最も重要な部分。 CentOSを搭載した別のマシンで、このスクリプトを作成しました。



 import sys import smtplib import string from sys import argv import os, time import optparse import glob # function message that defines the email we get about the status def message(subjectMessage,msg): SUBJECT = subjectMessage FROM = "address@domain.com" TO = 'address@domain.com' BODY = string.join(( "From: %s" % FROM, "To: %s" % TO, "Subject: %s" % SUBJECT , "", msg ), "\r\n") s = smtplib.SMTP('mail.domain.com') #s.set_debuglevel(True) s.sendmail(FROM, TO, BODY) s.quit() sys.exit(0) def processing(runningServicesFileName,desiredServicesFileName): try: desiredServicesFile=open(desiredServicesFileName,'r') except (IOError,NameError,TypeError): print "The list with the desired state of services either does not exist or the name has been typed incorrectly. Please check it again." sys.exit(0) try: runningServicesFile=open(runningServicesFileName,'r') except (IOError,NameError,TypeError): print "The dump with services either does not exist or the name has been typed incorrectly. Please check it again." sys.exit(0) #Defining variables readtxt = desiredServicesFile.readlines() desiredServices = [] nLines = 0 nRunning = 0 nDesiredServices = len(readtxt) faultyServices = [] missingServices = [] currentServices = [] serverName = '' dumpdate='' errorCount=0 # Trimming file in order to get a list of desired services. Just readlines did not work putting \n in the end of each line for line in readtxt: line = line.rstrip() desiredServices.append(line) # Finding the number of currently running services and those that failed to start for line in runningServicesFile: nLines+=1 # 1 is the line where I append the name of each server if nLines==1: serverName = line.rstrip() # 3 is the line in the dump that contains date if nLines==3: dumpdate=line.rstrip() # 7 is the first line that contains valueable date. It is just the way we get these dumps from Microsoft servers. if nLines<7: continue # The last line in these dumps seems to have a blank character that we have to ignore while iterating. if len(line)<3: break line = line.rstrip(); serviceStatusPair = line.split(None,1) currentServices.append(serviceStatusPair[1]) if serviceStatusPair[1] in desiredServices and serviceStatusPair[0] == 'Running': nRunning+=1 if serviceStatusPair[1] in desiredServices and serviceStatusPair[0] != 'Running': faultyServices.append(serviceStatusPair[1]) if nLines==0: statusText='Dumps are empty on %s' % (serverName) detailsText='Dumps are empty' # Checking if there are any missing services for i in range(nDesiredServices): if desiredServices[i] not in currentServices: missingServices.append(desiredServices[i]) # Sending the email with results if nRunning == nDesiredServices: statusText='%s: OK' % (serverName) detailsText='%s: OK\nEverything works correctly\nLast dump of running services was taken at:\n%s\nThe list of desired services:\n%s\n' % (serverName,dumpdate,'\n'.join(desiredServices)) else: statusText='%s: Errors' % (serverName) detailsText='%s: Errors\n%s out of %s services are running.\nServices failed to start:%s\nMissing services:%s\nLast dump of the running services was taken at:\n%s\n' % (serverName,nRunning,nDesiredServices,faultyServices,missingServices,dumpdate) errorCount=errorCount+1 return (statusText,detailsText,errorCount) # Defining switches that can be passed to the script usage = "type -h or --help for help" parser = optparse.OptionParser(usage,add_help_option=False) parser.add_option("-h","--help",action="store_true", dest="help",default=False, help="this is help") parser.add_option("-d","--desired",action="store", dest="desiredServicesFileName", help="list of desired services") parser.add_option("-r","--running",action="store", dest="runningServicesFileName", help="dump of currently running services") parser.add_option("-c","--config",action="store", dest="configServicesDirectoryName", help="directory with desired services lists") (opts, args) = parser.parse_args() # Outputting a help message and exiting in case -h switch was passed if opts.help: print """ This script checks all services on selected Windows machines and sends out a report. checkServices.py [argument 1] [/argument 2] [/argument 3] Arguments: Description: -c, --config - specifies the location of the directory with desired list of services and finds dumps automatically -d, --desired - specifies the location of the file with the desired list of services. -r, --running - specifies the location of the file with a dump of running services. """ sys.exit(0) statusMessage = [] detailsMessage = [] body = [] errorCheck=0 directory='%s/*' % opts.configServicesDirectoryName if opts.configServicesDirectoryName: check=glob.glob(directory) check.sort() if len(check)==0: message('Server status check:Error','The directory has not been found. Please check its location and spelling.') sys.exit(0) for i in check: desiredServicesFileName=i runningServicesFileName=i.replace('desiredServices', 'runningServices') #print runningServicesFileName status,details,errors=processing(runningServicesFileName,desiredServicesFileName) errorCheck=errorCheck+errors statusMessage.append(status) detailsMessage.append(details) body='%s\n\n%s' % ('\n'.join(statusMessage),'\n'.join(detailsMessage)) if errorCheck==0: message('Server status check:OK',body) else: message('Server status check:Errors',body) if opts.desiredServicesFileName or opts.desiredServicesFileName: status,details,errors=processing(opts.runningServicesFileName,opts.desiredServicesFileName) message(status,details)
      
      







目的のサービスのダンプファイルとリストファイルは同じ名前にする必要があります。 監視しているサービス(desiredServices)のリストは次のようになります。



 Acronis VSS Provider AcronisAgent AcronisFS AcrSch2Svc
      
      







スクリプトはサービスをチェックし、これをすべて1つの電子メールメッセージに作成します。結果に応じて、メッセージの件名にすべての順序が整っているか、エラーがあり、メッセージ本文にエラーがあることを明らかにします。 私たちにとっては、1日1回のチェックで十分なので、早朝にWindowsサーバーのステータスに関する通知を受け取ります。 WindowsサーバーからLinuxマシンにファイルをコピーするために、同僚は次のbashスクリプトを手伝ってくれました。



 #!/bin/bash mkdir runningServices smbclient --user="user%password" "//ServerName.domain.com/software" -c "lcd runningServices; prompt; cd services; mget *.txt" cd runningServices for X in `ls *.txt`; do iconv -f utf16 -t ascii $X > $X.asc mv $X.asc $X done
      
      







このスクリプトはエンコードも変更します。私のマシンではLinuxがUTF16を実際に使用したくなかったためです。 さらに、サービスを含むダンプからフォルダーを削除するために、バッチファイルをタスクスケジューラに追加して、ダンプを消去するPowerShellスクリプトを実行しました。

ボディシャツ:

 powershell.exe C:\Software\Services\delete.ps1
      
      







Poweshellスクリプト:

 remove-item C:\Software\Services\ServerName.txt
      
      







このプロジェクトは、サービスの監視とPythonのトレーニングという2つの目標を追求しました。 これはHabréに関する私の最初の投稿なので、すでに私のアドレスには批判の流入が予想されます。 特にこのシステムの改善に関してコメントがあれば、歓迎します。 私はこのようなソリューションを無料でメール通知で見つけられなかったので、この記事が誰かに役立つように願っています。 たぶん彼はひどく見ていました。



All Articles