L'envoi de courrier électronique via powershell (Net.Mail.SmtpClient ou Send-Mailmessage) fonctionne, mais pas lorsqu'il est appelé par le planificateur de tâches

0

J'ai rédigé un script pour vérifier l'état de l'onduleur, le consigner et envoyer un e-mail de notification. Le script fonctionne correctement s'il est exécuté manuellement, mais lorsqu'il est exécuté via le Planificateur de tâches, il n'envoie pas le courrier électronique . Cependant, il fait tout le reste (par exemple, il se connecte correctement dans le fichier), donc je ne comprends pas ce qui se passe.

Un indice et / ou une explication? Merci beaucoup!

Voici le script:

<#
.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

Voici la tâche:

<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>

Système d'exploitation: Windows Server 2012 R2

PS: J'ai parcouru Technet et divers sites de Stack Exchange pour résoudre ce problème, mais pas de chance: / Alors, essayez ici ...

gardien
la source
Un peu hors sujet, mais je me demande, pourquoi utilisez-vous la .NET SmtpClientclasse pour envoyer un courrier électronique au lieu du Send-Mailmessagecmd-let natif ?
Smeerpijp
@doenoe Parce que je n'ai pas compris comment appliquer l'authentification à l'aide de cette cmd-let. Si vous savez comment, faites le moi savoir.
Crysman
Jetez un coup d'œil à cet article TechNet. Il y a un -Credentialparamètre. Il y a aussi un exemple dans l'article: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, je suis passé à Send-MailMessage cmd-let. Cependant, rien n'a changé. L’exécution manuelle fait tout ce qui est supposé, y compris l’envoi du courrier électronique de notification. Le planificateur de tâches indique le code de sortie 0, tout semble aller pour le mieux, il y a de nouvelles lignes dans le journal de fichiers, il y a de nouveaux journaux dans l'observateur d'événements du système, mais AUCUN E-MAIL n'est envoyé! :(
crysman
Hmm, eh bien, j’ai une tâche de planification qui exécute un script PS et envoie un mail une fois terminé. Voici les paramètres de ma tâche dans le script de programme d’onglet Actions: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exeArguments: -command "& 'C:\Scripts\asabackup\asabackup.ps1'"Démarrer dans: C:\Scripts\asabackup Vous pouvez peut-être ajuster vos valeurs pour les faire correspondre aux miennes ( avec votre propre répertoire de travail, etc.) et testez-le à nouveau
Smeerpijp

Réponses:

1

Après des heures de débogage, je l'ai.

Le problème:

utilisation de l' -Command "..."argument dans le planificateur de tâches.

Solution:

Utilisez l' -File "..."argument à la place. Dans ce cas particulier, ce serait:

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

Détails:

Lors de l'utilisation -Command "&{D:\testScript.ps1}", les variables globales déclarées dans le script ne sont pas disponibles, c'est-à-dire que cela ne fonctionnera pas:

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

Je n'ai pas trouvé de réponse à ma question suivante concernant la résolution de bugs: "Quelle est la différence entre un argument -Commandet -FilePowerShell?" Invoquer powershell /?ne m'aide pas de toute façon, car il ne dit rien sur les variables globales et / ou "semi-globales". En outre, il est indiqué que l'utilisation de -Command:

... Exécute les commandes spécifiées (et tous les paramètres) comme si elles avaient été saisies à l'invite de commandes Windows PowerShell ...

Ce qui est faux, car démarrer une nouvelle fenêtre PowerShell et exécuter les lignes que j'ai insérées dans l'exemple de code ci-dessus avec $ myVar fonctionnera, alors que l'exécution de l'exemple avec -Command ...NOT ne sera pas.

J'espère que cela t'aidera.

gardien
la source
On dirait que la source du problème est exactement où Invoke-Commandtrace une ligne entre local et distant. (Je suppose que cela Invoke-Commandest utilisé en coulisse pour le -Commandparamètre de PowerShell .) Vous pourrez peut-être utiliser -ArgumentList(à mi-chemin de cette documentation ) pour contourner le problème.
Jpaugh