内存不足,无法继续执行程序。从CSV创建Xlx

时间:2019-02-05 08:19:33

标签: excel powershell

我有一个脚本,该脚本在一个文件夹中循环,并将多个CSV压缩为一个xlsx文件,并以CSV名称作为工作表。但是,当脚本作为较大脚本的一部分运行时,刷新查询时将失败。

$Query.Refresh()

脚本本身运行良好,但是将脚本添加到较大的脚本时会失败。谁能说出为什么会这样吗?

以下是我得到的错误:

Insufficient memory to continue the execution of the program.
At C:\Temp\Scripts\Shares_Complete.psm1:254 char:13
+             $Query.Refresh()
+             ~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (:) [], OutOfMemoryException
    + FullyQualifiedErrorId : System.OutOfMemoryException

我用相同的代码尝试了单个csv,结果仍然相同。

$script:SP = "C:\Temp\Servers\"

$script:TP = "C:\Temp\Servers\Pc.txt"
$script:FSCSV = "C:\Temp\Server_Shares\Server Lists\"
$script:Message1 = "Unknown Hosts"
$script:Message2 = "Unable to connect"
$script:Message3 = "Unknown Errors Occurred"
$script:Txt = ".txt"
$script:OT = ".csv"
$script:FSERROR1 = $FSCSV+$Message1+$OT
$script:FSERROR2 = $FSCSV+$Message2+$OT
$script:FSERROR3 = $FSCSV+$Message2+$OT

$script:ERL3 = $E4 + "Shares_Errors_$Date.txt"
$script:ECL1 = $E4 + "Shares_Exceptions1_$Date.txt"
$script:ERL1 = $E4 + "Shares_Errors1_$Date.txt"
$script:ECL3 = $E4 + "Shares_Exceptions_$Date.txt"

function Excel-Write {
    if ($V -eq "1") {
        return
    }

    [System.GC]::Collect()
    $RD = $FSCSV + "*.csv" 
    $CsvDir = $RD 
    $Ma4 = $FSCSV + "All Server Shares for Domain $CH4"
    $csvs = dir -path $CsvDir # Collects all the .csv's from the driectory 
    $FSh = $csvs | Select-Object -First 1
    $FSh = ($FSh -Split "\\")[4]
    $FSh = $FSh -replace ".{5}$"
    $FSh
    $outputxls = "$Ma4.xlsx"
    $script:Excel = New-Object -ComObject Excel.Application
    $Excel.DisplayAlerts = $false
    $workbook = $excel.Workbooks.Add()
    # Loops through each CVS, pulling all the data from each one
    foreach ($iCsv in $csvs) {
        $script:iCsv
        $WN = ($iCsv -Split "\\")[-1]
        $WN = $WN -replace ".{4}$"
        if ($WN.Length -gt 30) {
            $WN = $WN.Substring(0, [Math]::Min($WN.Length, 20))
        }
        $Excel = New-Object -ComObject Excel.Application
        $Excel.DisplayAlerts = $false
        $Worksheet = $workbook.Worksheets.Add()
        $Worksheet.Name = $WN

        $TxtConnector = ("TEXT;" + $iCsv)
        $Connector = $worksheet.Querytables.Add($txtconnector,$worksheet.Range("A1"))
        $query = $Worksheet.QueryTables.Item($Connector.Name)

        $query.TextfileOtherDelimiter = $Excel.Application.International(5)

        $Query.TextfileParseType = 1
        $Query.TextFileColumnDataTypes = ,2 * $worksheet.Cells.Column.Count
        $query.AdjustColumnWidth = 1

        $Query.Refresh()
        $Query.Delete()
        $Worksheet.Cells.EntireColumn.AutoFit()
        $Worksheet.Rows.Item(1).Font.Bold = $true
        $Worksheet.Rows.Item(1).HorizontalAlignment = -4108
        $Worksheet.Rows.Item(1).Font.Underline = $true
        $Workbook.Save()
    }
    $Empty = $workbook.Worksheets.Item("Sheet1")
    $Empty.Delete()
    $Workbook.SaveAs($outputxls,51)
    $Workbook.Close()
    $Excel.Quit()
    $ObjForm.Close()
    Delete
}

应继续执行脚本并创建xlsx。

1 个答案:

答案 0 :(得分:2)

看着您的脚本,您最终用完内存不足为奇,因为您一直在创建Com对象,并且从不释放它们。

每当创建完Com对象并完成处理后,请使用以下这些行释放内存:

$Excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()

也请仔细看一下代码。
您正在$Script:Excel = New-Object -ComObject excel.application循环之前创建一个foreach对象,但是您没有使用它。相反,您是在循环内一次又一次创建新的Excel和工作簿对象,这完全没有理由,因为您可以重复使用在循环前创建的对象。

顺便说一句:Excel工作表名称中不允许使用以下字符

\/?*[]:

长度限制为31个字符。


编辑


我查看了您的项目,尤其是Shares_Complete.psm1文件。
尽管我当然不愿意重写您的整个项目,但我确实有一些建议可以帮助您:

  1. [System.Net.Dns]::GetHostByName()已过时。使用GetHostEntry()
  2. 使用Windows窗体完成操作后,请使用$ObjForm.Dispose()从内存中清除它
  3. 您无缘无故地做[System.GC]::Collect(); [System.GC]::WaitForPendingFinalizers()
  4. 为什么不使用[System.Windows.MessageBox]::Show()而不是Com对象$a = new-object -comobject wscript.shell。再次,您将该对象留在内存中徘徊。
  5. 使用Join-Path cmdlet代替$RD = $FSCSV + "*.csv"$Cop = $FSCSV + "*.csv"构造
  6. 从Excel工作表名称(replace '[\\/?*:[\]]', '')中删除无效字符
  7. 为函数使用Verb-Noun名称,以便清楚地知道它们的作用。现在您有了LocationDeleteFile之类的功能,什么都没有意义
  8. 您正在像在第65行中那样定义函数之前调用函数,在第65行中,您调用函数Shares。那时它还不存在,因为函数本身是在第69行中编写的。
  9. 在功能[System.Runtime.Interopservices.Marshal]::ReleaseComObject($worksheet) | Out-Null中添加Excel-Write
  10. 不需要在脚本作用域($Excel)中使用变量$Script:Excel = New-Object -ComObject excel.application,该变量仅在函数的本地使用。
  11. 您可能需要查看Excel specifications and limits
  12. 修正代码缩进,以便在循环或开始和结束时都清楚
  13. 我建议使用更有意义的变量名。对于局外人甚至几个月后的您自己来说,两个字母的变量名变得令人困惑