updating hash table while reading excel file failing in powershell - excel

Any idea why below code is failing.
# Open an Excel workbook first:
$ExcelObj = New-Object -comobject Excel.Application
$ExcelWorkBook = $ExcelObj.Workbooks.Open("c:\anil\test.xlsx",2,$true)
$ExcelWorkSheet = $ExcelWorkBook.Sheets.Item("Sheet1")
# Get the number of filled in rows in the XLSX worksheet
$rowcount=$ExcelWorkSheet.UsedRange.Rows.Count
$report = #{}
$outFile = "vm_info.csv"
"VM Name,Vcenter,Disk usage" | Out-File -FilePath $outFile
######
$data = $ExcelWorksheet.Range("A1:Z100000").Value2
for( $row = 2 ; $row -lt $data.GetUpperBound(0); $row++) {
$vmname = $data[$row, 1]
if ( $vmname -notin $report.keys){
$report[$vmname] = #{}
$report[$vmname]['vcenter'] = $data[$row, 5]
$report[$vmname]['datasize'] = $data[$row, 12]
}
}
$ExcelWorkBook.close($true)
$report.GetEnumerator()|foreach {
"$($_.name),$($_.value.vcenter),$($_.value.datasize)" | Out-File -FilePath $outFile -Append
}
Message getting
Index operation failed; the array index evaluated to null.
At C:\anil\scripts\get_vm_disk_usage_from_excel.ps1:20 char:26
$report[$vmname] = #{}
~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : InvalidOperation: (:) [], RuntimeException
FullyQualifiedErrorId : NullArrayIndex

Related

Powershell - Export Count of Groups Members to excel

foreach ($group in $ADMSObjects){
$searchString = $group.GroupDisplayName
$count = (Get-AzureADGroup -All $true -SearchString "$searchString" | Get-AzureADGroupMember -ALL 1).COUNT
write-host $group.GroupDisplayName , $count
}
I just need the function 'extended' to actually export $group.GroupDisplayName and $count to an Excel Sheet.
When I try to do something like:
foreach ($group in $ADMSObjects){
$searchString = $group.GroupDisplayName
$count = (Get-AzureADGroup -All $true -SearchString "$searchString" | Get-AzureADGroupMember -ALL 1).COUNT
write-host $group.GroupDisplayName , $count
Export-Csv -Path $path $group, $count -Append
}
DLAS - AMER - Global Planning and Transformation - 1190-GO-CGPT10026 32
Export-Csv : Cannot convert 'System.Object[]' to the type 'System.Char' required by parameter
'Delimiter'. Specified method is not supported.
At C:\users\crxdan\Documents\Set-DLASGroups.ps1:220 char:36
+ Export-Csv -Path $path $group, $count -Append
+ ~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Export-Csv], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.ExportCsvCommand
I'm not really sure where to go from here.
you could use PSCustomObject to get your results in an order. I guess the $group you mentioned is group display name. I do not have an environment to test it. so please test it from your end. Thanks!
$result = foreach ($group in $ADMSObjects){
$searchString = $group.GroupDisplayName
$count = (Get-AzureADGroup -All $true -SearchString "$searchString" | Get-AzureADGroupMember -ALL 1).COUNT
write-host $group.GroupDisplayName , $count
[PSCustomObject]#{
Group = $group.GroupDisplayName
Count = $Count
}
}
$result | Export-Csv -Path $path -Append
I tried to reproduce the scenario in my environment:
Note: To print display name:
Run using $group.DisplayName
Used below code:
$azgroups=Get-AzureADGroup
foreach ($group in $azgroups){
$searchString = $group.GroupDisplayName
$count = (Get-AzureADGroup -All $true -SearchString "$searchString" | Get-AzureADGroupMember -ALL 1).COUNT
write-host $group.DisplayName , $count
$group_properties = [pscustomobject] #{
"DisplayName" = $group.DisplayName
"Count" = $count
}
$group_properties | Export-csv -Path C:\User\xxx\myexcelsheet" -NoTypeInformation -Force -Append
}
The csv or excel file is created successfully:
And we could see the required fiels in the csv file

Having difficult creating excel sheet while looping thru names

I have bunch of server names. Then i am looping thru these names and creating sheet by each server name. But getting error. below is my code
create excel spreadsheet
$xlsx = Join-Path -Path (Get-Location).Path -ChildPath "ClusterUsageReport-$(get-date -UFormat '%Y-%m-%d-%H-%M-%S').xlsx"
$xl = new-object -ComObject Excel.Application
$workbook = $xl.Workbooks.Add()
$i = 1
$clusters = ('Hcohesity01','Hcohesity05')
foreach ($vip in $clusters){
### create excel woorksheet
$worksheet = $workbook.Worksheets.Item($i)
$worksheet.Name = "$vip-Storage Growth"
$worksheet.activate | Out-Null
$i ++
### there are more scripts below this line, which create charts in each sheet ####
}
$xl.visible = $true
$worksheet.columns.autofit() | Out-Null
$worksheet.usedRange.rows(1).Font.Bold = $True
$workbook.SaveAs($xlsx,51) | Out-Null
Message i am getting
Invalid index. (Exception from HRESULT: 0x8002000B (DISP_E_BADINDEX))
At C:\raju\scripts\cluster_usage_in_excel.ps1:25 char:1
$worksheet = $workbook.Worksheets.Item($i)
+ CategoryInfo : OperationStopped: (:) [], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException
Message coming from line $worksheet = $workbook.Worksheets.Item($i) , any idea how do i achieve this ?
Below is entire script .. can you point where needs update ??
usage: ./graphStorageGrowth.ps1 -vip mycluster -username myuser [ -domain mydomain.net ] [ -days 60 ]
### process commandline arguments
[CmdletBinding()]
param (
[Parameter(Mandatory = $True)][string]$username,
[Parameter()][int32]$days = 60
)
### constants
$TB = (1024*1024*1024*1024)
$GB = (1024*1024*1024)
### source the cohesity-api helper code
. ./cohesity-api
### create excel spreadsheet
$xlsx = Join-Path -Path (Get-Location).Path -ChildPath "ClusterUsageReport-$(get-date -UFormat '%Y-%m-%d-%H-%M-%S').xlsx"
$xl = new-object -ComObject Excel.Application
$workbook = $xl.Workbooks.Add()
$i = 0
$clusters = ('Hcohesity01','hcohesity03')
foreach ($vip in $clusters){
### create excel woorksheet
while($xlsx.Worksheets.Count -lt $i) { $xlsx.Worksheets.Add() }
#$worksheet = $workbook.Worksheets.Item($i)
$worksheet.Name = "$vip-Storage Growth"
$worksheet.activate()
### headings for data rows
$row = 1
$worksheet.Cells.Item($row,1) = 'Date'
$worksheet.Cells.Item($row,2) = 'Usage in Tib'
$row++
### authenticate
apiauth -vip $vip -username $username -domain corpads.local
### calculate startTimeMsecs
$startTimeMsecs = $(timeAgo $days days)/1000
### get cluster info
$clusterInfo = api get cluster?fetchStats=true
$clusterId = $clusterInfo.id
### collect $days of write throughput stats
#$stats = api get statistics/timeSeriesStats?schemaName=kBridgeClusterStats`&entityId=$clusterId`&metricName=kSystemUsageBytes`&startTimeMsecs=$startTimeMsecs`&rollupFunction=average`&rollupIntervalSecs=86400
$stats = api get "statistics/timeSeriesStats?endTimeMsecs=1662609600000&entityId=$clusterId&metricName=kMorphedUsageBytes&metricUnitType=0&range=day&rollupFunction=average&rollupIntervalSecs=86400&schemaName=kBridgeClusterStats&startTimeMsecs=$startTimeMsecs"
### populate excel worksheet with the throughput stats
foreach ($stat in $stats.dataPointVec){
$day = usecsToDate (($stat.timestampMsecs)*1000)
$consumed = $stat.data.int64Value/$TB
$worksheet.Cells.Item($row,1) = "$day".split()[0]
$worksheet.Cells.Item($row,2) = "{0:N2}" -f $consumed
$row++
}
### create excel chart
$chartData = $worksheet.Range("A1").CurrentRegion
$chart = $worksheet.Shapes.AddChart().Chart
$chart.chartType = 4
$chart.SetSourceData($chartData)
$chart.HasTitle = $true
$chart.ChartTitle.Text = "Storage Consumption Last $days Days"
$chart.Parent.Top = 50
$chart.Parent.Left = 150
$chart.Parent.Width = 600
$i ++
}
$xl.visible = $true
#[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)
$worksheet.columns.autofit() | Out-Null
$worksheet.usedRange.rows(1).Font.Bold = $True
$workbook.SaveAs($xlsx,51) | Out-Null

Powershell script using Excel running slow

So i have this script that i coded on my laptop that works just fine, the job is to combine two .csv-files into one .xls-file.
And running the script with two .csv-files containing a couple of thousand rows takes a few seconds max.
But when i try to run it on the server where it should be located, it takes... hours. I haven't done a full run, but writing one line in the .xls-file takes maybe 2-3 seconds.
So what im wondering is what is causing the huge increase in runtime. I'm monitoring the CPU-load while the script is running, and it's at 50-60% load.
The server has loads of Ram, and two CPU-core.
How can i speed this up?
The script looks like this:
$path = "C:\test\*"
$path2 = "C:\test"
$date = Get-Date -Format d
$csvs = Get-ChildItem $path -Include *.csv | Sort-Object LastAccessTime -Descending | Select-Object -First 2
$y = $csvs.Count
Write-Host "Detected the following CSV files: ($y)"
foreach ($csv in $csvs) {
Write-Host " "$csv.Name
}
$outputfilename = "regSCI " + $date
Write-Host Creating: $outputfilename
$excelapp = New-Object -ComObject Excel.Application
$excelapp.sheetsInNewWorkbook = $csvs.Count
$xlsx = $excelapp.Workbooks.Add()
$sheet = 1
$xlleft = -4131
foreach ($csv in $csvs) {
$row = 1
$column = 1
$worksheet = $xlsx.Worksheets.Item($sheet)
$worksheet.Name = $csv.Name
$worksheet.Rows.HorizontalAlignment = $xlleft
$file = (Get-Content $csv)
Write-Host Worksheet created: $worksheet.Name
foreach($line in $file) {
Write-Host Writing Line
$linecontents = $line -split ',(?!\s*\w+")'
foreach($cell in $linecontents) {
Write-Host Writing Cell
$cell1 = $cell.Trim('"')
$worksheet.Cells.Item($row, $column) = $cell1
$column++
}
$column = 1
$row++
$WorkSheet.UsedRange.Columns.Autofit() | Out-Null
}
$sheet++
$headerRange = $worksheet.Range("a1", "q1")
$headerRange.AutoFilter() | Out-Null
}
$output = $path2 + "\" + $outputfilename
Write-Host $output
$xlsx.SaveAs($output)
$excelapp.Quit()
To speed up your existing code, add these just after creating Excel object:
$excelapp.ScreenUpdating = $false
$excelapp.DisplayStatusBar = $false
$excelapp.EnableEvents = $false
$excelapp.Visible = $false
And these just before SaveAs:
$excelapp.ScreenUpdating = $true
$excelapp.DisplayStatusBar = $true
$excelapp.EnableEvents = $true
This causes excel not to render the worksheet in realtime and fire events every time you change the contets. Most probably DisplayStatusBar and ScreenUpdating doesn't matter if you make an application invisible, but I included it just in case.
Also, you're running Autofit() after every line. This certainly doesn't help with performance.

Importing large csv file into Excel using PowerShell

I'm writing a script which imports a large csv file in Excel document.
I try to use a faster way to enter the data and pass the array directly to Excel without looping it.
$p = Import-Csv -Path "C:\Report.csv" -Delimiter "`t"
$Excel01 = New-Object -ComObject Excel.Application
$Excel01.Visible = $True
$Workbook01 = $Excel01.Workbooks.Add()
$Worksheet01 = $Workbook01.Sheets.Item(1)
$Worksheet01.Activate()
$Worksheet01.Range("A1:D1").EntireColumn.Value() = $p | select field1,field2...
But when I run this it hungs...How can I do that?
OpenText() already exists in Excel. Note, however, that you MUST change the extension of the text file to something other than .csv, because Excel has its own mind about how files with that particular extension should be handled.
New-Variable -Option Constant -Name xlDelimited -Value 1
New-Variable -Option Constant -Name xlTextQualifierNone -Value -4142
New-Variable -Option Constant -Name xlWorkbookDefault -Value 51
$csv = 'C:\path\to\your.csv'
$txt = $csv -replace '\.csv$','.txt'
$xls = $csv -replace '\.csv$','.xlsx'
Rename-Item $csv $txt
$xl = New-Object -COM 'Excel.Application'
$xl.Workbooks.OpenText($txt, [Type]::Missing, [Type]::Missing, $xlDelimited, $xlTextQualifierNone, $false, $true)
$wb = $xl.Workbooks | ? { $_.FullName -eq $txt }
$wb.SaveAs($xls, $xlWorkbookDefault)
$wb.Close()
$xl.Quit()
The [Type]::Missing values are required for parameters that should retain their default value.
Quick and dirty. Maybe you can optimize it :-)
$p = Import-Csv -Path "C:\Report.csv" -Delimiter "`t"
$Excel01 = New-Object -ComObject Excel.Application
$Excel01.Visible = $True
$Workbook01 = $Excel01.Workbooks.Add()
$Worksheet01 = $Workbook01.Sheets.Item(1)
$Worksheet01.Activate()
#Add csv header to excel
For ($i = 0; $i -lt ($p | Get-Member | Where-Object -FilterScript {$_.MemberType -eq "NoteProperty"}).Count; $i ++) {
$Worksheet01.Cells.Item(1,(1+$i)) = "$(($p | Get-Member | Where-Object -FilterScript {$_.MemberType -eq "NoteProperty"})[$i].Name)"
}
#Add csv data to ecxel
$startRow = 2
For ($i = 0; $i -lt ($p | Measure-Object).Count; $i ++) {
For ($i2 = 0; $i2 -lt ($p[$i] | Get-Member | Where-Object -FilterScript {$_.MemberType -eq "NoteProperty"}).Count; $i2 ++) {
$PropertyName = ($p[$i2] | Get-Member | Where-Object -FilterScript {$_.MemberType -eq "NoteProperty"})[$i2].Name
$Worksheet01.Cells.Item($startRow,(1+$i2)) = "$($p[$i].$PropertyName)"
}
$startRow ++
}

Export specific columns from Excel to .csv Powershell

I have such a code for exporting Excel file with two worksheets into two csv files.The problem is that I am currently exporting whole worksheets and I want to export only these 3 columns from my loop.How can I save them? They must be in order because I want to import it later to AD.
Function ExportWSToCSV ($excelFileName , $csvLoc){
#Sample use in a console: ExportWSToCSV -excelFileName "Test_Peoplesoft.xls" -csvLoc "y:\Application Data\CSVFiles\"
$CultureOld = [System.Threading.Thread]::CurrentThread.CurrentCulture
#Original culture info
$CultureUS = [System.Globalization.CultureInfo]'en-US'
#US culture info
$excelFile = "y:\Application Data\Test_Peoplesoft.xls"
#Loc of Excel file .xls , #csvLov - Loc of output files in format .csv
[System.Threading.Thread]::CurrentThread.CurrentCulture = $CultureUS
$E = New-Object -ComObject Excel.Application
$E.Visible = $false
$E.DisplayAlerts = $false
$wb = $E.Workbooks.Open($excelFile)
$intRow = 2
$intRowMax =($ws.UsedRange.Rows).count
$elements = $email -or $costcode -or $leader
Do{
foreach($ws in $wb.sheets.item("Inactive")){
if($elements -ne $null ){
$email = $ws.Cells.Item($intRow, 4).Value()
$costcode = $ws.Cells.Item($intRow, 15).Value()
$leader = $ws.Cells.Item($intRow, 20).Value()
}else{Write-Host "Null Value in one of the attributes"}
}
<#
foreach($ws in $wb.sheets.item("Inactive")){
$email = $ws.Cells.Item($intRow, 4).Value()
$costcode = $ws.Cells.Item($intRow, 15).Value()
$leader = $ws.Cells.Item($intRow, 20).Value()
}
#>
$user = $email + "_" + $costcode + "_" + $leader
write-host $intRow " " $user
$intRow++
}While ($ws.Cells.Item($intRow,1).Value() -ne $null)
foreach ($ws in $wb.Worksheets)
{
Write-Host "Processing Worksheet: " $ws.Name
$n = $csvLoc + $excelFileName + "_" + $ws.Name
#Name variable - Output file loc + excel file name + worksheet name
$ws.SaveAs($n + ".csv", 6)
#Saving file to .csv
}
$E.Quit()
[System.Threading.Thread]::CurrentThread.CurrentCulture = $CultureOld
}
Something like this should work:
First, setup an array for containing our list of exported users like so:
$exportList = #()
(place before you start looping the rows)
Then loop through the rows on your worksheet with your do while loop and add a user object to add the your export list like so
# Create userObj with the required properties
$userObj = New-Object System.Object
$userObj | Add-Member -Type NoteProperty -Name Email -Value $email
$userObj | Add-Member -Type NoteProperty -Name CostCode -Value $costcode
$userObj | Add-Member -Type NoteProperty -Name Leader -Value $leader
# Add $userObj to our list to be exported
$exportList += $userObj
And ofcourse export it to .csv
$exportList | Export-Csv $pathToCsvFile

Resources