>source

폴더를 순환하고 CSV 이름을 워크 시트로 사용하여 여러 CSV를 하나의 xlsx 파일로 압축하는 스크립트가 있습니다. 그러나 스크립트가 더 큰 스크립트의 일부로 실행되면 쿼리를 새로 고치면 실패합니다.

$Query.Refresh()

자체적으로 스크립트가 제대로 실행되지만 더 큰 스크립트에 추가하면 실패합니다. 누구든지 이것이 왜 그런지 조언 해 줄 수 있습니까?

아래 오류는 다음과 같습니다.

프로그램 실행을 계속하기위한 메모리가 부족합니다.
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

    스크립트를 보면 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 및 통합 문서 개체를 반복해서 만들고 있습니다.

    제외 : 엑셀 워크 시트 이름에는 다음 문자를 사용할 수 없습니다

    \/?*[]:
    
    

    길이 제한은 31 자입니다.

    <시간> 수정

    <시간>

    귀하의 프로젝트와 특히 Shares_Complete.psm1 를 살펴 보았습니다.  파일.
    물론 전체 프로젝트를 다시 작성하지는 않겠지 만 도움이 될만한 몇 가지 언급이 있습니다.

      [System.Net.Dns]::GetHostByName()  더 이상 사용되지 않습니다. GetHostEntry () 사용

      Windows 양식으로 작업 할 때는 $ObjForm.Dispose() 를 사용하십시오.  메모리에서 지우려면

      당신은 많은 [System.GC]::Collect(); [System.GC]::WaitForPendingFinalizers() 를  아무 이유없이

      [System.Windows.MessageBox]::Show() 를 사용하지 않는 이유  Com 객체 $a = new-object -comobject wscript.shell 를 사용하는 대신 . 다시 한 번 그 개체는 메모리에 남아 있습니다 ..

      Join-Path 사용   $RD = $FSCSV + "*.csv" 대신 cmdlet  또는 $Cop = $FSCSV + "*.csv"  구성

      Excel 워크 시트 이름에서 유효하지 않은 문자 제거 ( replace '[\\/?*:[\]]', '' )

      함수로 동사 명 (Verb-Noun) 이름을 사용하면 기능이 명확 해집니다. 이제 당신은 Location 와 같은 기능을 가지고 있습니다 Delete  그리고 File  아무 의미도 없습니다

      Shares 함수를 호출하는 65 행과 같이 정의되기 전에 함수를 호출합니다. . 이 시점에서 함수 자체가 69 행으로 작성되었으므로 아직 존재하지 않습니다

      [System.Runtime.Interopservices.Marshal]::ReleaseComObject($worksheet) | Out-Null 추가  기능 Excel-Write 에서

      $Excel 변수를 사용할 필요가 없습니다  스크립트 범위에서 ( $Script:Excel = New-Object -ComObject excel.application ) 함수에 로컬로만 사용되는 경우

      Excel 사양 및 제한을 확인해야 할 수도 있습니다

      루프가 언제 시작하고 끝나는 지 명확하게 코드 들여 쓰기 수정

      더 의미있는 변수 이름을 사용하는 것이 좋습니다. 두 달이 지난 후 외부 자나 자신의 경우 2 글자 변수 이름이 혼란스러워집니다.

  • 이전 css - 의사 요소 자체가 행을 끊지 않도록 방지
  • 다음 caching - infinispan JDG 키 자동 제거