PowerShell脚本无法从Windows任务计划程序正常工作

时间:2016-04-27 00:49:02

标签: windows powershell scheduled-tasks sccm

概述: 我有一个脚本用于通过WMI在SCCM中查询新的应用程序请求。在PowerShell控制台中手动启动时,该脚本可以正常工作(无论是否提升,都无关紧要)。我需要通过Task Scheduler运行脚本。目前设置为使用管理员凭据运行,并选中“以最高权限运行”复选框。

问题: 无法从Windows Server 2008 R2中的任务计划程序正确运行。没有报告错误(任务调度程序返回错误代码为0)但它似乎没有超过读取的行:

$GetAppRequest = Get-WmiObject -Class SMS_UserApplicationRequest -Namespace root/SMS/site_$SiteCode | Where-Object {$_.CurrentState -like "1"} | ForEach-Object {

以下是完整的脚本:

#Hard-coded variables
$SiteCode = "MySiteCode"
$ComputerName = "My-SCCM-Server"
$GUIDFilePath = "C:\Scripts\SCCM\GUIDList.txt"
$FilePath = "C:\Scripts\SCCM"
$smtpServers = "smtp1.domainname.com","smtp2.domainname.com"
$reliableSmtpServer = $null
$logpath = "C:\Scripts\SCCM\RequestLog.txt"

#logging functionality
function log($message, $type){
  $date = get-date
  $string = "$date $type : $message" | Out-File $logpath -Append
}

#does log exist?
if (gi -Path $logpath -ErrorAction SilentlyContinue){
  #yep, the log exists!
  $logContent = cat $logpath
  log -message "Script called and log opened for writing." -type "Info"
} else {
  #nope, the log doesn't exist, let's make one.
  write "Can't find log file, creating a new one."
  $newFileResult = New-Item -Path $logpath -ItemType File -ErrorAction Stop
  if ($newFileResult.Exists){
    log -message "new log file created" -type "Info"
  } #end if
} #end else

#Email variables
$from = "no.reply@domainname.com"
$to = "sccm-admin@domainname.com"
$subject = "New SCCM Application Approval Requests"

#Determine which SMTP to use.
$smtpServers | ForEach-Object {
  if ($reliableSmtpServer -eq $null){
    if (Test-Connection -ComputerName $_ -ErrorAction SilentlyContinue){
      write "Reliable SMTP server found: $_"
      $reliableSmtpServer = $_       
    } #end if test-connection
  } #end if reliableSmtpServer exists
} #end foreach SMTP server

if ($reliableSmtpServer){
  log -message "Reliable SMTP server found, $reliableSmtpServer" -type "Info"
} else {
  log -message "No reliable SMTP server could be found" -type "Error"
}

#Get the entries from GUIDList.txt
if ($GetGUID = Get-Content -Path $GUIDFilePath -ErrorVariable guidReadError {
  write "Successfully read $GUIDFilePath"
  log -message "Successfully read $GUIDFilePath" -type "Info"
} else {
  Write-Error -Message "Couldn't read GUIDfile..."
  log -message "Failed to read GUIDFile" -type "Error"
}

#Get all Application Requests with a CurrentState of "1"
log -message 'Attempting to get all Application Requests with a CurrentState of 1' -type "Info"
$GetAppRequest = Get-WmiObject -Class SMS_UserApplicationRequest -Namespace root/SMS/site_$SiteCode | Where-Object {$_.CurrentState -like "1"} | ForEach-Object {
  log -message "App found, $_.Application" -type "Info"
  if ($GetGUID -contains $_.RequestGuid) {
    Write-Host "Application request $($_.RequestGuid) already present"
    log -message "Application request $($_.RequestGuid) already present" -type "Info"
  } else {
    $appUser = $_.User
    $appName = $_.Application
    $appComment = $_.Comments
    $Body = @"
    Application request: $appName
    User: $appUser

    Comment: $appComment
    "@ #This row can't contain any blank spaces or tabs

    log -message "New record found: $appUser, $appName, $appComment" -type "Info"

   #Email configuration
    Send-MailMessage -SmtpServer $reliableSmtpServer -From $from -To $to -Subject $subject -Body $body -ErrorVariable mailError
   if (!($mailError)){
     write "Message successfully sent to : $to"
     log -message "Message successfully sent to : $to" -type "Info"
   } else {
     Write-Error -message "Failed to send email!"
     log -message "Failed to send email!" -type "Error"
   } #end else

   #Append the current objects GUID to GUIDList.txt
   Write "Appending $($_.RequestGUID) to $GUIDFilePath"
   log -message "Appending $($_.RequestGUID) to $GUIDFilePath" -type "Info"
$_.RequestGuid | Out-File $GUIDFilePath -Append

  } #end else statement
} #end forEach

#Remove the GUIDList.txt file and re-create it when there's more than 100 entries
$GUIDCount = $GetGUID.Count
if ($GUIDCount -gt 100) {
  log -message "Greater than 100 GUID entries, clearing list." -type "Info"
  Get-Item $GUIDFilePath | Remove-Item
  New-Item -Path $FilePath -Name GUIDList.txt -ItemType file
}

#Create a new log once the log file exceeds 1000 lines.
$logCount = $logContent.Count
if ($logCount -gt 1000) {
  log -message "Log file is too long, removing log" -type "Warning"
  Remove-Item $logpath
}

以下是计划任务XML:

<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.3" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Date>2014-05-09T17:10:48.6636926</Date>
    <Author>domainname\myUserAccount</Author>
    <Description>Runs a script located at C:\scripts\SCCM to determine if there are any new application requests and notify IT staff via Email.</Description>
  </RegistrationInfo>
  <Triggers>
    <TimeTrigger>
      <Repetition>
        <Interval>PT15M</Interval>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2014-05-09T17:12:04</StartBoundary>
      <ExecutionTimeLimit>PT1H</ExecutionTimeLimit>
      <Enabled>true</Enabled>
    </TimeTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>domain\AdminAccount</UserId>
      <LogonType>Password</LogonType>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>false</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession>
    <UseUnifiedSchedulingEngine>false</UseUnifiedSchedulingEngine>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>P3D</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>powershell.exe</Command>
      <Arguments>-noprofile -file "C:\scripts\sccm\Notify.ps1"</Arguments>
    </Exec>
  </Actions>
</Task>

2 个答案:

答案 0 :(得分:2)

您的意思是将Get-WmiObject ... | Foreach-Object {行的结果分配给 $ GetAppRequest 变量吗?我的意思是Foreach-Object循环的输出被该赋值捕获,因为你不再使用该变量,所以它看起来并不是故意的。

我建议您对变量执行赋值,然后将变量分别传递给Foreach-Object cmdlet,并在其间进行一些登录。此外,我们可以将Get-WmiObject包装在try{}catch{}构造中,以捕获cmdlet可能抛出的任何错误;为了确保捕获错误,我们设置了-ErrorAction Stop

try {
  $GetAppRequest = Get-WmiObject -Class SMS_UserApplicationRequest -Namespace root/SMS/site_$SiteCode -ErrorAction Stop
}
catch {
  log -message "Get-WmiObject cmdlet failed" -type "Error"
  log -message $_.Exception.Message.ToString() -type "Error"
}

if(-not $GetAppRequest) {
  log -message "Failed to retrieve WMI data" -type "Error"

} elseif(-not ($GetAppRequest = $GetAppRequest | Where-Object {$_.CurrentState -like "1"})) {
  log -message "No results with CurrentState = 1" -type "Info"
}

$GetAppRequest | ForEach-Object {
  ...

答案 1 :(得分:-1)

选中“仅在用户登录时运行”并且未选中隐藏复选框。