2016-01-06 1 views
-1

Это не вопрос, потому что у меня уже есть ответ. Я просто хотел поблагодарить всех, кто публикует и помогает в Интернете. Мне действительно потребовалось много времени, чтобы поместить все, что я нашел вместе.powershell конвертировать все листы excel в csv, просто вставив файл в контролируемую папку

+0

так сайт Q & A, а не форум или блог. –

+0

Вы должны отредактировать это в форме вопроса, а затем самостоятельно ответить на него с помощью кода, который вы предоставили. Через 48 часов вы сможете вернуться и пометить свое собственное представление в качестве принятого ответа. – Jeeped

+0

Я думал об этом, и я googled ли SO можно использовать как это ... Я нашел эту запись в блоге https://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your -own-questions/ – jmaltube

ответ

0

Этот сценарий охватывает: - Мониторинг папок через события: поэтому вам просто нужно вставить файл Excel в указанную папку (и ее дочерние элементы), чтобы автоматически запускать преобразование. - Excel (xls/xlsx) - csv. Он собирает все листы из всех предикатов внутри этой папки и объединяет все содержимое в один файл .csv ... он отличается от нескольких excels/worksheets, он выдает исключение ... Но он, очевидно, работает в более простой сценарий с одним файлом excel с одной книгой. - Вход в файл для всех различных действий/событий. - Сбрасывает память, чтобы избежать проблем с прослушиванием.

Здесь мы идем:

<#-----------------------------------------------------------------------# 
Purpose: To enable users to paste excel/txt files into a single folder and automatically convert them to .csv. 
     The resulting .csv adopts its parent's folder name. 
     If more thn 1 excel/txt file is pasted on the same folder, these multiple files are merged into a single .csv file as long as they have the same structure, otherwise 
      an exception is raised. 
     This script watches constantly these events on a defined folder in this script itself: 
       -Creation of files/folders -> Currently enabled. 
       -Modification of files/folders -> Currently disabled. (see main region to activate this event) 
       -Deletion of files/folders -> Currently disabled. (see main region to activate this event) 
       -Renaming of files/folders -> Currently disabled. (see main region to activate this event) 
     This script, when run from powershell, will output to console some messages, but it also maintains a physical log file on the server. 
     The location of this log file is defined within the writeToLogFile function.  
#------------------------------------------------------------------------#> 




#------------------------------------------------------------------------# 
########################## FUNCTIONS REGION ############################## 
#------------------------------------------------------------------------# 



function writeToLogFile { 
    param ([string]$strLogLine = $(throw 'must supply a log line to be inserted!')) #param1: the log line to be inserted/appended to the log 

    $logFile = "D:\OneLoader\OneLoaderLog.txt" #Path and name of log file. Modify this if required. 

    #checks if log file is greater than 5mb and renames it with system date to allow the creation of a new log file. 
    if ((Get-Item $logFile).length -gt 5mb) { #Checks if it's greater than 5 megabytes. 
     $renamedLog = $logFile -replace ".txt$", "_$(get-date -Format yyyyMMMdd).txt" #prepares new log file name, it sufixes sysdate to allow the creation of a new log file.    
     rename-item -path $logFile -newname $renamedLog #renames the current log file. 
    } 


    $line = "$(Get-Date): $strLogLine" #Prepares the log line to be inserted: It prefixes the sytem date to whatever you want to insert in the log. 

    Write-host $line 
    Add-content $logFile -value $line #Appends a log line to the the log file. 

} 



<#-----------------------------------------------------------------------# 
Function getCSVFileName 
Purpose: Given an excel file, it checks for the file's existance and returns a new file name with the name equals to the parent folder and the extension as .csv 

Parameters: 
    1) parameter $strFileName: Full path name to an excel file. e.g.: D:\Folder1\ChildFolder\ExcelFile.xlsx  
#------------------------------------------------------------------------#> 
function getCSVFileName { 

    param ([string]$strFileName = $(throw 'must supply a file name!')) #parm1: The excel file name. 


    #Test if the path to the excel file is correct. if not, exits the function. 
    if (-not (Test-Path $strFileName)) { 
     throw "Path $strFileName does not exist."  
    } 

    $parentFolder= Split-Path (Split-Path $strFileName -Parent) -Leaf #Obtains the most inner folder name. E.g: C:\Folder1\Folder2\file.txt --> RESULT: Folder2 
    #$justFileName = split-path $strFileName -leaf -resolve #Obtains just the file name. E.g: C:\Folder1\Folder2\file.txt --> RESULT: file.txt 
    $baseFolder = Split-path $strFileName #Obtainsthe file's base folder name. E.g: C:\Folder1\Folder2\file.txt --> RESULT: C:\Folder1\Folder2 

    $fileNameToCSV = $baseFolder + '\' + $parentFolder + '.csv' #Build a string for the new .csv file name. The file is renamed to match the parent's folder name. 

    return $fileNameToCSV 

} #End of function getCSVFileName 


<#-----------------------------------------------------------------------# 
Function xls-csv 
Purpose: Given an excel file and a sheet name within that file, it converts the contents of that sheet into a .csv file and places it in the same location as the excel file 

Parameters: 
    1) parameter $strFileName: Full path name to an excel file. e.g.: D:\Folder1\ChildFolder\ExcelFile.xlsx 

#------------------------------------------------------------------------#> 
function xls-csv { 

    param (
     [string]$strFileName = $(throw 'Must supply a file name!') #parm 1: Excel file. full path.   
    ) 

    try{ 
     $newFileNameCSV = getCSVFileName $strFileName #Obtains new .csv file name from function  
    } 
    Catch {  
     $ErrorMessage = $_.Exception.Message 
     $FailedItem = $_.Exception.ItemName 

     $logLine="Exception occured while renaming file to csv. FailedItem: $FailedItem. The error message was $ErrorMessage" 
     writeToLogFile $logLine #Writes a line to the log 

     return 
    } 

    #Checking if the excel file was not already converted to CSV. If it was, it appends the content of the xls. This is done in case there are more than one excel file in the same directory. 


    writeToLogFile "Converting $strFileName" #Writes a line to the log 

    #BEGIN SECTION CONFIG 
    #These parameters are required to setup the connection to the OLEDB adapter. Must not change unless necessary. 
    $strProvider = "Provider=Microsoft.ACE.OLEDB.12.0" 
    $strDataSource = "Data Source = $strFileName" 
    $strExtend = "Extended Properties='Excel 12.0;HDR=Yes;IMEX=1';" 

    #END SECTION CONFIG 

    #BEGIN SECTION CONNECTION 
    Try { 
     #These steps stablish the connection and the query command that is passed to the OleDB adapter. Must not change unless necessary. 
     $objConn = New-Object System.Data.OleDb.OleDbConnection("$strProvider;$strDataSource;$strExtend") 
     $sqlCommand = New-Object System.Data.OleDb.OleDbCommand 
     $sqlCommand.Connection = $objConn 

     $objConn.open() 
     #END SECTION CONNECTION 


     #BEGIN SECTION SELECT QUERY  

     #Obtains all worksheets within the excel file and converts the content of each one of them into csv    
     $objConn.GetSchema("Tables") | 
     ForEach-Object { 
      if($_.Table_Type -eq "TABLE") 
      { 
       $wrksheet= $_.Table_Name 
       $strQuery = "Select * from [$wrksheet]" #Query to read all content from worksheet 
       $sqlCommand.CommandText = $strQuery 

       $da = New-Object system.Data.OleDb.OleDbDataAdapter($sqlCommand)     
       $dt = New-Object system.Data.datatable 

       [void]$da.fill($dt) #fills a datatable with the content of the worksheet 

       if (-not (Test-Path $newFileNameCSV)) {  
        #Pipes the contents of the datatable into a NEW CSV File. Export-Csv function is a native PowerShell function. 
        $dt | Export-Csv $newFileNameCSV -Delimiter ',' -NoTypeInformation  
       } else { 
        #Pipes the contents of the datatable and APPENDS it to the existing CSV File. Export-Csv function is a native PowerShell function. 
        $dt | Export-Csv $newFileNameCSV -Delimiter ',' -NoTypeInformation -Append   
       } #end of if-else 


       #END SECTION SELECT QUERY 
      } 
    } 
     $objConn.close() 
    } 
    Catch {  
     $ErrorMessage = $_.Exception.Message 
     $FailedItem = $_.Exception.ItemName 

     $logLine = "Exception occured while converting excel file: '$strFileName', worksheet name: $wrksheet --> FailedItem: $FailedItem. The error message was $ErrorMessage" 
     writeToLogFile $logLine #Writes a line to the log 

     $objConn.close() #close the file in case of errors so it doesn't get locked by a user. 

     return 
    } 

    try { 


     #Once and excel file is converted successfully, the extension is changed so it's not picked up again by the script. 
     if ($strFileName -like '*.xlsx') { 
      $renamedExcel = $strFileName -replace ".xlsx$", ".old" #Renames xlsx to .old extension 
     }else { 
      $renamedExcel = $strFileName -replace ".xls$", ".old" #Renames xls to .old extension 
     } 

     rename-item -path $strFileName -newname $renamedExcel #changes the extension of the recently converted excel file. 
    }  
    Catch {  
     $ErrorMessage = $_.Exception.Message 
     $FailedItem = $_.Exception.ItemName 

     $logLine = "Exception occured while renaming the original file. FailedItem: $FailedItem. The error message was $ErrorMessage" 
     writeToLogFile $logLine #Writes a line to the log 

     return 
    } 

    writeToLogFile "Converted $strFileName to $newFileNameCSV" #Writes a line to the log 
    return 
} #end of function xls-csv 


<#-----------------------------------------------------------------------# 
Function txt-csv 
Purpose: Given a txt file, it converts the contents of that txt into a .csv file and places it in the same location as the txt file 

Parameters: 
    1) parameter $strFileName: Full path name to a txt file. e.g.: D:\Folder1\ChildFolder\ExcelFile.txt 

#------------------------------------------------------------------------#> 
function txt-csv { 

    param ([string]$strFileName = $(throw 'Must supply a file name!')) #parm 1: txt file. full path.    

    try{ 
     $newFileNameCSV = getCSVFileName $strFileName #Obtains new .csv file name from function  
    } 
    Catch {  
     $ErrorMessage = $_.Exception.Message 
     $FailedItem = $_.Exception.ItemName 

     $logLine="Exception occured while renaming file to csv. FailedItem: $FailedItem. The error message was $ErrorMessage" 
     writeToLogFile $logLine #Writes a line to the log 

     return 
    } 

    #Checking if the txt file was not already converted to CSV. If it was, it appends the content of the txt. This is done in case there are more than one txt files in the same directory. 


    writeToLogFile "Converting $strFileName" #Writes a line to the log 

    try { 

     if (-not (Test-Path $newFileNameCSV)) {  
      #Pipes the contents of the txt file into a NEW CSV File. Export-Csv function is a native PowerShell function. 
      Import-Csv -Path $strFileName | Export-Csv -Path $newFileNameCSV -Delimiter ',' -NoTypeInformation 
     } else { 
      #Pipes the contents of the txt file and APPENDS it to the existing CSV File. Export-Csv function is a native PowerShell function. 
      Import-Csv -Path $strFileName | Export-Csv -Path $newFileNameCSV -Delimiter ',' -NoTypeInformation -Append   
     } #end of if-else 

     #Once a txt file is converted successfully, the extension is changed so it's not picked up again by the script. 
     $renamedFile = $strFileName -replace ".txt$", ".old" #Renames xlsx to .old extension 

     rename-item -path $strFileName -newname $renamedFile #changes the extension of the recently converted excel file. 
    }  
    Catch {  
     $ErrorMessage = $_.Exception.Message 
     $FailedItem = $_.Exception.ItemName 

     $logLine = "Exception occured while exporting to csv. FailedItem: $FailedItem. The error message was $ErrorMessage" 
     writeToLogFile $logLine #Writes a line to the log 

     return 
    } 

    writeToLogFile "Converted $strFileName to $newFileNameCSV" #Writes a line to the log 
    return 
} #end of function txt-csv 



<#-----------------------------------------------------------------------# 
Function convertDirectory 
Purpose: Given directory, it looks for .xls and .xlsx files recursively and calls the xls-csv function to perform the conversion 

Parameters: 
    1) parameter $Directory: Full directory path to scan for excel files  
#------------------------------------------------------------------------#> 
function convertDirectory { 

    param ([string]$Directory = $(throw 'Must supply a folder name!')) 

    if (-not (Test-Path $Directory)) { 
     throw "Path '$Directory' does not exist." 
     return 
    }  

    #### BEGIN EXCEL CONVERSION SECTION ### 
    #Gets list of files within the folder and filters by .xls and .xlsx extensions 

    $dir = Get-ChildItem -path $($Directory + "\*") -include *.xls,*.xlsx 

    foreach($file in $dir) #Loops through all excel files 
    {  
     writeToLogFile "Found file $file candidate to conversion" #Writes a line to the log 
     xls-csv $file.FullName "Sheet1$" #Calls the function to convert the excel file into csv. "Sheet1" is static as of now. 
    } 
    #### END EXCEL CONVERSION SECTION ### 


    #### BEGIN TXT CONVERSION SECTION ### 
    #Gets list of files within the folder and filters by .txt extension 

    $dir = Get-ChildItem -path $($Directory + "\*") -include *.txt 

    foreach($file in $dir) { #Loops through all excel files   
     writeToLogFile "Found file $file candidate to conversion" #Writes a line to the log 
     txt-csv $file.FullName #Calls the function to convert the txt file into csv. 
    } 
    #### END EXCEL CONVERSION SECTION ## 

} #end of function convertDirectory 



<#-----------------------------------------------------------------------# 
Function flushMemory 
Purpose: since this is a While{true} script, it may end abruptly. This function is called at beginning of MAIN REGION to clear all possible allocated 
      space of memory and to, more importantly, unregister all posible IO event handlers on the OneLoader directory. 

Parameters: None. 
#------------------------------------------------------------------------#> 
Function flushMemory { 
    # Find out how much memory is being consumed by your Sesssion: 
    #[System.gc]::gettotalmemory("forcefullcollection") /1MB #Uncomment in case of debugging a memory leak 

    # Force a collection of memory by the garbage collector: 
    [System.gc]::collect() 

    # Dump all variables not locked by the system: 
    foreach ($i in (ls variable:/*)) {rv -ea 0 $i.Name} # -verbose $i.Name} #you can include the verbose argument to get the list of variables out of bound. 

    #Check memory usage again and force another collection: 
    #[System.gc]::gettotalmemory("forcefullcollection") /1MB #Uncomment in case of debugging a memory leak 
    [System.gc]::collect() 

    #Check Memory once more: 
    #[System.gc]::gettotalmemory("forcefullcollection") /1MB #Uncomment in case of debugging a memory leak 

    #Unregister events created by previous instances of this script 
    get-eventsubscriber -force | unregister-event -force #THIS LINE IS REALLY IMPORTANT 
} 


#------------------------------------------------------------------------# 
############################ MAIN REGION ################################# 
#------------------------------------------------------------------------# 


writeToLogFile "Script 'OneLoader monitor' initiated at $(Get-Date)" #Writes a line to the log 

###IMPORTANT! KEEP CALL TO flushMemory function 
flushMemory #!!!!!!IMPORTANT 

### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO 
$watcher = New-Object System.IO.FileSystemWatcher 
$watcher.Path = "D:\OneLoader" #IMPORTANT: Defines the OneLoader folder to be monitored. Don't put a slash "\" on the end or a puppy will die. 
$watcher.Filter = "*.*" 
$watcher.IncludeSubdirectories = $true 
$watcher.EnableRaisingEvents = $true 


### DEFINE ACTIONS AFTER A EVENT IS DETECTED 
$action = { 
      $eventFullPath = $Event.SourceEventArgs.FullPath #obtains full path of file that got created    
      $changeType = $Event.SourceEventArgs.ChangeType #obtains the type of event captured.    

      $logLine = "$changeType, $eventFullPath" #Prepares the log line that will be inserted in the log file. 
      writeToLogFile $logLine #Writes a line to the log 

      try{ 
       $eventBaseDirectory = split-path $eventFullPath #extracts the base directory from the full path of the file recently created. 
       convertDirectory $eventBaseDirectory #calls the function to convert all excel files within the directory caught by the event. 
      } 
      Catch {  
       $ErrorMessage = $_.Exception.Message 
       $FailedItem = $_.Exception.ItemName 

       $logLine = "Exception occured while discovering excel files in folder. FailedItem: $FailedItem. The error message was $ErrorMessage"     
       writeToLogFile $logLine #Writes a line to the log 

      } 
      } #End of $action  

### DECIDE WHICH EVENTS SHOULD BE WATCHED + SET CHECK FREQUENCY. 
#Uncomment the events you want this script to monitor over the folder. 

$created = Register-ObjectEvent $watcher "Created" -Action $action 
#$changed = Register-ObjectEvent $watcher "Changed" -Action $action 
#$deleted = Register-ObjectEvent $watcher "Deleted" -Action $action 
#$renamed = Register-ObjectEvent $watcher "Renamed" -Action $action 

while ($true) {sleep 5} 
0
function Save-CSVasExcel { 
    param (
     [string]$CSVFile = $(Throw 'No file provided.') 
    ) 


    BEGIN { 
     function Resolve-FullPath ([string]$Path) {  
      if (-not ([System.IO.Path]::IsPathRooted($Path))) { 
       # $Path = Join-Path (Get-Location) $Path 
       $Path = "$PWD\$Path" 
      } 
      [IO.Path]::GetFullPath($Path) 
     } 

     function Release-Ref ($ref) { 
      ([System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$ref) -gt 0) 
      [System.GC]::Collect() 
      [System.GC]::WaitForPendingFinalizers() 
     } 

     $CSVFile = Resolve-FullPath $CSVFile 
     $xl = New-Object -com 'Excel.Application' 
    } 

    PROCESS { 
     $wb = $xl.workbooks.open($CSVFile) 
     $xlOut = $CSVFile -replace '\.csv$', '.xlsx' 
     $ws = $wb.Worksheets.Item(1) 
     $range = $ws.UsedRange 
     [void]$range.EntireColumn.Autofit() 

     $num = 1 
     $dir = Split-Path $xlOut 
     $base = $(Split-Path $xlOut -Leaf) -replace '\.xlsx$' 
     $nextname = $xlOut 
     while (Test-Path $nextname) { 
      $nextname = Join-Path $dir $($base + "-$num" + '.xlsx') 
      $num++ 
     } 

     $wb.SaveAs($nextname, 51) 
    } 

    END { 
     $xl.Quit() 

     $null = $ws, $wb, $xl | % {Release-Ref $_} 

     # del $CSVFile 
    } 
} 

function Save-ExcelasCSV { 
    param (
     [string[]]$files = $(Throw 'No files provided.'), 
     [string]$OutFolder, 
     [switch]$Overwrite 
    ) 

    BEGIN { 
     function Release-Ref ($ref) { 
      ([System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$ref) -gt 0) 
      [System.GC]::Collect() 
      [System.GC]::WaitForPendingFinalizers() 
     } 

     $xl = New-Object -ComObject 'Excel.Application' 
     $xl.DisplayAlerts = $false 
     $xl.Visible = $false 
    } 

    PROCESS { 
     foreach ($file in $files) { 
      $file = Get-Item $file | ? {$_.Extension -match '^\.xlsx?$'} 
      if (!$file) {continue} 
      $wb = $xl.Workbooks.Open($file.FullName) 

      if ($OutFolder) { 
       $CSVfilename = Join-Path $OutFolder ($file.BaseName + '.csv') 
      } else { 
       $CSVfilename = $file.DirectoryName + '\' + $file.BaseName + '.csv' 
      } 

      if (!$Overwrite -and (Test-Path $CSVfilename)) { 
       $num = 1 
       $folder = Split-Path $CSVfilename 
       $base = (Split-Path $CSVfilename -Leaf).Substring(0, (Split-Path $CSVfilename -Leaf).LastIndexOf('.')) 
       $ext = $CSVfilename.Substring($CSVfilename.LastIndexOf('.')) 
       while (Test-Path $CSVfilename) { 
        $CSVfilename = Join-Path $folder $($base + "-$num" + $ext) 
        $num += 1 
       } 
       $wb.SaveAs($CSVfilename, 6) # 6 -> csv 
      } else { 
       $wb.SaveAs($CSVfilename, 6) # 6 -> csv 
      } 

      $wb.Close($True) 
      $CSVfilename 
     } 
    } 

    END { 
     $xl.Quit() 
     $null = $wb, $xl | % {try{ Release-Ref $_ }catch{}} 
    } 
} 

также, это может быть полезным, если документ Excel имеет несколько страниц:

http://www.codeproject.com/Articles/451744/Extract-worksheets-from-Excel-into-separate-files

Смежные вопросы