1

当我使用以下命令从命令提示符手动执行它时,我有一个完美运行的 powershell 脚本:

powershell -NoLogo -NonInteractive -File "D:\ServerFolders\Company\Scripts\Powershell Scripts\SendMonthlyGrowthRateReport.ps1"

该脚本正在打开一个 Excel 电子表格,从 SQL 中将一些数据提取到电子表格中,保存一份带有当前日期的电子表格副本,然后通过 SQL sp_send_dbmail 将电子表格通过电子邮件发送出去。它还将当前状态记录到日志文件中。

现在我在 Windows 2012 R2 上设置了一个计划任务,每月执行一次上述命令,但是当我手动运行任务或尝试让它自行启动时,只生成日志文件,电子表格没有保存并通过电子邮件发送从不出门。
有任何想法吗?

更新:下面是脚本中的代码,我还应该注意powershell在通过计划任务执行时返回退出代码0......

$DebugPreference = 2
$VerbosePreference = 2
$WarningPreference = 2
#param([string] $TemplateFilePath = "TemplateFilePath", 
#    [string]$StorageRoot = "StorageRoot",
#    [string]$NameFormat = "NameFormat",
#    [string]$ReportType = "ReportType",
#    [string] $SendReportTo = "SendReportTo")

$TemplateFilePath = 'D:\ServerFolders\Company\Spreadsheets\templates\DatabaseGrowthTemplate.xlsx'
$StorageRoot = 'D:\ServerFolders\Company\Spreadsheets'
$NameFormat = '%type% Database Growth Report %date%.xlsx'
$ReportType = "Monthly"
$SendReportTo ="*******@someDomain.com"

$Date = get-Date
$LogFile = "D:\ServerFolders\Company\SyncLogs\MonthlyGrowthReport" + $Date.toString("yyyy-MM-dd hhmmss") + ".log"

Function LogWrite
{
   Param ([string]$logstring)
   $date =  get-date
   $DateString = $date.toString("yyyy-MM-dd hh:mm:ss")
   $FileValue = $DateString +' - ' + $logstring
   if($LogFile -ne $null -and $LogFile -ne "")
   {
        Add-content $Logfile -value $FileValue
   }

   Write-Host $FileValue
}

if ($ReportType -ne 'Weekly' -and $ReportType -ne 'Monthly' -and $ReportType -ne 'Quarterly' -and $ReportType -ne 'Yearly')
{
    Write-Host "Valid options for ReportType parameter are 'Weekly', 'Monthly', 'Quarterly', or 'Yearly'"
    exit
}

$Date = get-Date
$DateString = $Date.ToString("yyyy-MM-dd")

$FromDate = $DateString
$FileName = $NameFormat.Replace("%date%", $DateString)
$FileName = $FileName.Replace("%type%", $ReportType)

$Destination = join-path $StorageRoot $FileName

$LogWrite = "Generate Destination File of " + $Destination
LogWrite $LogWrite

$IncrementType ="Days"
if ($ReportType -eq "Weekly"){
    $IncrementType = "Weeks"
} 
if ($ReportType -eq "Monthly"){
    $IncrementType = "Months"
} 
if ($ReportType -eq "Quarterly"){
    $IncrementType = "Quarters"
} 
if ($ReportType -eq "Yearly") {
    $IncrementType = "Years"
}
$IncrementBackValue = -1

## Connect to the target SQL Server and run the query to refresh data
$cstr = "Server=SERVERNAME\INSTANCENAME;Database=Logging;Trusted_Connection=True;"
$cn = new-object system.data.SqlClient.SqlConnection($cstr);
LogWrite "Connecting to SQL"
$cn.Open()

#Query the first date from using the built-in function  
$dateQuery = "SELECT [dbo].[ufn_getIncrementBackDate]('$DateString', '${IncrementType}', ${IncrementBackValue}) as [StartDate]"

$cmd1 = New-Object System.Data.SqlClient.SqlCommand($dateQuery, $cn)
$DateDS = $cmd1.ExecuteReader();
while($DateDS.Read()){
    $StartDate = $DateDS.GetDateTime(0)
}
$DateDS.Close()

#Copy isn't needed Open the template and then at the End do a save as


LogWrite "Opening Excel workbook..."
# Open the Excel document and pull in the 'Data' worksheet
$Excel = New-Object -Com Excel.Application
$Workbook = $Excel.Workbooks.Open($TemplateFilePath) 
$page = 'Data'
$ws = $Workbook.worksheets | where-object {$_.Name -eq $page}
# Delete the current contents of the page
$ws.Cells.Clear() | Out-Null

LogWrite "Generating Report Data..."
#Prepare adapter objects for reading info into Excel
$ds = new-object "System.Data.DataSet" "dsProductData"
$q = "usp_GenerateDatabaseSizeReport @FirstDate='$StartDate'"
$da = new-object "System.Data.SqlClient.SqlDataAdapter" ($q, $cn)
$da.Fill($ds) | Out-Null
$dtProduct = $ds.Tables[0]

# Set variables for the worksheet cells, and for navigation
$cells=$ws.Cells
$row=1
$col=1
$MaxCol = 1
$MaxRow = 1

LogWrite "Populating Data worksheet.."
#Fill Headers
foreach($column in $dtProduct.Columns){
    $cells.item($row, $col) = $column.ColumnName
    if ($col -gt $MaxCol){
        $MaxCol = $col
    }
    $col++
}

# Add the results from the DataTable object to the worksheet
foreach($dataRow in $dtProduct){
    $row++
    $col = 1
    foreach($column in $dtProduct.Columns)
    {
        if ($col -eq 1){
            $cells.item($row, $col) = $dataRow[$column.ColumnName].ToString()
        } else {
            $cells.item($row, $col) = $dataRow[$column.ColumnName].ToString()
        }
        $col++
    }
    if ($row -gt $MaxRow){
        $MaxRow = $row
    }
}

LogWrite "Finished populating Data..."

# Set the width of the columns automatically
$ws.columns.item("A:Z").EntireColumn.AutoFit() | out-null
#Format Date Column
$ws.Range("A2:A1000").NumberFormat ="m/d/yyyy"

#Create the Line Chart's 
$ColumnLetter = "A"


if ($MaxCol -eq 1) { $ColumnLetter = "A" }
if ($MaxCol -eq 2) { $ColumnLetter = "B" }
if ($MaxCol -eq 3) { $ColumnLetter = "C" }
if ($MaxCol -eq 4) { $ColumnLetter = "D" }
if ($MaxCol -eq 5) { $ColumnLetter = "E" }
if ($MaxCol -eq 6) { $ColumnLetter = "F" }
if ($MaxCol -eq 7) { $ColumnLetter = "G" }
if ($MaxCol -eq 8) { $ColumnLetter = "H" }
if ($MaxCol -eq 9) { $ColumnLetter = "I" }
if ($MaxCol -eq 10) { $ColumnLetter = "J" }
if ($MaxCol -eq 11) { $ColumnLetter = "K" }
if ($MaxCol -eq 12) { $ColumnLetter = "L" }
if ($MaxCol -eq 13) { $ColumnLetter = "M" }
if ($MaxCol -eq 14) { $ColumnLetter = "N" }
if ($MaxCol -eq 15) { $ColumnLetter = "O" }
if ($MaxCol -eq 16) { $ColumnLetter = "P" }
if ($MaxCol -eq 17) { $ColumnLetter = "Q" }
if ($MaxCol -eq 18) { $ColumnLetter = "R" }
if ($MaxCol -eq 19) { $ColumnLetter = "S" }
if ($MaxCol -eq 20) { $ColumnLetter = "T" }
if ($MaxCol -eq 21) { $ColumnLetter = "U" }
if ($MaxCol -eq 22) { $ColumnLetter = "V" }
if ($MaxCol -eq 23) { $ColumnLetter = "W" }
if ($MaxCol -eq 24) { $ColumnLetter = "X" }
if ($MaxCol -eq 25) { $ColumnLetter = "Y" }
if ($MaxCol -eq 26) { $ColumnLetter = "Z" }


$RangeString = "A1:"+$ColumnLetter
#$RangeString
$RangeString =$RangeString + $MaxRow
#$RangeString
$range = $ws.range($RangeString)

LogWrite "Performing Chart updates."

$page = "Chart"
$ws = $Workbook.worksheets | where-object {$_.Name -eq $page}
foreach($Shape in $ws.Shapes){
    if ($Shape.HasChart){
        $chart = $Shape.Chart
        break


}

if ($chart -ieq $null){
    Write-Host "Can't find chart!!!"
} else {
    $chart.SetSourceData($range)
}


LogWrite "Saving updated copy of Excel workbook."

# Close the workbook and exit Excel
$Workbook.SaveAs($Destination)
$workbook.Close($true)
$excel.quit()

$DestinationFileO = New-Object System.IO.FileInfo($Destination)
$EmailSubject = $DestinationFileO.Name.Replace($DestinationFileO.Extension, "")

LogWrite "Sending Excel Workbook via email."

#Send an email to operator with report
$SendEmailCmdText ="exec msdb..sp_send_dbmail @profile_name='GMail'
    , @recipients = '${SendReportTo}'
    , @subject = '${EmailSubject}'
    , @body = 'Attached is the $EmailSubject for database server [HOMEGROWNSERVER\TFSSQL].'
    , @file_attachments = '${Destination}'
    --, @query_result_header = 1
    --, @query_result_separator=','
    --, @query_result_width = 32767
    --, @append_query_error = 1
    --, @query_result_no_padding = 1"



$cmd2 = New-Object System.Data.SqlClient.SqlCommand($SendEmailCmdText, $cn)
$cmd2.ExecuteNonQuery()
$cn.Close()
LogWrite "Process Complete"
4

1 回答 1

2

您最可能的问题是打开 Excel 需要一个交互式会话。

$Excel = New-Object -Com Excel.Application
$Workbook = $Excel.Workbooks.Open($TemplateFilePath) 

当您将脚本作为计划作业运行时,这些行将失败。我所知道的; 在 Windows 2012 R2 中;让它工作的唯一方法是将计划作业设置为“仅在用户登录时运行”并让用户保持登录状态。

很抱歉没有回答,但我还没有找到解决方法。

于 2015-03-12T03:29:26.710 回答