2

Firstly, I do apologize if this is a duplicate question. I searched and searched but haven't found anything which addresses the problem I'm stuck on.

My goal is taking 7 Powershell scripts that output a CSV from a SQL query into 1 Excel workbook, each CSV on a different worksheet.

I located this https://social.technet.microsoft.com/Forums/scriptcenter/en-US/ef70e191-1b2e-4ba8-8845-58c4b1159ab7/multiple-csvs-into-multiple-sheets-of-an-excel which works however the Excel workbook result has the First column as the last column.

function Export-Excel{
[cmdletBinding()]
Param([Parameter(ValueFromPipeline=$true)]
[string]$junk)
begin{
    $header=$null
    $row=1
}
process{
    if(!$header){
        $i=0
        $header=$_ | Get-Member -MemberType NoteProperty | select name
        $header | %{$Global:ws.cells.item(1,++$i)=$_.Name}
    }
    $i=0
    ++$row
    foreach($field in $header){
        $Global:ws.cells.item($row,++$i)=$($_."$($field.Name)")
    }
}

}

$xl=New-Object -ComObject Excel.Application
$wb=$xl.WorkBooks.add(1)
$Global:ws=$wb.WorkSheets.item(1)
$Global:ws.Name='Sunday'
import-csv 'C:\Sunday.csv' | Export-Excel
3
  • Why not use SSIS for the Excel export instead? Commented Jan 13, 2015 at 8:42
  • Because if I had SQL installed, I could use the invoke-sqlcmd cmdlet and the point of Powershell is to provide automation without using the GUI. Commented Jan 13, 2015 at 21:37
  • I should clarify. I'm trying to automate a procedure from MS Access which queries an SQL DB over ODBC exporting to MS Excel. Some manual formatting was required. With Powershell I can skip most of those steps in an easy to run script. Commented Jan 14, 2015 at 5:17

2 Answers 2

2

Ended up working out the following. If there is a more efficient method, please let me know. SQL results sent to Excel to take advantage of EntireColumn.AutoFit() and have each SQL query result on it's own worksheet.

$docs = "C:\Scripts\Output.xlsx"
If (Test-Path $docs){Remove-Item $docs}
Function Run-Query {
 param([string[]]$queries,[string[]]$weekdays)
## - Create an Excel Application instance:
$xlsObj = New-Object -ComObject Excel.Application
$xlsObj.DisplayAlerts = $false
$xlsWb = $xlsobj.Workbooks.Add(1)
## - Create new Workbook and Sheet (Visible = 1 / 0 not visible)
$xlsObj.Visible = 0
$time = 7
for ($i = 0; $i -lt $queries.Count; $i++){
 $percentage = $i / $time
 $remaining = New-TimeSpan -Seconds ($time - $i)
 $message = "{0:p0} complete" -f $percentage, $remaining    
Write-Progress -Activity "Creating Daily Reboot Spreadsheet" -status $message -PercentComplete ($percentage * 100)
 $query = $queries[$i]
 $weekday = $weekdays[$i]
$xlsSh = $xlsWb.Worksheets.Add([System.Reflection.Missing]::Value, $xlsWb.Worksheets.Item($xlsWb.Worksheets.Count))
$xlsSh.Name = $weekday
### SQL query results sent to Excel
$SQLServer = 'ServerName'
$Database = 'DataBase'
## - Connect to SQL Server using non-SMO class 'System.Data':
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $Database; Integrated Security = True"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $query
$SqlCmd.Connection = $SqlConnection
## - Extract and build the SQL data object '$DataSetTable:
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$SqlConnection.Close()
$DataSetTable= $DataSet.Tables["Table"]
## - Build the Excel column heading:
[Array] $getColumnNames = $DataSetTable.Columns | SELECT ColumnName
## - Build column header:
[Int] $RowHeader = 1
foreach ($ColH in $getColumnNames)
{
$xlsSh.Cells.item(1, $RowHeader).font.bold = $true
$xlsSh.Cells.item(1, $RowHeader) = $ColH.ColumnName
$RowHeader++
}
## - Adding the data start in row 2 column 1:
[Int] $rowData = 2
[Int] $colData = 1
foreach ($rec in $DataSetTable.Rows)
{
foreach ($Coln in $getColumnNames)
{
## - Next line convert cell to be text only:
$xlsSh.Cells.NumberFormat = "@"
## - Populating columns:
$xlsSh.Cells.Item($rowData, $colData) = $rec.$($Coln.ColumnName).ToString()
$ColData++
}
$rowData++; $ColData = 1
}
## - Adjusting columns in the Excel sheet:
$xlsRng = $xlsSH.usedRange
[void] $xlsRng.EntireColumn.AutoFit()
}#End For loop.
#Delete unwanted Sheet1.
$xlsWb.Sheets.Item('Sheet1').Delete()
#Set Monday to Active Sheet upon opening Workbook.
$xlsWb.Sheets.Item('Cert').Activate()
## ---------- Saving file and Terminating Excel Application ---------- ##
$xlsFile = "C:\Scripts\Output.xlsx"
[void] $xlsObj.ActiveWorkbook.SaveAs($xlsFile)
$xlsObj.Quit()
## - End of Script - ##
Start-Sleep -Milliseconds 700
 While ([System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlsRng)) {'cleanup xlsRng'}
 While ([System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlsSh)) {'cleanup xlsSh'}
 While ([System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlsWb)) {'cleanup xlsWb'}
 While ([System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlsObj)) {'cleanup xlsObj'}
[gc]::collect() | Out-Null
[gc]::WaitForPendingFinalizers() | Out-Null
}#End Function
 $queries = @()
 $queries += "Query1"
 $queries += "Query2"
 $queries += "Query3"
 $queries += "Query4"
 $queries += "Query5"
 $queries += "Query6"
 $queries += "Query7"
$weekdays = @("Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday")
Run-Query -queries $queries -weekdays $weekdays
Sign up to request clarification or add additional context in comments.

Comments

0

I would have a stored procedure that produce 7 result sets then write a Powershell function export data from SQL to 7 sheets in Excel and CSV in 1 shot. Below codes I downloaded the module ImportExcel from the link here https://github.com/dfinke/ImportExcel

function Export-7Tables { <# .SYNOPSIS This is summary of the function .DESCRIPTION This is a more detailed description .PARAMETER

>

[CmdletBinding()]
Param(
    [Parameter(Mandatory=$false)]
    [string]$DBServerInstance='.\mssql14',

    [Parameter(Mandatory=$false)]
    [string]$DBName='MyDBName',

    [Parameter(Mandatory=$false)]
    [string]$DBSchema='dbo',

    [Parameter(Mandatory=$false)]
    [string[]]$DBStoredProcedure='StoredProcName',

    [Parameter(Mandatory=$false)]
    [string]$WorkSheetName1='Sheet1InExcel',

    [Parameter(Mandatory=$false)]
    [string]$WorkSheetName2='Sheet2InExcel',
    
    [Parameter(Mandatory=$false)]
    [string]$WorkSheetName3='Sheet3InExcel',

    [Parameter(Mandatory=$false)]        
    [string]$OutputExcelFilePath = 'C:\Users\myPC\Documents\myExcelFile.xlsx',

    [Parameter(Mandatory=$false)]
    [string]$OutputCSVFilePath= 'C:\Users\myPC\Documents\myCSVFile.csv'
)

#$Verbose = $VerbosePreference -ne 'SilentlyContinue'

Try {
    $ErrorActionPreference = 'Stop'

    #Set Private Data from Psd1 to Shorter Variable
    $PD=$MyInvocation.MyCommand.Module.PrivateData

   
    $DBParams = @{
        ServerInstance = $DBServerInstance
        Database = $DBName
        Credential = Import-Clixml -Path $PD.CredentialFile
        Query = "EXEC [$DBName].[$DBSchema].[$DBStoredProcedure]"
    } 

#Call storedproc 
    $DataSet = Invoke-SqlCmd @DBParams -OutputAs DataSet
    # assign the first result set of stored procedure to $Sheet1DataTable and so on so forth
    $Sheet1DataTable = $DataSet.Tables[0]
    $Sheet2DataTable = $DataSet.Tables[1]
    $Sheet3DataTable = $DataSet.Tables[2]
  

    #Filter just the properties we want, these would be column headers
    $DesiredProperties1 = @(
        'ColumnName1'
        'ColumnName2'
        'ColumnName3'
        'ColumnName4'
        'ColumnName5'
    )  

     #Filter just the properties we want in $Sheet2DataTable
     $DesiredPropertiesSheet2 = @(
        'ColumnName1'
        'ColumnName2'
        'ColumnName3'
        'ColumnName4'
        'ColumnName5'
    )

         #Filter just the properties we want in $Sheet3DataTable
         $DesiredPropertiesSheet3 = @(
           'ColumnName1'
        'ColumnName2'
        'ColumnName3'
        'ColumnName4'
        'ColumnName5'
        )

       
    #writing headers for the first Excel sheet (Sheet1)
    $ResultSP1 = $Sheet1DataTable | Select-Object -Property $DesiredPropertiesSheet1 
    $ResultSP2 = $Sheet2DataTable | Select-Object -Property $DesiredPropertiesSheet2
    $ResultSP3 = $Sheet3DataTable | Select-Object -Property $DesiredPropertiesSheet3
    
    #Output to Excel file, CSV file, or to the screen
    if ($OutputExcelFilePath) {
        if (Test-Path -Path $OutputExcelFilePath) {Remove-Item -Path $OutputExcelFilePath}
         $ResultSP1 | Export-Excel -Path $OutputExcelFilePath -WorksheetName "Sheet1InExcel" -AutoSize
         $ResultSP2 | Export-Excel -Path $OutputExcelFilePath -WorksheetName "Sheet2InExcel" -AutoSize 
         $ResultSP3 | Export-Excel -Path $OutputExcelFilePath -WorksheetName "Sheet3InExcel" -AutoSize 
     
    }
    
    #at the same time, out put data from StoredProc to CSV
    if ($OutputCSVFilePath) {
        $Output | Export-Csv -Path $OutputCSVFilePath -NoTypeInformation
    }
 
}
Catch {
    $ErrorActionPreference = 'Continue'
    $PSCmdlet.WriteError($_)
} }

Hope it helps.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.