Powershell script to append the resultset from multiple source to a csv - powershell

I need help with this script. Basically I am connecting to multiple databases to get a dataset I need. And after capturing the dataset from all different databases, I need to write output it to a CSV file. Below is the code I basically came up with. The script is creating an output CSV file but it doesn't append all the data I captured. It only writes the last dataset captured. How do I go around this?
Need help to fix it.
$DB = Get-Content c:\ps\DBLIST.txt
foreach($Data in $DB)
{
Write-Host $Data
$strDB = $Data+".local"
$con = New-Object System.Data.SqlClient.SqlConnection
$con.ConnectionString = "Server=$strDB;Database=db;User ID=user;Password=password"
$con.open()
$qry = "select a, b, c, d from table1"
$cmd = New-Object System.Data.SqlClient.SqlCommand
$cmd.CommandText = $qry
$cmd.Connection = $con
$da = New-Object System.Data.SqlClient.SqlDataAdapter
$da.SelectCommand = $cmd
$ds = New-Object System.Data.Dataset
$da.Fill($ds)
$dr = $cmd.ExecuteReader()
Write-Host
$outFile = "C:\ps\OUTPUT.csv"
If ($dr.HasRows)
{
write-Host a b c d
While ($dr.Read())
{
Write-Host $dr["a"] $dr["b"] $dr["c"] $dr["d"]
}
}
Else
{
Write-Host There are no records found. Try again.
}
$ds.Tables[0] | export-csv $outFile -NoTypeInfo -Force -Append
#$ds.Tables[0] | Export-Csv -Delimiter ','$outFile -Encoding "unicode"
Write-Host
$dr.Close()
$con.Close()
}

Instead of a ForEach loop, you can make use of the Powershell Pipeline via Foreach-Object. If you send the list of database servers down the pipeline, and then simply output the results inside the loop, Powershell will send all the results into the pipeline, effectively combining them. You can then take the final result and write it to the CSV file.
Note that I had to move the $outfile variable above the loop (where it belongs anyway). I also had to explicitly label the -Path parameter when I tested it in Powershell v2.0:
$outFile = "C:\TEMP\OUTPUT.csv"
$DB = Get-Content c:\ps\DBLIST.txt
$DB | Foreach-Object {
$Data = $_
$strDB = $Data+".local"
$con = New-Object System.Data.SqlClient.SqlConnection
$con.ConnectionString = "Server=$strDB;Database=db;User ID=user;Password=password"
$con.open()
$qry = "select a, b, c, d from table1"
$cmd = New-Object System.Data.SqlClient.SqlCommand
$cmd.CommandText = $qry
$cmd.Connection = $con
$da = New-Object System.Data.SqlClient.SqlDataAdapter
$da.SelectCommand = $cmd
$ds = New-Object System.Data.Dataset
$da.Fill($ds) | Out-Null # prevent the number of records from going down the pipeline
$dr = $cmd.ExecuteReader()
# This is the magic right here -- it simply outputs the
# contents of $ds.Tables[0] to the pipeline
$ds.Tables[0]
$dr.Close()
$con.Close()
} | Select-Object a,b,c,d | Export-Csv -Path $outFile -Delimiter ',' -Encoding "unicode"

This should work
$SomeObject | export-csv $outFile -NoTypeInfo -Append
Edit for PowerShell v2 where -Append doesn't exist:
Collect all info in one object. Write this object to a file once done.
# before you start the loop:
$a = #()
# in your loop:
$a += $ds.Tables[0]
# after the loop:
$a | Export-Csv $outFile -NoTypeInformation

Related

Powershell Error: "There is not enough memory or disk to complete the operation"

I'm running a powershell script to read multiple word documents. When running to around 700 documents, it shows error "There is not enough memory or disk to complete the operation".
Here is my code
$excel = New-Object -ComObject Excel.application
$source = 'powershell/attachments'
$docs = Get-ChildItem -Path $source -Recurse -Filter *cover*.docx
$XL = New-Object -ComObject Excel.Application
#Open the workbook
$WB = $XL.Workbooks.Open("powershell/result.xlsx")
#Activate Sheet1, pipe to Out-Null to avoid 'True' output to screen
$WB.Sheets.Item("Sheet1").Activate() | Out-Null
$SearchArray = #('employment', 'source of income', 'US address', 'residential address', 'ID', 'driver license', 'visa', 'passport', 'I-20', 'Social Security Card', 'information update form', 'w9', 'w8', 'tax', 'email address')
$word = New-Object -ComObject Word.application
foreach ($doc in $docs) {
$Document = $word.Documents.Open($doc)
$CVSInfo = $Document.Paragraphs | ForEach-Object{
foreach ($SerchText in $SearchArray) {
$_.Range.Text | Where-Object { $_-match $SerchText} | ForEach-Object {
$_-split ' ' | Select-Object -Last 1
}
}
}
$PathArray = $doc.FullName
#Launch Excel
#Find first blank row #, and activate the first cell in that row
$FirstBlankRow = $($xl.ActiveSheet.UsedRange.Rows)[-1].Row + 1
$XL.ActiveSheet.Range("A$FirstBlankRow").Activate()
#Create PSObject with the properties that we want, convert it to a tab delimited CSV, and copy it to the clipboard
$Record = [PSCustomObject]#{
'ID' = $PathArray
'Context' = $CVSInfo
}
$Record | ConvertTo-Csv -Delimiter "`t" -NoTypeInformation | Clip
#Paste at the currently active cell
$XL.ActiveSheet.Paste() | Out-Null
# Save and close
$WB.Save() | Out-Null
}
$WB.Close() | Out-Null
$XL.Quit() | Out-Null
#Release ComObject
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($XL)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($word)
Thanks in advance!
It looks like you have hundreds of Word documents open. Don't forget to close them in each iteration of the loop:
$Document.Close()

Invoke-sqlcmd not working when inserting csv data

Below mentioned code is generating CSV files successfully, but not inserting into database. Code was working previously, but not now:
Doesn't give error, data is not generating
$DestinationFileName = $DestinationFile
$SourceFileName = $SourceFile
$tableNum = $tableNumber
$DatabaseTable = $DatabaseTableName
$delimiter = ','
$objWord = New-Object -Com Word.Application
$objWord.Visible = $false # $false
$objDocument = $objWord.Documents.Open($SourceFileName,$false,$true)
$LETable = $objDocument.Tables.Item($tableNum)
$LETableCols = $LETable.Columns.Count
$LETableRows = $LETable.Rows.Count
$RawCSV = for($r=1; $r -le $LETableRows; $r++) {
$content= #()
for($c=1; $c -le $LETableCols; $c++) {
$content += ("`"{0}`"" -f $LETable.Cell($r,$c).Range.Text -replace "(`r|`n|`t)|$([char]7)?")
}
$Content -join $delimiter
}
$Csv = $RawCSV | ConvertFrom-Csv
$objDocument.Close()
$objWord.Quit()
# Stop Winword Process
$rc = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objWord)
$Csv
$Csv | Export-Csv $DestinationFileName -NoTypeInformation
$database = 'Test'
$server = '.'
$table = 'ScanDoc'
Invoke-Sqlcmd -Database $database -ServerInstance $server -Query "Trun
Import-CSV $DestinationFile -Header Col1, Col2 | Select-Object -Skip 1 | ForEach-Object { Invoke-Sqlcmd -Database $database -ServerInstance $server -Query "insert into $table VALUES ('$($SourceFileName)','$($_.Col1)','$($_.Col2)')"}

Powershell ISE setting a path from dataset return

I'm trying to set the path that I'm going to navigate to from a field in our database. However; I keep running into errors regarding the | Format-Table command. Removing the Format-Table does not permit the dataset to be displayed so I need to keep that there. When I Write-Host $Path the correct value is returned but If I try to set-location $Path that is when I get the error:
The object of Type "Microsoft.PowerShell.Commands.Internal.Format.FormatStartData" is not valid or not in the correct sequence.
This is likely caused by a user-specified "format-table" command which is conflicting with the default formatting.
I've included the code I'm using below. Sorry if this ends up being simple I'm knew to Powershell.
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$DataSet = New-Object System.Data.DataSet
$SqlConnection.ConnectionString = "MyConnection"
cls
$SQLQuery = "SELECT setting, value FROM Table"
$SqlConnection.Open()
$SqlCmd.CommandText = $SQLQuery
$SqlCmd.Connection = $SqlConnection
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$DataSet.Tables[0] | Format-Table -Autosize
$SqlConnection.Close()
foreach ($Row in $dataset.Tables[0].Rows)
{
IF ("$($Row.setting)" -eq "ArchiveDir" -and "$($Row.value)" -like "\\*")
{
$Path = "$($Row.value)"
$Path
set-location $Path
dir
}
ELSE {$Path = ""}
}
Not sure I fully follow your question; but give this a try:
$ds = $DataSet.Tables[0]
$ds | Format-Table -Autosize
...
foreach ($row in $ds.Rows) {
if ($row.setting -eq "ArchiveDir" -and $row.value -like "\\*") {
$path = $row.value
Write-Host $path
Set-Location $path
}
}
If you get the same error try:
$path = $row.value.ToString()
Set-Location $Path

How to Export-Csv with variables?

I'm trying to write 8 variables into an CSV file with PowerShell, but it just ends up as ,,,,,,, instead of var1,var2,var3,var4,var5,var6,var7,var8
My code is as follows:
$newRow = "{0},{1},{2},{3},{4},{5},{6},{7}" -f $var1,$var2,$var3,$var4,$var5,$var6,$var7,$var8
$newRow = $newRow -Replace "`t|`n|`r",""
$newRow = $newRow -Replace " ;|; ",";"
$newRow += "`n"
$newRow | Export-Csv -Path $file -Append -noType -Force
Without -Force I get the following error message:
Export-Csv : Cannot append CSV content to the following file: C:\result.txt. The
appended object does not have a property that corresponds to the following column:
var1. To continue with mismatched properties, add the -Force parameter, and then
retry the command.
At C:\Test.ps1:72 char:12
+ $newRow | Export-Csv -Path $file -Append -noType
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (var1:String) [Export-Csv], InvalidOperationException
+ FullyQualifiedErrorId : CannotAppendCsvWithMismatchedPropertyNames,Microsoft.PowerShell.Commands.ExportCsvCommand
EDIT:
Script:
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
$startInfo.FileName = "powershell.exe"
$startInfo.Arguments = 'C:\zabbix\script\zabbix_vbr_job.ps1 "Discovery"'
$startInfo.RedirectStandardOutput = $true
$startInfo.UseShellExecute = $false
$startInfo.CreateNoWindow = $false
#$startInfo.Username = "DOMAIN\Username"
#$startInfo.Password = $password
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $startInfo
$process.Start() | Out-Null
$discoveryJson = $process.StandardOutput.ReadToEnd()
$process.WaitForExit()
cls
$discovery = $discoveryJson | ConvertFrom-Json
$file = "C:\zabbix\script\result.txt"
function RunScript ($param, $id)
{
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
$startInfo.FileName = "powershell.exe"
$startInfo.Arguments = "C:\zabbix\script\zabbix_vbr_job.ps1 '$param' '$id'"
$startInfo.RedirectStandardOutput = $true
$startInfo.UseShellExecute = $false
$startInfo.CreateNoWindow = $false
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $startInfo
$process.Start() | Out-Null
$output = $process.StandardOutput.ReadToEnd()
$process.WaitForExit()
return $output
}
$fileContent = Import-csv $file
$NewCSVObject = #()
foreach($obj in $discovery.data)
{
$index = [array]::indexof($discovery.data, $obj)
Write-Host $index "/" $discovery.data.count
#Write-Host (RunScript "Result" $obj.JOBID )
$Result = RunScript "Result" $obj.JOBID
#Write-Host $Result
$RunStatus = RunScript "RunStatus" $obj.JOBID
#Write-Host $RunStatus
$IncludedSize = RunScript "IncludedSize" $obj.JOBID
#Write-Host $IncludedSize
$ExcludedSize = RunScript "ExcludedSize" $obj.JOBID
#Write-Host $ExcludedSize
$VmCount = RunScript "VmCount" $obj.JOBID
#Write-Host $VmCount
$Type = RunScript "Type" $obj.JOBID
#Write-Host $Type
$RunningJob = "RunningJob"#RunScript "RunningJob" $obj.JOBID
#Write-Host $RunningJob
#$newRow = New-Object PsObject -Property #{ JobID = $obj.JOBID ; Result = $Result ; RunStatus = $RunStatus ; IncludedSize = $IncludedSize ; ExcludedSize = $ExcludedSize ; VmCount = $VmCount ; Type = $Type ; RunningJob = $RunningJob }
$newRow = "{0},{1},{2},{3},{4},{5},{6},{7}" -f $obj.JOBID,$Result,$RunStatus,$IncludedSize,$ExcludedSize,$VmCount,$Type,$RunningJob
$newRow = $newRow -Replace "`t|`n|`r",""
$newRow = $newRow -Replace " ;|; ",";"
$newRow += "`n"
#$newRow | Out-File $file
#[io.file]::WriteAllText("C:\zabbix\script\test.txt",$newRow)
Write-Host $newRow
$newRow | Export-Csv -Path $file -Append -noType
break
}
#cls
Write-Host $fileContent
CSV headers:
JobID,Result,RunStatus,IncludedSize,ExcludedSize,VmCount,Type,RunningJob
There is no point in using Export-Csv if you're building the CSV line by hand anyway.
Either change
$newRow | Export-Csv -Path $file -Append -noType -Force
into
$newRow | Add-Content $file
or build $newRow like this:
$newRow = New-Object -Type PSObject -Property #{
'JobID' = $var1
'Result' = $var2
'RunStatus' = $var3
'IncludedSize' = $var4
'ExcludedSize' = $var5
'VmCount' = $var6
'Type' = $var7
'RunningJob' = $var8
}
and the problem will disappear.
The reason for this behavior is that Export-Csv is for transforming objects into a tabular string representation of their properties. Essentially, an object
#{
propertyA: 'foo'
propertyB: 23
}
becomes
propertyA,propertyB
"foo","23"
If you're already building a string, the resulting (string) object has just a single property (Length), which doesn't match any of the properties from your existing CSV. Hence the error you're getting without -Force. Even if you use -Force, the properties written to the CSV are determined from the first item in the existing CSV. Properties that are not present in this set are omitted from the output, and properties from that set that are not present in the object are filled with null values.

Save an open Excel sheet using Powershell

I am completely newbie to Powershell. Need your help in saving an opened excel sheet using Powershell.
Script goes something like this
$xlPasteValues = -4163
$xlCellTypeLastCell = 11
$xl = new-object -comobject excel.application
$xl.Visible = $True
$xl.DisplayAlerts = $False
$wb = $xl.Workbooks.Add()
$i = 1
$collection = Get-ChildItem C:\Test\* -include *.csv # Change the location of your CSV files here.
$length = 4
foreach ($item in $collection) {
$wb1 = $xl.Workbooks.Open("$item")
$array = $item.ToString()
$delim = "\"
$SheetName = $array.split($delim)
$s = $SheetName[2]
$sn = $s.split(".")
$nsn = $sn[0]
$ws1 = $wb1.worksheets | where {$_.name -eq $nsn}
Write-Host $item $nsn
$used = $ws1.usedRange
$used.Select()
$used.copy()
$wb.Activate()
$ws = $wb.Sheets.Add()
$ws2 = $wb.worksheets | where {$_.name -eq "sheet$i"}
[void]$ws2.Range("A1").PasteSpecial(-4163)
$ws2.name = $nsn
$i++
$wb1.Close()
}
Add-Type -AssemblyName Microsoft.Office.Interop.Excel
$xlFixedFormat =[Microsoft.Office.Interop.Excel.XlFileFormat]::xlWorkbookDefault
$Excel = New-Object -comobject Excel.Application
$Excel.Visible = $true
Your question was rather vague so I'm assuming that you want to know how to open and save an Excel document through Powershell.
Open your Excel Document using New-Object
$a = New-Object -COM "Excel.Application"
$a.Visible = $true
$b = $a.Workbooks.Open("C:\PATH\TO\YOUR\EXCEL\sheet.xlsx")
Save and close your document
$b.Save()
$b.Close()
Check out my PowerShell Excel Module on Github. You can also grab it from the PowerShell Gallery.
Then try:
$xlFileName="c:\temp\test.xlsx"
dir *.csv |
ForEach {
$sheetName=$_.Name.Split('.')[0]
Import-Csv $_.FullName |
Export-Excel $xlFileName -WorkSheetname $sheetName
}
Invoke-Item $xlFileName