Das Senden von E-Mails über Powershell (Net.Mail.SmtpClient oder Send-Mailmessage) funktioniert, jedoch nicht, wenn es vom Taskplaner aufgerufen wird

0

Ich habe ein Skript erstellt, um den UPS-Status zu überprüfen, zu protokollieren und eine Benachrichtigungs-E-Mail zu senden. Skript funktioniert gut, wenn es manuell ausgeführt wird, aber wenn es über den Taskplaner ausgeführt wird, wird die E-Mail nicht gesendet . Es macht aber alles andere (zB loggt es sich korrekt in die Datei ein), so dass ich nicht verstehe, was passiert.

Irgendwelche Hinweise und / oder Erklärungen? Danke vielmals!

Hier ist das Skript:

<#
.SYNOPSIS
Skript pro test stavu napájení (AC, nebo UPS)
.DESCRIPTION
Zjistí stav napájení, a pokud to není AC, ale baterie, pole notifikační e-mail. Stejně tak ho pole, pokud ádná baterie připojena není.
.PARAMETER none
no parameters
.EXAMPLE
no example needed
.NOTES
crysman (copyleft) 2016
# changelog:
# ...         next version - don't forget to update the $scriptVersion variable!
# 2016-03-10  přidány barvy výstupů, help, upraveny exit codes a návratové hodnoty, upraven hostname
# 2016-03-09  opraveno logování, vč. loggingu nefunkčních mailnotifikací
# 2016-03-08  initial release
#>
$scriptVersion = '2016-03-10'
$scriptName = $MyInvocation.mycommand.name
$timestamp = [datetime]::now.tostring("yyyy-MM-dd_HH-mm")
$hostName = [system.environment]::MachineName.ToLower()


#funkce pro posílání notifikačních mailů
#v.1.2
function sendEmail($Subject, $Body){
  $EmailTo = "[email protected]"
  $EmailFrom = "$global:[email protected]"
  $SMTPServer = "smtp.XXXYOURFAVOURITEDOMAIN.cz"
  $SMTPClient = New-Object Net.Mail.SmtpClient($SMTPServer, 587)
  $SMTPClient.EnableSsl = $true
  $SMTPClient.Credentials = New-Object System.Net.NetworkCredential("[email protected]", "XXXYOURFAVOURITEPASSWORD");
  $Body = "$Body `n-----`nscript $global:scriptName v.$global:scriptVersion on host $global:hostName`ntimestamp: $global:timestamp"
  #Write-Host $EmailTo $EmailFrom $Subject $Body
  try {
    $SMTPClient.Send([string]$EmailFrom,[string]$EmailTo,[string]$Subject,[string]$Body)
  }
  catch {
    $msg = "$global:timestamp WARNING: notification e-mail has NOT been sent, please check SMTP credentials"
    Write-Host "ERR: " $Error[0].ToString() -ForegroundColor Red
    #následující řádek nefunguje - proč? :( - do souboru se zapisuje, ale na screen ne!
      #Write-Output $msg | Tee -Append -FilePath $global:errorLog
    Write-Host $msg -ForegroundColor Red
    Write-Output $msg | Out-File -Append $global:errorLog
    return $false
  }
  finally {
    $SMTPClient.Dispose()  
  }
  Write-Host "notification e-mail has been sent succesfully" -ForegroundColor Gray
  return $true
}

$scriptDir = "D:\scripts"
$log = "$scriptDir\checkPowerUPS-error.log"
$errorLog = $log


# kategorie stavů baterie viz https://msdn.microsoft.com/en-us/library/aa394074(v=vs.85).aspx
$bStats= @{"1"="battery is discharging";"2"="On AC";"3"="Fully Charged";"4"="Low";"5"="Critical";"6"="Charging";"7"="Charging and High";"8"="Charging and Low";"9"="Charging and Critical";"10"="Undefined";"11"="Partially Charged";} 

# aktuální stav:
$powerStat=Get-WmiObject -class Win32_Battery -ComputerName localhost
$bStat=$powerStat.BatteryStatus
$bStatText=$bStats["$bStat"]
$bStatRemaining=$powerStat.EstimatedRunTime

#zapíeme do EventLogu, popř. poleme mail
#nachystat EventLog
$eLog = $scriptName #pouijeme název skriptu
if (! $eLog) {
  Write-Output "$timestamp něco je patně s powershellem (?)" | tee -Append -FilePath $log
  exit 99  
}
$eLogExists = get-EventLog -LogName Application -Source "$eLog"
if (! $eLogExists){
  echo "WARNING: jetě neexistuje eventlog, vytvářím..."
  new-EventLog -LogName Application -Source "$eLog"
}
#zalogovat a notifikovat
if (!($powerStat) -or $bStat -eq 1 -or $bStat -eq 4 -or $bStat -eq 5) { 
  if(!$powerStat){
    #(nemáme UPS)
    $Subject = "IMPORTANT: Power without UPS on $hostName"
    $Body = "this host seems NOT to be connected to any battery/UPS"
  } else {
    #(UPS máme, ale nějaký non-AC status)
    $Subject = "IMPORTANT: Power failure on $hostName"
    $Body = "battery status is $bStat ($bStatText), estimated remaining battery time: $bStatRemaining min"
  }
  #vypsat na screen a zalogovat:
  Write-Output "$timestamp $Body" | Out-File -Append $log
  Write-Host "$timestamp $Body" -ForegroundColor Red
  Write-EventLog -LogName Application -Source "$eLog" -EntryType Warning -EventId 11 -Message "$eLog skončil neúspěně - $Body"
  #poslat maila:
  $mailsent = sendEmail $Subject $Body
  if ($mailsent) {$exitcode=1} else {$exitcode=2}
} else {
  $exitcode = 0
  Write-Host "OK, $hostName is on AC (status $bStat)`nscript $scriptName v.$scriptVersion" -ForegroundColor Green
}
exit $exitcode

Hier ist die Aufgabe:

<Task xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task" version="1.2">
<RegistrationInfo>
<Date>2016-03-07T16:53:24.9000439</Date>
<Author>SERVER-XXX\myadminaccount</Author>
</RegistrationInfo>
<Triggers>
<CalendarTrigger>
<Repetition>
<Interval>PT1M</Interval>
<StopAtDurationEnd>false</StopAtDurationEnd>
</Repetition>
<StartBoundary>2016-03-07T00:00:00</StartBoundary>
<Enabled>true</Enabled>
<ScheduleByDay>
<DaysInterval>1</DaysInterval>
</ScheduleByDay>
</CalendarTrigger>
</Triggers>
<Principals>
<Principal id="Author">
<UserId>SERVER-XXX\myadminaccount</UserId>
<LogonType>Password</LogonType>
<RunLevel>HighestAvailable</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>StopExisting</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>true</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT1H</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command>powershell</Command>
<Arguments>
-NonInteractive -Noprofile -Command "&{D:\scripts\checkPowerUPS.ps1}"
</Arguments>
</Exec>
</Actions>
</Task>

Betriebssystem: Windows Server 2012 R2

PS: Ich habe sowohl Technet als auch verschiedene Stack Exchange-Sites durchsucht, um dieses Problem zu lösen, aber kein Glück: / Also versuche ich es hier ...

Crysman
quelle
Ein bisschen off-topic, aber ich frage mich, warum Sie die .NET SmtpClientKlasse verwenden, um E-Mails anstelle der nativen Send-MailmessageCmd-Let zu senden ?
Smeerpijp
@doenoe Weil ich nicht herausgefunden habe, wie die Authentifizierung mit diesem Cmd-Let angewendet wird. Wenn Sie wissen, wie, lassen Sie es mich wissen.
Crysman
Schauen Sie sich diesen TechNet-Artikel an. Es gibt einen -CredentialParameter. Es gibt auch ein Beispiel in dem Artikel:send-mailmessage -to "User01 <[email protected]>" -from "ITGroup <[email protected]>" -cc "User02 <[email protected]>" -bcc "ITMgr <[email protected]>" -subject "Don't forget today's meeting!" -credential domain01\admin01 -useSSL
Smeerpijp
OK, ich habe zu Send-MailMessage cmd-let gewechselt. Es hat sich jedoch nichts geändert. Das manuelle Ausführen erledigt alles wie erwartet, einschließlich des Versendens der Benachrichtigungs-E-Mail. Der Taskplaner meldet den Beendigungscode 0, alles scheint in Ordnung zu sein, das Dateiprotokoll enthält neue Zeilen, die Systemereignisanzeige enthält neue Protokolle, es wird jedoch KEINE E-MAIL gesendet! :(
Crysman
Hmm, auch ich habe ein Sched - Aufgabe das ist , bekam läuft ein PS - Skript, und sendet eine E - Mail , wenn Sie fertig, das ist meine Aufgabe Parameter in der Registerkarte Aktionen Programm Skript sind: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exeArgumente: -command "& 'C:\Scripts\asabackup\asabackup.ps1'"Starten Sie in: C:\Scripts\asabackup Vielleicht können Sie Ihre Werte einstellen Mine übereinstimmen ( mit
Ihrem

Antworten:

1

Nach stundenlangem Debuggen habe ich es verstanden.

Das Problem:

Verwendung des -Command "..."Arguments im Taskplaner.

Lösung:

Verwenden Sie -File "..."stattdessen ein Argument. In diesem speziellen Fall wäre das:

<Exec>
<Command>powershell</Command>
<Arguments>
-NonInteractive -Noprofile -File "D:\scripts\checkPowerUPS.ps1"
</Arguments>
</Exec>

Einzelheiten:

Bei Verwendung -Command "&{D:\testScript.ps1}"sind im Skript deklarierte globale Variablen nicht verfügbar, das heißt, dies funktioniert beispielsweise nicht:

$myVar = "ham"
function myF(){
  Write-Output $global:myVar
}
myF

Ich habe keine Antwort auf meine Fehler-gelöst-folgende Frage gefunden: „Was ist der Unterschied zwischen -Commandund -File? Powershell Argument“ Das Aufrufen powershell /?hilft mir sowieso nicht, weil es nichts über globale und / oder irgendwelche "semiglobalen" Variablen aussagt. Darüber hinaus heißt es, dass mit -Command:

... Führt die angegebenen Befehle (und alle Parameter) so aus, als ob sie an der Windows PowerShell-Eingabeaufforderung eingegeben worden wären ...

Das ist nicht wahr, weil das Starten eines neuen PowerShell-Fensters und das Ausführen der Zeilen, die ich im obigen Beispielcode mit $ myVar eingegeben habe, funktionieren wird, während das Ausführen des Beispiels mit -Command ...NOT.

Ich hoffe, dies wird dir helfen.

Crysman
quelle
Anscheinend liegt die Ursache des Problems genau dort, wo Invoke-Commandeine Grenze zwischen lokal und entfernt gezogen wird. (Ich Invoke-Commandgehe davon aus, dass der -CommandParameter von PowerShell im Hintergrund verwendet wird.) Möglicherweise können Sie -ArgumentList(in der Mitte dieser Dokumentation ) das Problem umgehen.
Jpaugh